Repository navigation
adds secrets. #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| <?php | ||
|
|
||
| namespace Neuron\Data\Encryption; | ||
|
|
||
| /** | ||
| * Interface for encryption/decryption implementations | ||
| * | ||
| * Provides a contract for different encryption methods to implement, | ||
| * allowing the framework to support various encryption algorithms | ||
| * and libraries (OpenSSL, Sodium, etc.) | ||
| * | ||
| * @package Neuron\Data\Encryption | ||
| */ | ||
| interface IEncryptor | ||
| { | ||
| /** | ||
| * Encrypt data using the provided key | ||
| * | ||
| * @param string $data The plaintext data to encrypt | ||
| * @param string $key The encryption key | ||
| * @return string The encrypted data (base64 encoded for safe storage) | ||
| * @throws \Exception If encryption fails | ||
| */ | ||
| public function encrypt( string $data, string $key ): string; | ||
|
|
||
| /** | ||
| * Decrypt data using the provided key | ||
| * | ||
| * @param string $encryptedData The encrypted data (base64 encoded) | ||
| * @param string $key The decryption key | ||
| * @return string The decrypted plaintext data | ||
| * @throws \Exception If decryption fails or data is corrupted | ||
| */ | ||
| public function decrypt( string $encryptedData, string $key ): string; | ||
|
|
||
| /** | ||
| * Generate a random encryption key | ||
| * | ||
| * @return string A cryptographically secure random key | ||
| * @throws \Exception If key generation fails | ||
| */ | ||
| public function generateKey(): string; | ||
|
|
||
| /** | ||
| * Validate that a key meets the requirements for this encryptor | ||
| * | ||
| * @param string $key The key to validate | ||
| * @return bool True if the key is valid | ||
| */ | ||
| public function isValidKey( string $key ): bool; | ||
|
|
||
| /** | ||
| * Get the cipher algorithm name | ||
| * | ||
| * @return string The name of the cipher algorithm used | ||
| */ | ||
| public function getCipher(): string; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,228 @@ | ||
| <?php | ||
|
|
||
| namespace Neuron\Data\Encryption; | ||
|
|
||
| /** | ||
| * OpenSSL-based encryption implementation | ||
| * | ||
| * Provides secure encryption/decryption using OpenSSL with AES-256-CBC cipher. | ||
| * Includes HMAC authentication to ensure data integrity and authenticity. | ||
| * | ||
| * @package Neuron\Data\Encryption | ||
| */ | ||
| class OpenSSLEncryptor implements IEncryptor | ||
| { | ||
| private const CIPHER = 'aes-256-cbc'; | ||
| private const KEY_LENGTH = 32; // 256 bits for AES-256 | ||
|
|
||
| /** | ||
| * Encrypt data using OpenSSL with AES-256-CBC | ||
| * | ||
| * The encrypted payload includes: | ||
| * - Base64 encoded encrypted data | ||
| * - Base64 encoded initialization vector (IV) | ||
| * - HMAC for authentication | ||
| * - Metadata (cipher type) | ||
| * | ||
| * @param string $data The plaintext data to encrypt | ||
| * @param string $key The encryption key | ||
| * @return string JSON-encoded encrypted payload | ||
| * @throws \Exception If encryption fails | ||
| */ | ||
| public function encrypt( string $data, string $key ): string | ||
| { | ||
| if( !$this->isValidKey( $key ) ) | ||
| { | ||
| throw new \Exception( 'Invalid encryption key. Key must be 32 bytes (256 bits) for AES-256.' ); | ||
| } | ||
|
|
||
| // Convert hex key to binary if needed for consistent key format | ||
| if( preg_match( '/^[a-f0-9]{64}$/i', $key ) ) | ||
| { | ||
| $key = hex2bin( $key ); | ||
| } | ||
|
|
||
| // Generate a random initialization vector | ||
| $ivLength = openssl_cipher_iv_length( self::CIPHER ); | ||
| $iv = openssl_random_pseudo_bytes( $ivLength ); | ||
|
|
||
| // Encrypt the data | ||
| $encrypted = openssl_encrypt( | ||
| $data, | ||
| self::CIPHER, | ||
| $key, | ||
| OPENSSL_RAW_DATA, | ||
| $iv | ||
| ); | ||
|
ljonesfl marked this conversation as resolved.
|
||
|
|
||
| if( $encrypted === false ) | ||
| { | ||
| throw new \Exception( 'Encryption failed: ' . openssl_error_string() ); | ||
| } | ||
|
|
||
| // Create the payload | ||
| $payload = [ | ||
| 'cipher' => self::CIPHER, | ||
| 'encrypted' => base64_encode( $encrypted ), | ||
| 'iv' => base64_encode( $iv ), | ||
| ]; | ||
|
|
||
| // Generate HMAC for authentication | ||
| $payload['mac'] = $this->generateMac( $payload, $key ); | ||
|
|
||
| // Return as JSON for easy storage | ||
| return json_encode( $payload ); | ||
| } | ||
|
|
||
| /** | ||
| * Decrypt data encrypted with encrypt() | ||
| * | ||
| * @param string $encryptedData JSON-encoded encrypted payload | ||
| * @param string $key The decryption key | ||
| * @return string The decrypted plaintext data | ||
| * @throws \Exception If decryption fails or authentication fails | ||
| */ | ||
| public function decrypt( string $encryptedData, string $key ): string | ||
| { | ||
| if( !$this->isValidKey( $key ) ) | ||
| { | ||
| throw new \Exception( 'Invalid decryption key. Key must be 32 bytes (256 bits) for AES-256.' ); | ||
| } | ||
|
|
||
| // Parse the payload | ||
| $payload = json_decode( $encryptedData, true ); | ||
|
|
||
| if( json_last_error() !== JSON_ERROR_NONE ) | ||
| { | ||
| throw new \Exception( 'Invalid encrypted data format. Expected JSON payload.' ); | ||
| } | ||
|
|
||
| // Verify required fields | ||
| if( !isset( $payload['cipher'], $payload['encrypted'], $payload['iv'], $payload['mac'] ) ) | ||
| { | ||
| throw new \Exception( 'Incomplete encrypted payload. Missing required fields.' ); | ||
| } | ||
|
|
||
| // Verify cipher type | ||
| if( $payload['cipher'] !== self::CIPHER ) | ||
| { | ||
| throw new \Exception( "Cipher mismatch. Expected " . self::CIPHER . ", got {$payload['cipher']}" ); | ||
| } | ||
|
|
||
| // Verify MAC for authentication | ||
| if( !$this->verifyMac( $payload, $key ) ) | ||
| { | ||
| throw new \Exception( 'MAC verification failed. Data may have been tampered with.' ); | ||
| } | ||
|
|
||
| // Convert hex key to binary if needed for consistent key format | ||
| if( preg_match( '/^[a-f0-9]{64}$/i', $key ) ) | ||
| { | ||
| $key = hex2bin( $key ); | ||
| } | ||
|
|
||
| // Decrypt the data | ||
| $decrypted = openssl_decrypt( | ||
| base64_decode( $payload['encrypted'] ), | ||
| self::CIPHER, | ||
| $key, | ||
| OPENSSL_RAW_DATA, | ||
| base64_decode( $payload['iv'] ) | ||
| ); | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| if( $decrypted === false ) | ||
| { | ||
| throw new \Exception( 'Decryption failed: ' . openssl_error_string() ); | ||
| } | ||
|
|
||
| return $decrypted; | ||
| } | ||
|
|
||
| /** | ||
| * Generate a cryptographically secure random key | ||
| * | ||
| * @return string A 32-byte (256-bit) key encoded as hex | ||
| * @throws \Exception If key generation fails | ||
| */ | ||
| public function generateKey(): string | ||
| { | ||
| $key = openssl_random_pseudo_bytes( self::KEY_LENGTH, $strong ); | ||
|
|
||
| if( !$strong ) | ||
| { | ||
| throw new \Exception( 'Failed to generate cryptographically strong key' ); | ||
| } | ||
|
|
||
| // Return as hex for easy storage in text files | ||
| return bin2hex( $key ); | ||
| } | ||
|
|
||
| /** | ||
| * Validate that a key meets the requirements | ||
| * | ||
| * @param string $key The key to validate (hex encoded or raw binary) | ||
| * @return bool True if the key is valid | ||
| */ | ||
| public function isValidKey( string $key ): bool | ||
| { | ||
| // Check if it's hex encoded (64 hex chars = 32 bytes) | ||
| if( preg_match( '/^[a-f0-9]{64}$/i', $key ) ) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| // Check if it's raw binary (32 bytes) | ||
| if( strlen( $key ) === self::KEY_LENGTH ) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| /** | ||
| * Get the cipher algorithm name | ||
| * | ||
| * @return string | ||
| */ | ||
| public function getCipher(): string | ||
| { | ||
| return self::CIPHER; | ||
| } | ||
|
|
||
| /** | ||
| * Generate HMAC for payload authentication | ||
| * | ||
| * @param array $payload The payload to authenticate | ||
| * @param string $key The key for HMAC | ||
| * @return string The HMAC hash | ||
| */ | ||
| private function generateMac( array $payload, string $key ): string | ||
| { | ||
| // Prepare data for MAC (exclude the mac field itself) | ||
| $macData = $payload['cipher'] . '.' . $payload['encrypted'] . '.' . $payload['iv']; | ||
|
|
||
| // Convert hex key to binary if needed | ||
| if( preg_match( '/^[a-f0-9]{64}$/i', $key ) ) | ||
| { | ||
| $key = hex2bin( $key ); | ||
| } | ||
|
|
||
| return hash_hmac( 'sha256', $macData, $key ); | ||
| } | ||
|
|
||
| /** | ||
| * Verify HMAC for payload authentication | ||
| * | ||
| * @param array $payload The payload to verify | ||
| * @param string $key The key for HMAC | ||
| * @return bool True if MAC is valid | ||
| */ | ||
| private function verifyMac( array $payload, string $key ): bool | ||
| { | ||
| $expectedMac = $this->generateMac( $payload, $key ); | ||
|
|
||
| // Use hash_equals to prevent timing attacks | ||
| return hash_equals( $expectedMac, $payload['mac'] ); | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.