Argon2
Password Hashing Library
Argon2
Overview
Argon2 is the latest key derivation function selected as the winner of the 2015 Password Hashing Competition (PHC) and has established itself as the industry standard for password hashing as of 2025. With memory-hard design, it provides high resistance against parallel attacks using GPUs and ASICs, and responds to various security requirements through configurable parameters. It offers three variants: Argon2d, Argon2i, and Argon2id, allowing optimal implementation selection based on use cases. Rich implementations in major programming languages such as Python, Node.js, Java, Go, Rust, and PHP enable adoption in any application environment. Recommended by major security organizations including OWASP, NIST, and ENISA, it has been widely adopted as the foundational technology for password security in modern web applications.
Details
Argon2 is designed as a memory-hard function, making it difficult for attackers to perform parallel cracking attacks using GPUs and ASICs. By adjusting three parameters - memory usage, parallelism, and execution time - optimization according to hardware environment and security requirements is possible. Argon2d is fast and strong against GPU attacks through data-dependent memory access, while Argon2i is resistant to side-channel attacks through data-independent memory access. Argon2id provides balanced security as a hybrid of both. With automatic salt generation, configurable costs, and cross-platform support, it meets enterprise-level security requirements.
Key Features
- Memory-Hard Design: High resistance against GPU/ASIC parallel attacks
- Three Variants: Argon2d, Argon2i, Argon2id for use case optimization
- Configurable Parameters: Adjustable memory, parallelism, and time cost
- Multi-Language Support: Implementations in Python, Node.js, Java, Go, Rust, PHP, etc.
- Industry Standard Certification: Security standard recommended by OWASP, NIST, ENISA
- Cross-Platform: Stable operation on Windows, Linux, macOS, etc.
Advantages and Disadvantages
Advantages
- Provides industry-leading security as PHC winner
- High resistance against modern attack methods through memory-hard design
- Supports diverse environments and security requirements with configurable parameters
- Rich language implementations enable adoption without platform constraints
- Reliability guaranteed through recommendations from major security organizations
- Flexible design capable of adapting to future hardware advances
Disadvantages
- Higher memory usage and CPU load compared to traditional hash functions
- Parameter tuning requires deep understanding of cryptography and hardware performance
- Difficult to use in memory-constrained environments (embedded systems, etc.)
- Requires planned approach for migration from legacy systems
- Potential for performance issues or security degradation with improper parameter settings
- Implementation may be limited on some older platforms
Reference Pages
Usage Examples
Python Implementation (using 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):
# Initialize PasswordHasher with recommended parameters
self.ph = PasswordHasher(
time_cost=3, # 3 iterations (recommended minimum)
memory_cost=65536, # 64 MiB memory usage
parallelism=1, # 1 thread (adjust as needed)
hash_len=32, # 32-byte hash output
salt_len=16 # 16-byte salt
)
def hash_password(self, password: str) -> str:
"""Hash password with Argon2"""
try:
# Hash password (salt auto-generated)
hash_value = self.ph.hash(password)
print(f"Password hash generation successful")
return hash_value
except HashingError as e:
print(f"Hashing error: {e}")
raise
def verify_password(self, hash_value: str, password: str) -> bool:
"""Verify password against hash"""
try:
self.ph.verify(hash_value, password)
print("Password verification successful")
return True
except VerifyMismatchError:
print("Password verification failed")
return False
except Exception as e:
print(f"Verification error: {e}")
raise
def check_needs_rehash(self, hash_value: str) -> bool:
"""Check if hash needs to be recalculated"""
return self.ph.check_needs_rehash(hash_value)
# Usage example
password_manager = SecurePasswordManager()
# During user registration
user_password = "secure_password_123!"
password_hash = password_manager.hash_password(user_password)
print(f"Generated hash: {password_hash}")
# During login
if password_manager.verify_password(password_hash, user_password):
print("Login successful")
else:
print("Login failed")
# Hash upgrade check
if password_manager.check_needs_rehash(password_hash):
print("Hash recalculation recommended")
new_hash = password_manager.hash_password(user_password)
print(f"New hash: {new_hash}")
Node.js Implementation (using argon2 package)
// package.json dependencies
// "argon2": "^0.31.2"
const argon2 = require('argon2');
class NodePasswordManager {
constructor() {
// Argon2id configuration (recommended variant)
this.options = {
type: argon2.argon2id, // Use Argon2id
memoryCost: 2 ** 16, // 64 MiB
timeCost: 3, // 3 iterations
parallelism: 1, // 1 parallel thread
hashLength: 32, // 32-byte output
saltLength: 16, // 16-byte salt
};
}
async hashPassword(password) {
try {
console.log('Starting password hashing...');
const hash = await argon2.hash(password, this.options);
console.log('Hashing completed');
return hash;
} catch (error) {
console.error('Hashing error:', error);
throw error;
}
}
async verifyPassword(hash, password) {
try {
console.log('Starting password verification...');
const isValid = await argon2.verify(hash, password);
console.log(`Verification result: ${isValid ? 'success' : 'failed'}`);
return isValid;
} catch (error) {
console.error('Verification error:', error);
return false;
}
}
async needsRehash(hash) {
try {
return await argon2.needsRehash(hash, this.options);
} catch (error) {
console.error('Rehash check error:', error);
return false;
}
}
// Express.js middleware example
createAuthMiddleware() {
return async (req, res, next) => {
const { password, hash } = req.body;
if (!password || !hash) {
return res.status(400).json({
error: 'Password and hash are required'
});
}
try {
const isValid = await this.verifyPassword(hash, password);
if (isValid) {
// Hash upgrade check
if (await this.needsRehash(hash)) {
const newHash = await this.hashPassword(password);
req.newHash = newHash;
}
next();
} else {
res.status(401).json({ error: 'Authentication failed' });
}
} catch (error) {
res.status(500).json({ error: 'Authentication error' });
}
};
}
}
// Usage example
async function main() {
const passwordManager = new NodePasswordManager();
const password = 'user_secure_password_2025!';
// Password hashing
const hash = await passwordManager.hashPassword(password);
console.log('Generated hash:', hash);
// Password verification
const isValid = await passwordManager.verifyPassword(hash, password);
console.log('Verification result:', isValid);
// Wrong password test
const isInvalid = await passwordManager.verifyPassword(hash, 'wrong_password');
console.log('Wrong password result:', isInvalid);
// Rehash necessity check
const needsRehash = await passwordManager.needsRehash(hash);
console.log('Needs rehash:', needsRehash);
}
main().catch(console.error);
Java Implementation (using argon2-jvm)
// build.gradle or 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 parallel thread
// Dynamically calculate optimal iterations (complete within 1 second)
this.iterations = Argon2Helper.findIterations(
argon2, 1000, memory, parallelism
);
System.out.println("Optimal iterations: " + iterations);
}
public String hashPassword(String password) {
char[] passwordChars = password.toCharArray();
try {
System.out.println("Starting password hashing...");
String hash = argon2.hash(iterations, memory, parallelism, passwordChars);
System.out.println("Hashing completed");
return hash;
} finally {
// Wipe confidential data for security
argon2.wipeArray(passwordChars);
}
}
public boolean verifyPassword(String hash, String password) {
char[] passwordChars = password.toCharArray();
try {
System.out.println("Starting password verification...");
boolean isValid = argon2.verify(hash, passwordChars);
System.out.println("Verification result: " + (isValid ? "success" : "failed"));
return isValid;
} finally {
// Wipe confidential data for security
argon2.wipeArray(passwordChars);
}
}
public void close() {
// Resource cleanup
if (argon2 != null) {
// Cleanup process if needed
}
}
// Spring Security integration example
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());
}
}
// Usage example
public static void main(String[] args) {
JavaPasswordManager manager = new JavaPasswordManager();
try {
String password = "enterprise_password_2025!";
// Password hashing
String hash = manager.hashPassword(password);
System.out.println("Generated hash: " + hash);
// Password verification
boolean isValid = manager.verifyPassword(hash, password);
System.out.println("Verification success: " + isValid);
// Wrong password test
boolean isInvalid = manager.verifyPassword(hash, "wrong_password");
System.out.println("Wrong password: " + isInvalid);
} finally {
manager.close();
}
}
}
Go Implementation (using 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 iterations
Parallelism: 1, // 1 parallel thread
SaltLength: 16, // 16-byte salt
KeyLength: 32, // 32-byte key
},
}
}
func (pm *GoPasswordManager) HashPassword(password string) (string, error) {
fmt.Println("Starting password hashing...")
// Generate random salt
salt := make([]byte, pm.params.SaltLength)
if _, err := rand.Read(salt); err != nil {
return "", fmt.Errorf("salt generation error: %w", err)
}
// Compute hash with Argon2id
hash := argon2.IDKey(
[]byte(password),
salt,
pm.params.Iterations,
pm.params.Memory,
pm.params.Parallelism,
pm.params.KeyLength,
)
// Encoding format: $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("Hashing completed")
return encodedHash, nil
}
func (pm *GoPasswordManager) VerifyPassword(encodedHash, password string) (bool, error) {
fmt.Println("Starting password verification...")
// Parse hash
params, salt, hash, err := pm.decodeHash(encodedHash)
if err != nil {
return false, fmt.Errorf("hash decode error: %w", err)
}
// Recompute hash with input password
computedHash := argon2.IDKey(
[]byte(password),
salt,
params.Iterations,
params.Memory,
params.Parallelism,
params.KeyLength,
)
// Constant-time comparison to prevent timing attacks
isValid := subtle.ConstantTimeCompare(hash, computedHash) == 1
fmt.Printf("Verification result: %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("invalid hash format")
}
if parts[1] != "argon2id" {
return nil, nil, nil, errors.New("unsupported Argon2 variant")
}
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",
¶ms.Memory, ¶ms.Iterations, ¶ms.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 handler example
func (pm *GoPasswordManager) AuthenticationHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Only POST method allowed", 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, "Invalid JSON", http.StatusBadRequest)
return
}
isValid, err := pm.VerifyPassword(authReq.Hash, authReq.Password)
if err != nil {
http.Error(w, "Authentication error", 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)
}
// Usage example
func main() {
manager := NewGoPasswordManager()
password := "golang_secure_2025!"
// Password hashing
hash, err := manager.HashPassword(password)
if err != nil {
fmt.Printf("Hashing error: %v\n", err)
return
}
fmt.Printf("Generated hash: %s\n", hash)
// Password verification
isValid, err := manager.VerifyPassword(hash, password)
if err != nil {
fmt.Printf("Verification error: %v\n", err)
return
}
fmt.Printf("Verification success: %t\n", isValid)
// Wrong password test
isInvalid, err := manager.VerifyPassword(hash, "wrong_password")
if err != nil {
fmt.Printf("Verification error: %v\n", err)
return
}
fmt.Printf("Wrong password: %t\n", isInvalid)
}
Rust Implementation (using argon2 crate)
// 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("Hashing error: {0}")]
HashingError(#[from] argon2::password_hash::Error),
#[error("Salt generation error")]
SaltGenerationError,
#[error("Password verification failed")]
VerificationFailed,
}
pub struct RustPasswordManager {
argon2: Argon2<'static>,
params: Params,
}
impl RustPasswordManager {
pub fn new() -> Result<Self, PasswordError> {
println!("Initializing Rust password manager...");
// Argon2id parameter configuration
let params = Params::new(
65536, // 64 MiB memory cost
3, // 3 iterations
1, // 1 parallel thread
Some(32) // 32-byte hash output
).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!("Starting password hashing...");
let start = Instant::now();
// Generate salt
let mut salt = [0u8; 16];
OsRng.fill_bytes(&mut salt);
// Hash password
let password_hash = self.argon2
.hash_password(password.as_bytes(), &salt)
.map_err(PasswordError::HashingError)?;
let duration = start.elapsed();
println!("Hashing completed (elapsed time: {:?})", duration);
Ok(password_hash.to_string())
}
pub fn verify_password(&self, hash: &str, password: &str) -> Result<bool, PasswordError> {
println!("Starting password verification...");
let start = Instant::now();
// Parse hash
let parsed_hash = PasswordHash::new(hash)
.map_err(PasswordError::HashingError)?;
// Verify password
let result = self.argon2
.verify_password(password.as_bytes(), &parsed_hash);
let duration = start.elapsed();
match result {
Ok(()) => {
println!("Verification successful (elapsed time: {:?})", duration);
Ok(true)
}
Err(_) => {
println!("Verification failed (elapsed time: {:?})", duration);
Ok(false)
}
}
}
pub fn get_params_info(&self) -> String {
format!(
"Argon2id - Memory: {} KiB, Iterations: {}, Parallelism: {}",
self.params.m_cost(),
self.params.t_cost(),
self.params.p_cost()
)
}
}
// Async web framework (Axum) integration example
#[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 {
"Authentication successful".to_string()
} else {
"Authentication failed".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))
}
// Usage example and testing
fn main() -> Result<(), Box<dyn std::error::Error>> {
let password_manager = RustPasswordManager::new()?;
println!("Configuration info: {}", password_manager.get_params_info());
let password = "rust_secure_password_2025!";
// Password hashing
let hash = password_manager.hash_password(password)?;
println!("Generated hash: {}", hash);
// Password verification
let is_valid = password_manager.verify_password(&hash, password)?;
println!("Verification success: {}", is_valid);
// Wrong password test
let is_invalid = password_manager.verify_password(&hash, "wrong_password")?;
println!("Wrong password: {}", is_invalid);
// Performance test
println!("\nStarting performance test...");
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!("Test {}: {:?}", i, duration);
}
let average_time = total_time / iterations;
println!("Average hashing time: {:?}", 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();
// Different hashes generated due to different salts
assert_ne!(hash1, hash2);
// Both verify successfully with the same password
assert!(manager.verify_password(&hash1, password).unwrap());
assert!(manager.verify_password(&hash2, password).unwrap());
}
}
PHP Implementation (PHP 7.2+ Native Support)
<?php
// PHP 7.2+ with native Argon2 support
class PHPPasswordManager {
private $options;
public function __construct() {
// Argon2id recommended configuration
$this->options = [
'memory_cost' => 65536, // 64 MiB
'time_cost' => 3, // 3 iterations
'threads' => 1, // 1 parallel thread
];
echo "PHP password manager initialization completed\n";
echo "Configuration: " . json_encode($this->options) . "\n";
}
public function hashPassword($password) {
echo "Starting password hashing...\n";
$start = microtime(true);
try {
// Use PASSWORD_ARGON2ID (PHP 7.2+)
$hash = password_hash($password, PASSWORD_ARGON2ID, $this->options);
$duration = (microtime(true) - $start) * 1000;
echo "Hashing completed (elapsed time: {$duration}ms)\n";
return $hash;
} catch (Exception $e) {
echo "Hashing error: " . $e->getMessage() . "\n";
throw $e;
}
}
public function verifyPassword($hash, $password) {
echo "Starting password verification...\n";
$start = microtime(true);
try {
$isValid = password_verify($password, $hash);
$duration = (microtime(true) - $start) * 1000;
echo "Verification result: " . ($isValid ? "success" : "failed") . " (elapsed time: {$duration}ms)\n";
return $isValid;
} catch (Exception $e) {
echo "Verification error: " . $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 integration example
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 integration example
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);
}
}
// Usage example
try {
$passwordManager = new PHPPasswordManager();
$password = 'php_secure_password_2025!';
// Password hashing
$hash = $passwordManager->hashPassword($password);
echo "Generated hash: $hash\n";
// Password verification
$isValid = $passwordManager->verifyPassword($hash, $password);
echo "Verification success: " . ($isValid ? 'true' : 'false') . "\n";
// Wrong password test
$isInvalid = $passwordManager->verifyPassword($hash, 'wrong_password');
echo "Wrong password: " . ($isInvalid ? 'true' : 'false') . "\n";
// Hash information display
$info = $passwordManager->getInfo($hash);
echo "Hash information: " . json_encode($info, JSON_PRETTY_PRINT) . "\n";
// Rehash necessity check
$needsRehash = $passwordManager->needsRehash($hash);
echo "Needs rehash: " . ($needsRehash ? 'true' : 'false') . "\n";
// Performance test
echo "\nStarting performance test...\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 "Test $i: {$duration}ms\n";
}
$averageTime = $totalTime / $iterations;
echo "Average hashing time: {$averageTime}ms\n";
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
// Web API example (simple REST API)
function handlePasswordAPI() {
header('Content-Type: application/json');
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['error' => 'Only POST method allowed']);
return;
}
$input = json_decode(file_get_contents('php://input'), true);
if (!isset($input['action'])) {
http_response_code(400);
echo json_encode(['error' => 'action is required']);
return;
}
$passwordManager = new PHPPasswordManager();
try {
switch ($input['action']) {
case 'hash':
if (!isset($input['password'])) {
http_response_code(400);
echo json_encode(['error' => 'password is required']);
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 and hash are required']);
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' => 'invalid action']);
}
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['error' => 'Server error: ' . $e->getMessage()]);
}
}
// Enable when using API
// handlePasswordAPI();
?>