Encryption

Introduction

The Encryption class in JiFramework provides a set of methods for securely handling encryption and decryption of data, as well as password hashing and verification. It leverages industry-standard algorithms like AES-256-CBC for symmetric encryption and PBKDF2 for key derivation, ensuring that your application's sensitive data is protected against unauthorized access.

Key Features:

  • Two Methods of Encryption:
    1. Key-Based Encryption: Encrypt data using a 32-byte encryption key directly. This method is suitable when you can securely store and manage the encryption keys.
    2. Password-Based Encryption: Encrypt data using a password of any length. The class internally derives a 32-byte key from the password using a secure key derivation function (PBKDF2). This method is convenient when you prefer to use passwords or passphrases instead of managing encryption keys.

By using the Encryption class, developers can:

  • Generate strong encryption keys and initialization vectors.
  • Encrypt and decrypt data securely using symmetric encryption with keys or passwords.
  • Derive encryption keys from passwords using a secure key derivation function.
  • Hash and verify passwords using built-in PHP functions.

Important: Proper use of cryptographic functions is critical for application security. Always follow best practices and understand the implications of each method.

Usage:

// Option 1: Initialize the Encryption through the App
use JIFramework\Core\App\App;
$app = new App();
$encryption= $app->encryption;

OR 

// Option 2: Directly instantiate the Encryption
use JIFramework\Core\Security\Encryption;
$encryption = new Encryption();

Explanation:

  • Option 1: Initializes the App class and retrieves the encryption instance through it, using the framework's main entry point.
  • Option 2: Directly creates a encryption instance.

generateKey()

Method: generateKey(int $length = 32): string

Description: Generates a random encryption key of specified length.

Parameters:

  • $length (int, optional): The length of the key in bytes. Default is 32 bytes for AES-256.

Returns: A hexadecimal string representing the generated key.

Usage:

$key = $encryption->generateKey(); // Generates a 32-byte key
echo 'Encryption Key: ' . $key;

// Example output:
// Encryption Key: 4d6f6e636861727461746162616361626164616262616461626361626164616461

Explanation:

  • Uses random_bytes() to generate cryptographically secure random bytes.
  • Converts the binary key to a hexadecimal string using bin2hex().
  • The key can be stored securely and used for encryption and decryption.

encrypt()

Method: encrypt(string $plaintext, string $key, string $iv = null): string

Description: Encrypts plaintext data using AES-256-CBC encryption with a 32-byte key.

Parameters:

  • $plaintext (string): The data to encrypt.
  • $key (string): The encryption key in hexadecimal format.
  • $iv (string, optional): The initialization vector (IV) in hexadecimal format. If not provided, a random IV is generated.

Returns: A base64-encoded string containing the encrypted data along with the IV.

Usage:

$plaintext = 'Sensitive data to encrypt';
$key = $encryption->generateKey();

// Encrypt the data
$encryptedData = $encryption->encrypt($plaintext, $key);

echo 'Encrypted Data: ' . $encryptedData;

// Example output:
// Encrypted Data: U2FsdGVkX1+Kkq7jOjE8RVQ6pFradV1F7LrQWZfpK0c=

Explanation:

  • Converts the key from hexadecimal to binary using hex2bin().
  • If no IV is provided, generates a random IV of appropriate length.
  • Encrypts the plaintext using openssl_encrypt() with AES-256-CBC.
  • Concatenates the IV and ciphertext, separates them with ::, and encodes the result using base64.
  • The resulting string contains both the IV and the ciphertext, necessary for decryption.

decrypt()

Method: decrypt(string $ciphertext, string $key): string|false

Description: Decrypts data previously encrypted with the encrypt() method using a 32-byte key.

Parameters:

  • $ciphertext (string): The base64-encoded encrypted data containing the IV and ciphertext.
  • $key (string): The encryption key in hexadecimal format.

Returns: The decrypted plaintext as a string, or false on failure.

Usage:

// Assume $encryptedData and $key are obtained from the encryption step

$decryptedData = $encryption->decrypt($encryptedData, $key);

if ($decryptedData !== false) {
    echo 'Decrypted Data: ' . $decryptedData;
} else {
    echo 'Decryption failed.';
}

