/ Crypto

Crypto

Miko's Crypto library provides encryption, hashing, and token generation utilities. Secure your data with industry-standard algorithms.


Crypto Methods Summary

Category Method Description
Encryptionencrypt()AES-256-CBC encryption
decrypt()AES-256-CBC decryption
HashinghashPassword()Bcrypt password hash
verifyPassword()Verify bcrypt hash
sha256() / sha512()SHA hashing
hmac()HMAC signature
TokensgenerateToken()Random hex token
uuid()UUID v4 generation
Encodingbase64Encode()Base64 encoding
base64UrlEncode()URL-safe Base64

Encryption (AES-256-CBC)

Encrypt and decrypt sensitive data using AES-256-CBC algorithm.

Encrypt Data

use Miko\Library\Crypto;

// Encrypt string
$plaintext = 'Sensitive data here';
$key = 'your-secret-key-min-32-chars-long';

$encrypted = Crypto::encrypt($plaintext, $key);
// Returns: base64 encoded string with IV prepended

Decrypt Data

// Decrypt string
$decrypted = Crypto::decrypt($encrypted, $key);

echo $decrypted; // "Sensitive data here"

Encrypt Arrays/Objects

// Encrypt array (automatically JSON encoded)
$data = [
    'user_id' => 123,
    'permissions' => ['read', 'write'],
    'expires' => time() + 3600
];

$encrypted = Crypto::encrypt(json_encode($data), $key);

// Decrypt and decode
$decrypted = json_decode(Crypto::decrypt($encrypted, $key), true);

Password Hashing

Use bcrypt for secure password storage.

Hash Password

// Hash password with bcrypt
$password = 'user-password-123';
$hash = Crypto::hashPassword($password);

// Store $hash in database (60 characters)
// Example: $2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi

Verify Password

// Verify password against hash
$inputPassword = 'user-password-123';
$storedHash = '$2y$10$92IXUNpkjO0rOQ5byMi...';

if (Crypto::verifyPassword($inputPassword, $storedHash)) {
    echo "Password is correct";
} else {
    echo "Invalid password";
}

Custom Cost Factor

// Higher cost = more secure but slower
$hash = Crypto::hashPassword($password, 12); // Default is 10

Hashing Algorithms

SHA-256

// SHA-256 hash
$hash = Crypto::sha256('data to hash');
// Returns: 64 character hex string

SHA-512

// SHA-512 hash
$hash = Crypto::sha512('data to hash');
// Returns: 128 character hex string

MD5 (Not recommended for security)

// MD5 hash (use only for checksums, not security)
$hash = Crypto::md5('data');
// Returns: 32 character hex string

HMAC Signatures

Create and verify message authentication codes.

Create HMAC

// HMAC-SHA256
$message = 'Important message';
$secretKey = 'shared-secret-key';

$signature = Crypto::hmac($message, $secretKey, 'sha256');

Verify HMAC

// Verify signature
$expectedSignature = Crypto::hmac($message, $secretKey, 'sha256');

if (hash_equals($expectedSignature, $receivedSignature)) {
    echo "Signature is valid";
} else {
    echo "Invalid signature - message may be tampered";
}

Webhook Signature Verification

// Verify incoming webhook
$payload = file_get_contents('php://input');
$receivedSignature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';

$expectedSignature = Crypto::hmac($payload, $_ENV['WEBHOOK_SECRET'], 'sha256');

if (!hash_equals($expectedSignature, $receivedSignature)) {
    http_response_code(401);
    exit('Invalid signature');
}

// Process webhook...

Token Generation

Random Token

// Generate random hex token
$token = Crypto::generateToken(32);
// Returns: 64 character hex string (32 bytes)

// For API keys
$apiKey = Crypto::generateToken(24);
// Returns: 48 character hex string

// For session tokens
$sessionToken = Crypto::generateToken(16);
// Returns: 32 character hex string

Random Bytes

// Get raw random bytes
$bytes = Crypto::randomBytes(16);
// Returns: 16 random bytes (binary)

UUID v4

// Generate UUID v4
$uuid = Crypto::uuid();
// Returns: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx

// Example: 550e8400-e29b-41d4-a716-446655440000

Base64 Encoding

Standard Base64

// Encode
$encoded = Crypto::base64Encode('Hello World');
// Returns: SGVsbG8gV29ybGQ=

