150 lines
3.8 KiB
PHP
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;
|
|
}
|
|
} |