// Example output:
// Decrypted Data: Sensitive data to encrypt

Explanation:

  • Decodes the base64-encoded data to retrieve the concatenated IV and ciphertext.
  • Splits the data using explode('::', $data, 2) to separate the IV and ciphertext.
  • Converts the key from hexadecimal to binary.
  • Decrypts the ciphertext using openssl_decrypt() with AES-256-CBC.
  • Returns the plaintext if successful, or false if decryption fails.

generateKeyFromPassword()

Method: generateKeyFromPassword(string $password, string $salt = null, int $iterations = 100000): array

Description: Derives a secure 32-byte encryption key from a password of any length using PBKDF2 with SHA-256.

Parameters:

  • $password (string): The password to derive the key from.
  • $salt (string, optional): A hexadecimal string representing the salt. If not provided, a random salt is generated.
  • $iterations (int, optional): The number of iterations for the key derivation function. Default is 100,000.

Returns: An associative array containing:

  • 'key' (string): The derived 32-byte key in hexadecimal format.
  • 'salt' (string): The salt used in hexadecimal format.

Usage:

$password = 'my_secure_password';
$keyData = $encryption->generateKeyFromPassword($password);

echo 'Derived Key: ' . $keyData['key'] . PHP_EOL;
echo 'Salt: ' . $keyData['salt'];

// Example output:
// Derived Key: a1b2c3d4e5f67890123456789abcdef0a1b2c3d4e5f67890123456789abcdef0
// Salt: 1234567890abcdef1234567890abcdef

Explanation:

  • If no salt is provided, generates a random 16-byte salt.
  • Uses hash_pbkdf2() with sha256 to derive a 32-byte key from the password and salt.
  • Returns the key and salt in hexadecimal format for storage or further use.
  • The salt should be stored alongside the key or encrypted data for future derivations.

encryptWithPassword()

Method: encryptWithPassword(string $plaintext, string $password, int $iterations = 100000): string

Description: Encrypts data using a password of any length. Internally, it derives a 32-byte encryption key from the password using PBKDF2 and then encrypts the data using AES-256-CBC.

Parameters:

  • $plaintext (string): The data to encrypt.
  • $password (string): The password to derive the encryption key.
  • $iterations (int, optional): The number of iterations for the key derivation function. Default is 100,000.

Returns: A base64-encoded string containing the salt, IV, and ciphertext.

Usage:

$plaintext = 'Sensitive data to encrypt';
$password = 'my_secret_password';

$encryptedData = $encryption->encryptWithPassword($plaintext, $password);

echo 'Encrypted Data: ' . $encryptedData;

// Example output:
// Encrypted Data: U2FsdGVkX19i32jS2fE0x6Jx5aI6PbLqL4zJX1V7k1o=

Explanation:

  • Password-Based Encryption: Allows encryption using a password of any length without needing to manage encryption keys directly.
  • Generates a random salt and IV.
  • Derives a 32-byte key from the password and salt using PBKDF2 with SHA-256.
  • Encrypts the plaintext using openssl_encrypt() with AES-256-CBC.
  • Concatenates the salt, IV, and ciphertext in binary form.
  • Encodes the result using base64 for storage or transmission.
  • The recipient will need the same password to decrypt the data.

decryptWithPassword()

Method: decryptWithPassword(string $encodedData, string $password, int $iterations = 100000): string|false

Description: Decrypts data encrypted with the encryptWithPassword() method using the password provided. Internally, it derives the same 32-byte key from the password and salt.

Parameters:

  • $encodedData (string): The base64-encoded encrypted data containing the salt, IV, and ciphertext.
  • $password (string): The password used to derive the decryption key.
  • $iterations (int, optional): The number of iterations for the key derivation function. Must match the value used during encryption. Default is 100,000.

Returns: The decrypted plaintext as a string, or false on failure.

Usage:

// Assume $encryptedData is obtained from the encryption step

$decryptedData = $encryption->decryptWithPassword($encryptedData, $password);

if ($decryptedData !== false) {
    echo 'Decrypted Data: ' . $decryptedData;
} else {
    echo 'Decryption failed.';
}

// Example output:
// Decrypted Data: Sensitive data to encrypt

