VOOZH about

URL: https://deepwiki.com/hypervel/encryption/4.2-the-encrypter-implementation

⇱ The Encrypter Implementation | hypervel/encryption | DeepWiki


Loading...
Menu

The Encrypter Implementation

This document provides in-depth documentation of the Encrypter class, the core implementation of cryptographic operations in the hypervel/encryption package. It covers supported cipher algorithms, encryption and decryption flows, authentication mechanisms (MAC and AEAD), payload structure, serialization control, and key rotation support.

For information about the contract interfaces that Encrypter implements, see Encryption Contracts and Interfaces. For information about how Encrypter instances are instantiated and configured, see The Encrypter Factory. For key rotation strategies, see Key Rotation and Previous Keys.

Class Structure and Properties

The Encrypter class implements both EncrypterContract and StringEncrypter interfaces, providing a complete encryption solution for PHP applications.

Core Properties

PropertyTypeVisibilityPurpose
$keystringprotectedThe current encryption key used for all encryption operations
$previousKeysarrayprotectedArray of legacy keys used during decryption for key rotation support
$cipherstringprotectedThe cipher algorithm identifier (e.g., 'aes-256-cbc')
$supportedCiphersarrayprotected staticRegistry of supported cipher algorithms and their properties

Sources: src/Encrypter.php15-40

Cipher Support Registry

The $supportedCiphers static property defines four cipher variants with their respective properties:

CipherKey Size (bytes)AEAD ModeAuthentication Method
aes-128-cbc16NoHMAC-SHA256
aes-256-cbc32NoHMAC-SHA256
aes-128-gcm16YesBuilt-in AEAD tag
aes-256-gcm32YesBuilt-in AEAD tag

The aead flag determines whether the cipher uses Authenticated Encryption with Associated Data (GCM modes) or requires separate MAC computation (CBC modes).

Sources: src/Encrypter.php35-40

Constructor and Validation


The constructor performs strict validation to ensure cipher compatibility and correct key length. The supported() method validates that:

  1. The cipher exists in the $supportedCiphers registry
  2. The key length (in bytes) exactly matches the cipher's required size

Key length is measured using mb_strlen($key, '8bit') to ensure accurate byte counting regardless of character encoding.

Sources: src/Encrypter.php47-71

Encryption Process

Encryption Flow Diagram


Encryption Method Details

The encrypt() method implements the following sequence:

  1. IV Generation: Creates a random initialization vector using random_bytes() with length determined by openssl_cipher_iv_length() for the selected cipher src/Encrypter.php88

  2. Data Preparation: If $serialize is true (default), PHP's serialize() function converts the value to a string representation src/Encrypter.php91

  3. Encryption: Calls openssl_encrypt() with:

    • Plaintext (serialized or raw)
    • Cipher algorithm (lowercase)
    • Encryption key
    • Options: 0 (no special options)
    • IV
    • $tag parameter (by reference, populated for GCM modes)
  4. Error Handling: If openssl_encrypt() returns false, throws EncryptException src/Encrypter.php99-101

  5. Encoding: Base64-encodes both IV and tag (empty string for CBC modes) src/Encrypter.php103-104

  6. MAC Computation: For non-AEAD ciphers, computes HMAC-SHA256 over iv || ciphertext using the encryption key src/Encrypter.php106-108

  7. Payload Assembly: Creates JSON object with keys: iv, value, mac, tag src/Encrypter.php110

  8. Final Encoding: Base64-encodes the entire JSON payload for safe storage/transmission src/Encrypter.php116

String Encryption

The encryptString() method is a convenience wrapper that calls encrypt($value, false), bypassing serialization for string-only encryption. This is useful when the caller knows the data is already a string and wants to avoid serialization overhead.

Sources: src/Encrypter.php86-127

Decryption Process

Decryption Flow Diagram


Decryption Method Details

The decrypt() method implements a multi-stage validation and decryption process:

  1. Payload Parsing: The getJsonPayload() method decodes the base64-encoded payload, parses JSON, and validates structure src/Encrypter.php203-215

  2. IV Extraction: Base64-decodes the initialization vector src/Encrypter.php138

  3. Tag Validation: The ensureTagIsValid() method checks:

    • For AEAD ciphers: tag must be exactly 16 bytes
    • For non-AEAD ciphers: tag must be null or empty
    • Throws DecryptException if tag requirements are violated src/Encrypter.php261-270
  4. Key Rotation Support: Iterates through all available keys (current + previous) using getAllKeys() src/Encrypter.php148

  5. MAC Validation (CBC modes only): For each key, validates the MAC before attempting decryption using validMacForKey() src/Encrypter.php149-153

  6. Decryption Attempt: Calls openssl_decrypt() with the current key in the iteration src/Encrypter.php155-163

  7. Success Detection: If decryption returns a non-false value, breaks the loop src/Encrypter.php164-166

  8. Error Handling: After the loop:

  9. Deserialization: If $unserialize is true (default), calls PHP's unserialize() to restore the original data type src/Encrypter.php177

