first commit
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
namespace WorkbloomERP\Utils;
|
||||
|
||||
use Exception;
|
||||
use JsonException;
|
||||
|
||||
class CryptoUtil {
|
||||
/**
|
||||
* Criptografa uma string.
|
||||
*
|
||||
* @param string $data
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function encrypt(string $data): string {
|
||||
$algorithm = self::getAlgorithm();
|
||||
$key = self::getKey();
|
||||
|
||||
$ivLength = openssl_cipher_iv_length($algorithm);
|
||||
if ($ivLength === false) {
|
||||
throw new Exception('Unable to determine IV length');
|
||||
}
|
||||
|
||||
$iv = random_bytes($ivLength);
|
||||
$cipherText = openssl_encrypt(
|
||||
$data,
|
||||
$algorithm,
|
||||
$key,
|
||||
OPENSSL_RAW_DATA,
|
||||
$iv,
|
||||
$tag
|
||||
);
|
||||
|
||||
if ($cipherText === false) {
|
||||
throw new Exception('Failed to encrypt data');
|
||||
}
|
||||
|
||||
return self::encodePayload([
|
||||
'iv' => base64_encode($iv),
|
||||
'tag' => base64_encode($tag),
|
||||
'value' => base64_encode($cipherText)
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Descriptografa uma string.
|
||||
*
|
||||
* @param string $payload
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function decrypt(string $payload): string {
|
||||
$algorithm = self::getAlgorithm();
|
||||
$key = self::getKey();
|
||||
|
||||
$decodedPayload = self::decodePayload($payload);
|
||||
|
||||
$plainText = openssl_decrypt(
|
||||
base64_decode($decodedPayload['value']),
|
||||
$algorithm,
|
||||
$key,
|
||||
OPENSSL_RAW_DATA,
|
||||
base64_decode($decodedPayload['iv']),
|
||||
base64_decode($decodedPayload['tag'])
|
||||
);
|
||||
if ($plainText === false) {
|
||||
throw new Exception('Failed to decrypt data');
|
||||
}
|
||||
|
||||
return $plainText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retorna o algoritmo configurado.
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
private static function getAlgorithm(): string {
|
||||
$algorithm = $_ENV['SYSTEM_CRYPTO_ALGO'];
|
||||
if (!in_array($algorithm, openssl_get_cipher_methods(), true)) {
|
||||
throw new Exception('Invalid cipher algorithm');
|
||||
}
|
||||
return $algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retorna a chave de criptografia.
|
||||
*
|
||||
* A chave deve ser uma string hexadecimal de 64 caracteres (32 bytes).
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
private static function getKey(): string {
|
||||
$hexKey = $_ENV['SYSTEM_CRYPTO_KEY'];
|
||||
if (empty($hexKey)) {
|
||||
throw new Exception('Encryption key not configured');
|
||||
}
|
||||
|
||||
$key = hex2bin($hexKey);
|
||||
if ($key === false || strlen($key) !== 32) {
|
||||
throw new Exception(message: 'Invalid encryption key. Expected 32 bytes (64 hex characters).');
|
||||
}
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Codifica o payload para armazenamento.
|
||||
*
|
||||
* @param array $payload
|
||||
* @return string
|
||||
* @throws JsonException
|
||||
*/
|
||||
private static function encodePayload(array $payload): string {
|
||||
return base64_encode(
|
||||
json_encode(
|
||||
$payload,
|
||||
JSON_THROW_ON_ERROR
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodifica o payload criptografado.
|
||||
*
|
||||
* @param string $payload
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
private static function decodePayload(string $payload): array {
|
||||
try {
|
||||
$decoded = json_decode(
|
||||
base64_decode($payload),
|
||||
true,
|
||||
512,
|
||||
JSON_THROW_ON_ERROR
|
||||
);
|
||||
} catch (JsonException $e) {
|
||||
throw new Exception(message: 'Invalid encrypted payload', previous: $e);
|
||||
}
|
||||
|
||||
foreach (['iv', 'tag', 'value'] as $field) {
|
||||
if (!isset($decoded[$field])) {
|
||||
throw new Exception(sprintf('Missing "%s" field in encrypted payload', $field));
|
||||
}
|
||||
}
|
||||
return $decoded;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user