Explanation:

  • Decodes the base64-encoded data to retrieve the concatenated salt, IV, and ciphertext.
  • Extracts the salt (16 bytes), IV, and ciphertext from the binary data.
  • Derives the same 32-byte key from the password and extracted salt using PBKDF2 with SHA-256.
  • Decrypts the ciphertext using openssl_decrypt() with AES-256-CBC.
  • Returns the plaintext if successful, or false if decryption fails.

hashPassword()

Method: hashPassword(string $password): string

Description: Securely hashes a password using PHP's password_hash() function.

Parameters:

  • $password (string): The plaintext password to hash.

Returns: The hashed password as a string.

Usage:

$password = 'user_password';
$hashedPassword = $encryption->hashPassword($password);

echo 'Hashed Password: ' . $hashedPassword;

// Example output:
// Hashed Password: $2y$10$e0NRoF8Zp5e9sJYx/ox7ku3Z1oOFiHlGkE4Pl2Sm1X4U9tGmFg6u6

Explanation:

  • Uses password_hash() with the default algorithm (usually bcrypt).
  • The resulting hash includes the algorithm, cost factor, and salt.
  • The hash can be stored in the database for user authentication.

verifyPassword()

Method: verifyPassword(string $password, string $hash): bool

Description: Verifies a plaintext password against a hashed password.

Parameters:

  • $password (string): The plaintext password to verify.
  • $hash (string): The hashed password to compare against.

Returns: true if the password matches the hash, false otherwise.

Usage:

// Assume $hashedPassword is retrieved from the database

$isValid = $encryption->verifyPassword($password, $hashedPassword);

if ($isValid) {
    echo 'Password is valid.';
} else {
    echo 'Invalid password.';
}

// Example output:
// Password is valid.

Explanation:

  • Uses password_verify() to compare the plaintext password with the stored hash.
  • Returns true if the password is correct, false otherwise.
  • Essential for authenticating users during login.

Full Example

Below is a complete example demonstrating how to use the Encryption class in an application.

$encryption->generateKey();
echo 'Generated Key: ' . $key . PHP_EOL;

// Encrypt data using the key
$plaintext = 'Secret message to encrypt';
$encryptedData = $encryption->encrypt($plaintext, $key);
echo 'Encrypted Data: ' . $encryptedData . PHP_EOL;

// Decrypt data using the same key
$decryptedData = $encryption->decrypt($encryptedData, $key);

if ($decryptedData !== false) {
    echo 'Decrypted Data: ' . $decryptedData . PHP_EOL;
} else {
    echo 'Decryption failed.' . PHP_EOL;
}

// 2. Password-Based Encryption and Decryption
echo "\n=== Password-Based Encryption ===\n";

// Encrypt data with a password
$password = 'UserPassword123!';
$encryptedWithPassword = $encryption->encryptWithPassword($plaintext, $password);
echo 'Encrypted with Password: ' . $encryptedWithPassword . PHP_EOL;

// Decrypt data with the same password
$decryptedWithPassword = $encryption->decryptWithPassword($encryptedWithPassword, $password);

if ($decryptedWithPassword !== false) {
    echo 'Decrypted with Password: ' . $decryptedWithPassword . PHP_EOL;
} else {
    echo 'Decryption with password failed.' . PHP_EOL;
}

// 3. Password Hashing and Verification
echo "\n=== Password Hashing ===\n";

// Hash a password
$hashedPassword = $encryption->hashPassword($password);
echo 'Hashed Password: ' . $hashedPassword . PHP_EOL;

// Verify the password
$isPasswordValid = $encryption->verifyPassword($password, $hashedPassword);

if ($isPasswordValid) {
    echo 'Password is valid.' . PHP_EOL;
} else {
    echo 'Invalid password.' . PHP_EOL;
}

Sample Output:

=== Key-Based Encryption ===
Generated Key: e7c8f1a5d6b9c3e2f4a1b2c3d4e5f6789abcdef0123456789abcdef01234567
Encrypted Data: [base64-encoded string]
Decrypted Data: Secret message to encrypt

=== Password-Based Encryption ===
Encrypted with Password: [base64-encoded string]
Decrypted with Password: Secret message to encrypt

=== Password Hashing ===
Hashed Password: $2y$10$...
Password is valid.