String Decryption

The decryptString() method calls decrypt($payload, false), skipping deserialization to return the raw string.

Sources: src/Encrypter.php134-188

Authentication Mechanisms

The Encrypter class supports two distinct authentication mechanisms depending on the cipher mode:

HMAC-SHA256 for CBC Modes

For non-AEAD ciphers (aes-128-cbc, aes-256-cbc), authentication is provided through HMAC-SHA256:


The hash() method computes the MAC as: hash_hmac('sha256', $iv . $value, $key) where $iv and $value are the base64-encoded representations src/Encrypter.php193-196

During decryption, validMacForKey() uses hash_equals() for timing-safe comparison to prevent timing attacks src/Encrypter.php250-256

AEAD Tags for GCM Modes

For AEAD ciphers (aes-128-gcm, aes-256-gcm), authentication is built into the cipher:

  • The openssl_encrypt() function automatically generates a 16-byte authentication tag
  • The tag is returned via the $tag parameter (passed by reference)
  • During decryption, openssl_decrypt() validates the tag internally
  • No separate MAC computation or validation is required

The shouldValidateMac() method determines which authentication mechanism to use based on the cipher's aead property src/Encrypter.php275-278

Sources: src/Encrypter.php106-108 src/Encrypter.php149-153 src/Encrypter.php193-196 src/Encrypter.php250-256 src/Encrypter.php261-278

Payload Structure

JSON Payload Schema

Every encrypted payload is a base64-encoded JSON object with the following structure:

FieldTypeAlways PresentPurpose
ivstringYesBase64-encoded initialization vector
valuestringYesBase64-encoded ciphertext
macstringYesHMAC-SHA256 for CBC modes, empty string for GCM modes
tagstringOptionalBase64-encoded AEAD tag for GCM modes, empty string for CBC modes

Payload Validation

The validPayload() method enforces strict structural requirements:

  1. Payload must be an array after JSON decoding src/Encrypter.php222-224
  2. iv, value, and mac keys must exist and contain string values src/Encrypter.php226-230
  3. If tag is present, it must be a string src/Encrypter.php232-234
  4. The decoded IV length must match the cipher's required IV length src/Encrypter.php236

Payload Example (Conceptual)


Sources: src/Encrypter.php203-237

Key Management

Current and Previous Keys

The Encrypter class maintains two categories of encryption keys:


Key Usage Patterns

Encryption always uses the current key ($key property). This ensures new encrypted data uses the most recent, secure key src/Encrypter.php86-116

Decryption attempts keys in order:

  1. Current key ($key)
  2. Previous keys in array order ($previousKeys)

The getAllKeys() method returns [$this->key, ...$this->previousKeys] using array spread syntax src/Encrypter.php291-294

Setting Previous Keys

The previousKeys() method sets the legacy key array:

  1. Validates each key using supported() to ensure compatibility with the current cipher src/Encrypter.php310-314
  2. Throws RuntimeException if any key is incompatible
  3. Assigns the validated array to $previousKeys src/Encrypter.php317
  4. Returns $this for method chaining src/Encrypter.php319

This validation prevents runtime decryption failures due to incorrect key lengths.

Sources: src/Encrypter.php283-320

Static Utility Methods

Key Generation

The static generateKey() method creates cryptographically secure random keys:


Implementation:

  • Looks up the required key size from $supportedCiphers for the specified cipher
  • Falls back to 32 bytes if cipher is not found
  • Uses random_bytes() to generate the key

This method is called by the KeyGenerateCommand CLI tool src/Encrypter.php76-79

Cipher Support Check

The static supported() method validates key-cipher compatibility:


Implementation:

  1. Checks if cipher exists in $supportedCiphers (case-insensitive) src/Encrypter.php66-68
  2. Measures key length using mb_strlen($key, '8bit') for accurate byte counting
  3. Compares key length to cipher's required size src/Encrypter.php70

Returns true only if both conditions are satisfied.

Sources: src/Encrypter.php64-79

Implementation Details

Cipher Normalization

All cipher operations use strtolower($this->cipher) to ensure case-insensitive cipher handling src/Encrypter.php92

JSON Encoding Options

The encrypt() method uses JSON_UNESCAPED_SLASHES when encoding the payload to prevent unnecessary escaping of forward slashes, reducing payload size slightly src/Encrypter.php110

Timing-Safe Comparison

MAC validation uses hash_equals() instead of direct string comparison to prevent timing attacks that could reveal information about the MAC src/Encrypter.php252-255

Error Message Security

Exception messages avoid revealing sensitive cryptographic details. For example, the tag validation error message simply states "Could not decrypt the data" rather than explaining the specific tag validation failure src/Encrypter.php264

Sources: src/Encrypter.php86-320