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 |
|---|---|---|
| Encryption | encrypt() | AES-256-CBC encryption |
decrypt() | AES-256-CBC decryption | |
| Hashing | hashPassword() | Bcrypt password hash |
verifyPassword() | Verify bcrypt hash | |
sha256() / sha512() | SHA hashing | |
hmac() | HMAC signature | |
| Tokens | generateToken() | Random hex token |
uuid() | UUID v4 generation | |
| Encoding | base64Encode() | 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 variables | Store encryption keys in .env file |
| Never log sensitive data | Don't log encryption keys or passwords |
| Use bcrypt for passwords | Never use SHA/MD5 for password hashing |
| Rotate keys periodically | Change encryption keys on schedule |
| Constant-time comparison | Use 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!