// Decode
$decoded = Crypto::base64Decode($encoded);
// Returns: Hello World

URL-Safe Base64

// URL-safe encoding (no +, /, =)
$encoded = Crypto::base64UrlEncode('Hello World');
// Returns: SGVsbG8gV29ybGQ

// Decode
$decoded = Crypto::base64UrlDecode($encoded);
// Returns: Hello World

Practical Examples

Secure Token Storage

class TokenService
{
    private string $encryptionKey;
    
    public function __construct()
    {
        $this->encryptionKey = $_ENV['ENCRYPTION_KEY'];
    }
    
    public function createToken(int $userId, array $permissions): string
    {
        $payload = [
            'user_id' => $userId,
            'permissions' => $permissions,
            'created_at' => time(),
            'expires_at' => time() + 3600
        ];
        
        return Crypto::encrypt(json_encode($payload), $this->encryptionKey);
    }
    
    public function validateToken(string $token): ?array
    {
        try {
            $payload = json_decode(
                Crypto::decrypt($token, $this->encryptionKey),
                true
            );
            
            if ($payload['expires_at'] < time()) {
                return null; // Token expired
            }
            
            return $payload;
        } catch (Exception $e) {
            return null; // Invalid token
        }
    }
}

Password Reset Flow

class PasswordResetService
{
    public function createResetToken(User $user): string
    {
        // Generate secure token
        $token = Crypto::generateToken(32);
        
        // Store hashed token in database
        PasswordReset::create([
            'UserId' => $user->Id,
            'Token' => Crypto::sha256($token),
            'ExpiresAt' => date('Y-m-d H:i:s', time() + 3600)
        ]);
        
        return $token; // Send this to user via email
    }
    
    public function validateResetToken(string $token): ?PasswordReset
    {
        $hashedToken = Crypto::sha256($token);
        
        $reset = PasswordReset::where('Token', $hashedToken)
            ->where('ExpiresAt', '>', date('Y-m-d H:i:s'))
            ->where('UsedAt', null)
            ->first();
        
        return $reset;
    }
    
    public function resetPassword(string $token, string $newPassword): bool
    {
        $reset = $this->validateResetToken($token);
        
        if (!$reset) {
            return false;
        }
        
        $user = User::find($reset->UserId);
        $user->Password = Crypto::hashPassword($newPassword);
        $user->save();
        
        $reset->UsedAt = date('Y-m-d H:i:s');
        $reset->save();
        
        return true;
    }
}

API Key Management

class ApiKeyService
{
    public function generateApiKey(int $userId): array
    {
        // Generate key parts
        $keyId = Crypto::generateToken(8);      // Public identifier
        $keySecret = Crypto::generateToken(32); // Secret part
        
        // Store hashed secret
        ApiKey::create([
            'UserId' => $userId,
            'KeyId' => $keyId,
            'KeyHash' => Crypto::sha256($keySecret),
            'CreatedAt' => date('Y-m-d H:i:s')
        ]);
        
        // Return full key (only shown once)
        return [
            'key' => $keyId . '.' . $keySecret,
            'key_id' => $keyId
        ];
    }
    
    public function validateApiKey(string $fullKey): ?ApiKey
    {
        $parts = explode('.', $fullKey);
        
        if (count($parts) !== 2) {
            return null;
        }
        
        [$keyId, $keySecret] = $parts;
        
        $apiKey = ApiKey::where('KeyId', $keyId)
            ->where('IsActive', true)
            ->first();
        
        if (!$apiKey) {
            return null;
        }
        
        // Verify secret
        if (!hash_equals($apiKey->KeyHash, Crypto::sha256($keySecret))) {
            return null;
        }
        
        return $apiKey;
    }
}

Security Best Practices

Practice Description
Use environment variablesStore encryption keys in .env file
Never log sensitive dataDon't log encryption keys or passwords
Use bcrypt for passwordsNever use SHA/MD5 for password hashing
Rotate keys periodicallyChange encryption keys on schedule
Constant-time comparisonUse hash_equals() for signatures
// Store keys in environment
$encryptionKey = $_ENV['APP_ENCRYPTION_KEY'];
$hmacKey = $_ENV['APP_HMAC_KEY'];

// Never do this:
// $key = 'hardcoded-key-in-source-code';  // BAD!
// error_log("Key: " . $key);               // BAD!