Files
Claudecio Martins a951944997 first commit
2026-06-16 10:04:10 -03:00

150 lines
3.8 KiB
PHP

<?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;
}
}