├── LICENSE ├── README.md ├── composer.json └── src ├── Encryption.php └── Helpers └── helpers.php /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Mohammed Alsaloul 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Laravel Number Encryption Package** 2 | 3 | License: MIT 4 | 5 | --- 6 | 7 | **Overview** 8 | 9 | The **Laravel Number Encryption Package** provides robust encryption and decryption functionality for numeric values within Laravel applications. Building upon simple number-to-string mappings, this package offers enhanced security features, configurability, and comprehensive error handling to ensure reliable and secure operations. 10 | 11 | --- 12 | 13 | **Features** 14 | 15 | - **Encrypt Numbers**: Transform numeric values into non-readable, encrypted strings. 16 | - **Decrypt Numbers**: Revert encrypted strings back to their original numeric form. 17 | - **Cryptographically Secure Randomness**: Utilizes `random_int()` for secure random string generation. 18 | - **Configurable Padding Lengths**: Customize the length of prefix and suffix padding added during encryption. 19 | - **Input Validation**: Ensures that only valid numeric inputs are processed. 20 | - **Customizable Mappings**: Modify digit-to-character mappings to suit specific requirements. 21 | - **Enhanced Error Handling**: Provides descriptive exceptions for easier debugging and reliability. 22 | - **Logging Capability**: Integrate with Laravel's logging system to monitor encryption and decryption processes. 23 | - **Utility Methods**: Includes methods to verify if a string is encrypted and to customize encryption settings. 24 | 25 | --- 26 | 27 | **Installation** 28 | 29 | 1. **Install via Composer** 30 | 31 | Run the following command in your terminal to install the package: 32 | 33 | ``` 34 | composer require al-saloul/encryption 35 | ``` 36 | 37 | --- 38 | 39 | **Usage** 40 | 41 | 42 | 1. **Using the Encryption Class** 43 | 44 | **Using Helper Functions** 45 | 46 | For quick and straightforward usage, helper functions are available globally throughout your Laravel project after installing the package. 47 | 48 | ```php 49 | 50 | // Encrypt a number using the helper function 51 | $encrypted = encrypt_numbers(12345); 52 | // Output: "UQ9rovS*(Yr5inVd" 53 | 54 | // Check if the encrypted string is indeed encrypted 55 | $isEncrypted = is_encrypted($encrypted); 56 | // Output: true 57 | 58 | // Decrypt the encrypted string using the helper function 59 | $decrypted = decrypt_numbers($encrypted); 60 | // Output: 12345 61 | 62 | // Output results 63 | echo "Encrypted: " . $encrypted . PHP_EOL; 64 | echo "Is Encrypted: " . ($isEncrypted ? 'Yes' : 'No') . PHP_EOL; 65 | echo "Decrypted: " . $decrypted . PHP_EOL; 66 | ``` 67 | 68 | *Note: Ensure that the helper functions are properly registered and autoloaded in your Laravel application.* 69 | 70 | 71 | **Using Encryption Class** 72 | 73 | Leverage the `Encryption` class to encrypt and decrypt numeric values seamlessly. 74 | 75 | ```php 76 | use Alsaloul\Encryption\Encryption; 77 | use Illuminate\Validation\ValidationException; 78 | 79 | try { 80 | $number = 1234567890; 81 | 82 | // Encrypt the number 83 | $encrypted = Encryption::encryptNumbers($number); 84 | echo "Encrypted: " . $encrypted . PHP_EOL; 85 | 86 | // Decrypt the encrypted string 87 | $decrypted = Encryption::decryptNumbers($encrypted); 88 | echo "Decrypted: " . $decrypted . PHP_EOL; 89 | 90 | // Check if a string is encrypted 91 | $isEncrypted = Encryption::isEncrypted($encrypted); 92 | echo "Is Encrypted: " . ($isEncrypted ? 'Yes' : 'No') . PHP_EOL; 93 | 94 | } catch (ValidationException $e) { 95 | // Handle decryption errors 96 | echo "Decryption failed: " . $e->getMessage() . PHP_EOL; 97 | } catch (\Exception $e) { 98 | // Handle other exceptions 99 | echo "An error occurred: " . $e->getMessage() . PHP_EOL; 100 | } 101 | ``` 102 | 103 | 2. **Configuring Padding Lengths** 104 | 105 | Customize the prefix and suffix padding lengths to enhance security or meet specific requirements. 106 | 107 | ```php 108 | use Alsaloul\Encryption\Encryption; 109 | 110 | // Set custom padding lengths 111 | Encryption::setPaddingLengths(10, 5); 112 | 113 | // Now, encryption will use a prefix of 10 characters and a suffix of 5 characters 114 | $encrypted = Encryption::encryptNumbers(12345); 115 | ``` 116 | 117 | 3. **Customizing Variable Mappings** 118 | 119 | Modify the digit-to-character mappings to define your own encryption patterns. 120 | 121 | ```php 122 | use Alsaloul\Encryption\Encryption; 123 | 124 | // Define custom mappings 125 | $customMappings = [ 126 | "1" => "A1B2C3", 127 | "2" => "D4E5F6", 128 | "3" => "G7H8I9", 129 | "4" => "J0K1L2", 130 | "5" => "M3N4O5", 131 | "6" => "P6Q7R8", 132 | "7" => "S9T0U1", 133 | "8" => "V2W3X4", 134 | "9" => "Y5Z6A7", 135 | "0" => "B8C9D0", 136 | ]; 137 | 138 | // Apply custom mappings 139 | Encryption::setVars($customMappings); 140 | 141 | // Encrypt and decrypt using custom mappings 142 | $encrypted = Encryption::encryptNumbers(67890); 143 | $decrypted = Encryption::decryptNumbers($encrypted); 144 | ``` 145 | 146 | 4. **Integrating Logging** 147 | 148 | To enable logging of encryption and decryption processes, inject a `LoggerInterface` instance into the `Encryption` class. 149 | 150 | ```php 151 | use Alsaloul\Encryption\Encryption; 152 | use Monolog\Logger; 153 | use Monolog\Handler\StreamHandler; 154 | 155 | // Set up logger (using Monolog as an example) 156 | $logger = new Logger('encryption_logger'); 157 | $logger->pushHandler(new StreamHandler(storage_path('logs/encryption.log'), Logger::INFO)); 158 | 159 | // Instantiate the Encryption class with the logger 160 | $encryption = new Encryption($logger); 161 | 162 | try { 163 | $number = 9876543210; 164 | 165 | // Encrypt the number 166 | $encrypted = $encryption->encryptNumbers($number); 167 | echo "Encrypted: " . $encrypted . PHP_EOL; 168 | 169 | // Decrypt the encrypted string 170 | $decrypted = $encryption->decryptNumbers($encrypted); 171 | echo "Decrypted: " . $decrypted . PHP_EOL; 172 | 173 | } catch (\Exception $e) { 174 | // Handle exceptions 175 | echo "An error occurred: " . $e->getMessage() . PHP_EOL; 176 | } 177 | ``` 178 | 179 | *Note: Logging is optional and can be enabled as needed. Ensure that logging sensitive information complies with your application's security policies.* 180 | 181 | --- 182 | 183 | **Methods** 184 | 185 | *Encryption Class Methods* 186 | 187 | - **encryptNumbers(int|string $value): string** 188 | 189 | Encrypts the input numeric value and returns an encrypted string. 190 | 191 | ```php 192 | $encrypted = Encryption::encryptNumbers(12345); 193 | ``` 194 | 195 | - **decryptNumbers(string $value): string** 196 | 197 | Decrypts the encrypted string and returns the original numeric value. 198 | 199 | ```php 200 | $decrypted = Encryption::decryptNumbers($encrypted); 201 | ``` 202 | 203 | - **setPaddingLengths(int $prefixLength, int $suffixLength): void** 204 | 205 | Sets custom lengths for prefix and suffix padding used during encryption. 206 | 207 | ```php 208 | Encryption::setPaddingLengths(10, 5); 209 | ``` 210 | 211 | - **setVars(array $vars): void** 212 | 213 | Customizes the digit-to-character mappings for encryption. 214 | 215 | ```php 216 | Encryption::setVars($customMappings); 217 | ``` 218 | 219 | - **isEncrypted(string $value): bool** 220 | 221 | Checks if a given string follows the encryption format. 222 | 223 | ```php 224 | $isEncrypted = Encryption::isEncrypted($encryptedString); 225 | ``` 226 | 227 | --- 228 | 229 | **Usage Example** 230 | 231 | Here’s a comprehensive example demonstrating various features of the package: 232 | 233 | ```php 234 | use Alsaloul\Encryption\Encryption; 235 | use Illuminate\Validation\ValidationException; 236 | use Monolog\Logger; 237 | use Monolog\Handler\StreamHandler; 238 | 239 | // Set up logger 240 | $logger = new Logger('encryption_logger'); 241 | $logger->pushHandler(new StreamHandler(storage_path('logs/encryption.log'), Logger::INFO)); 242 | 243 | // Instantiate the Encryption class with the logger 244 | $encryption = new Encryption($logger); 245 | 246 | try { 247 | $number = 1234567890; 248 | 249 | // Encrypt the number 250 | $encrypted = $encryption->encryptNumbers($number); 251 | echo "Encrypted: " . $encrypted . PHP_EOL; 252 | 253 | // Decrypt the encrypted string 254 | $decrypted = $encryption->decryptNumbers($encrypted); 255 | echo "Decrypted: " . $decrypted . PHP_EOL; 256 | 257 | // Check if a string is encrypted 258 | $isEncrypted = Encryption::isEncrypted($encrypted); 259 | echo "Is Encrypted: " . ($isEncrypted ? 'Yes' : 'No') . PHP_EOL; 260 | 261 | // Set custom padding lengths 262 | Encryption::setPaddingLengths(10, 5); 263 | 264 | // Encrypt with new padding 265 | $encryptedWithCustomPadding = Encryption::encryptNumbers($number); 266 | echo "Encrypted with Custom Padding: " . $encryptedWithCustomPadding . PHP_EOL; 267 | 268 | // Set custom variable mappings 269 | $customMappings = [ 270 | "1" => "A1B2C3", 271 | "2" => "D4E5F6", 272 | "3" => "G7H8I9", 273 | "4" => "J0K1L2", 274 | "5" => "M3N4O5", 275 | "6" => "P6Q7R8", 276 | "7" => "S9T0U1", 277 | "8" => "V2W3X4", 278 | "9" => "Y5Z6A7", 279 | "0" => "B8C9D0", 280 | ]; 281 | Encryption::setVars($customMappings); 282 | 283 | // Encrypt and decrypt with custom mappings 284 | $customEncrypted = Encryption::encryptNumbers(67890); 285 | echo "Custom Encrypted: " . $customEncrypted . PHP_EOL; 286 | 287 | $customDecrypted = Encryption::decryptNumbers($customEncrypted); 288 | echo "Custom Decrypted: " . $customDecrypted . PHP_EOL; 289 | 290 | } catch (ValidationException $e) { 291 | // Handle decryption errors 292 | echo "Decryption failed: " . $e->getMessage() . PHP_EOL; 293 | } catch (\Exception $e) { 294 | // Handle other exceptions 295 | echo "An error occurred: " . $e->getMessage() . PHP_EOL; 296 | } 297 | ``` 298 | 299 | --- 300 | 301 | **License** 302 | 303 | This package is open-sourced software licensed under the MIT License. 304 | 305 | --- 306 | 307 | **Contributing** 308 | 309 | Contributions are welcome! Please follow these steps: 310 | 311 | 1. Fork the repository. 312 | 2. Create a new branch for your feature or bugfix. 313 | 3. Commit your changes with clear messages. 314 | 4. Push to your fork and submit a pull request. 315 | 316 | --- 317 | 318 | **Security Considerations** 319 | 320 | While this package enhances the security of numeric data through obfuscation, it is **not** intended for encrypting highly sensitive information. For cryptographically secure encryption requirements, consider using established libraries such as OpenSSL or Sodium. 321 | 322 | --- 323 | 324 | **Support** 325 | 326 | If you encounter any issues or have questions, please open an issue on the GitHub repository: https://github.com/al-saloul/encryption/issues 327 | 328 | --- 329 | 330 | **Changelog** 331 | 332 | Please see the CHANGELOG.md for more information on what has changed recently. 333 | 334 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "al-saloul/encryption", 3 | "description": "Simple number encryption and decryption package", 4 | "type": "library", 5 | "license": "MIT", 6 | "autoload": { 7 | "psr-4": { 8 | "Alsaloul\\Encryption\\": "src/" 9 | }, 10 | "files": [ 11 | "src/Helpers/helpers.php" 12 | ] 13 | }, 14 | "authors": [ 15 | { 16 | "name": "Mohammed Alsaloul", 17 | "email": "eng.alsaloul.mohammed@gmail.com" 18 | } 19 | ], 20 | "minimum-stability": "stable", 21 | "require": {}, 22 | "keywords": [ 23 | "encryption", 24 | "decryption", 25 | "number encryption", 26 | "laravel package", 27 | "security" 28 | ] 29 | } -------------------------------------------------------------------------------- /src/Encryption.php: -------------------------------------------------------------------------------- 1 | ~ ! @ # $ % ^ &", 25 | "* ( ) _ + = - Q W E", 26 | "R T Y U I O P A S D", 27 | "F G H J K L Z X C V", 28 | "B N M", 29 | ]; 30 | 31 | // Character mapping for digits 32 | private static $vars = [ 33 | "1" => "1q{k<*RFB", 34 | "2" => "2w}l>(TGN", 35 | "3" => "3e|;~)YHM", 36 | "4" => "4raz!_UJ", 37 | "5" => "5tsx@+IK", 38 | "6" => "6ydc#=OL", 39 | "7" => "7ufv$-PZ", 40 | "8" => "8igb%QAX", 41 | "9" => "9ohn^WSC", 42 | "0" => "0pjm&EDV", 43 | ]; 44 | 45 | /** 46 | * @var LoggerInterface 47 | */ 48 | private $logger; 49 | 50 | /** 51 | * Constructor to inject Logger. 52 | * 53 | * @param LoggerInterface $logger 54 | */ 55 | public function __construct(LoggerInterface $logger) 56 | { 57 | $this->logger = $logger; 58 | } 59 | 60 | /** 61 | * Generate a cryptographically secure random string of a specified length. 62 | * 63 | * @param int $length 64 | * @return string 65 | * @throws \Exception 66 | */ 67 | private static function generateRandomString(int $length = 10): string 68 | { 69 | $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 70 | $charactersLength = strlen($characters); 71 | $randomString = ''; 72 | 73 | // Use random_int for cryptographic security 74 | for ($i = 0; $i < $length; $i++) { 75 | $index = random_int(0, $charactersLength - 1); 76 | $randomString .= $characters[$index]; 77 | } 78 | 79 | return $randomString; 80 | } 81 | 82 | /** 83 | * Encrypt a numeric string. 84 | * 85 | * @param int|string $value 86 | * @return string 87 | * @throws InvalidArgumentException 88 | */ 89 | public static function encryptNumbers($value): string 90 | { 91 | if (!is_numeric($value)) { 92 | throw new InvalidArgumentException('The value to encrypt must be numeric.'); 93 | } 94 | 95 | $string = ''; 96 | foreach (str_split((string) $value) as $digit) { 97 | if (!isset(self::$vars[$digit])) { 98 | throw new InvalidArgumentException("Invalid digit encountered during encryption: {$digit}"); 99 | } 100 | $characters = self::$vars[$digit]; 101 | $charactersLength = strlen($characters); 102 | // Use random_int for cryptographic security 103 | $randomIndex = random_int(0, $charactersLength - 1); 104 | $string .= $characters[$randomIndex]; 105 | } 106 | 107 | $encrypted = self::generateRandomString(self::$prefixLength) . $string . self::generateRandomString(self::$suffixLength); 108 | 109 | // Optionally, log the encryption 110 | // $this->logger->info("Encrypted value: {$encrypted}"); 111 | 112 | return $encrypted; 113 | } 114 | 115 | /** 116 | * Decrypt an encrypted string. 117 | * 118 | * @param string $value 119 | * @return string 120 | * @throws ValidationException 121 | */ 122 | public static function decryptNumbers(string $value): string 123 | { 124 | try { 125 | if (strlen($value) < (self::$prefixLength + self::$suffixLength)) { 126 | throw new InvalidArgumentException('The encrypted value is too short to contain valid data.'); 127 | } 128 | 129 | $value = substr($value, self::$prefixLength, -self::$suffixLength); // Remove random padding 130 | $string = ''; 131 | 132 | foreach (str_split($value) as $char) { 133 | $found = false; 134 | foreach (self::$vars as $digit => $letters) { 135 | if (strpos($letters, $char) !== false) { 136 | $string .= $digit; 137 | $found = true; 138 | break; 139 | } 140 | } 141 | if (!$found) { 142 | throw new InvalidArgumentException("Invalid character encountered during decryption: {$char}"); 143 | } 144 | } 145 | 146 | // Optionally, log the decryption 147 | // $this->logger->info("Decrypted value: {$string}"); 148 | 149 | return $string; 150 | } catch (\Exception $exception) { 151 | throw ValidationException::withMessages(['decrypt' => $exception->getMessage()]); 152 | } 153 | } 154 | 155 | /** 156 | * Set custom padding lengths. 157 | * 158 | * @param int $prefixLength 159 | * @param int $suffixLength 160 | * @return void 161 | * @throws InvalidArgumentException 162 | */ 163 | public static function setPaddingLengths(int $prefixLength, int $suffixLength): void 164 | { 165 | if ($prefixLength < 0 || $suffixLength < 0) { 166 | throw new InvalidArgumentException('Padding lengths must be non-negative integers.'); 167 | } 168 | self::$prefixLength = $prefixLength; 169 | self::$suffixLength = $suffixLength; 170 | } 171 | 172 | /** 173 | * Set custom variable mappings. 174 | * 175 | * @param array $vars 176 | * @return void 177 | * @throws InvalidArgumentException 178 | */ 179 | public static function setVars(array $vars): void 180 | { 181 | foreach ($vars as $digit => $characters) { 182 | if (!is_string($digit) || !is_string($characters)) { 183 | throw new InvalidArgumentException('Variable mappings must be an associative array of strings.'); 184 | } 185 | if (!ctype_digit($digit) || strlen($digit) !== 1) { 186 | throw new InvalidArgumentException("Invalid digit key: {$digit}. Keys must be single digits."); 187 | } 188 | self::$vars[$digit] = $characters; 189 | } 190 | } 191 | 192 | /** 193 | * Check if a string is a valid encrypted number. 194 | * 195 | * @param string $value 196 | * @return bool 197 | */ 198 | public static function isEncrypted(string $value): bool 199 | { 200 | if (strlen($value) < (self::$prefixLength + self::$suffixLength)) { 201 | return false; 202 | } 203 | 204 | $core = substr($value, self::$prefixLength, -self::$suffixLength); 205 | foreach (str_split($core) as $char) { 206 | $found = false; 207 | foreach (self::$vars as $letters) { 208 | if (strpos($letters, $char) !== false) { 209 | $found = true; 210 | break; 211 | } 212 | } 213 | if (!$found) { 214 | return false; 215 | } 216 | } 217 | 218 | return true; 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /src/Helpers/helpers.php: -------------------------------------------------------------------------------- 1 |