You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

78 lines
2.3 KiB

4 months ago
<?php
namespace App\Support;
use RuntimeException;
class ChannelEntryEncryption
{
public const ALGORITHM = 'RSA-OAEP-2048';
/**
* @return array{public_key: string, private_key: string}
*/
public static function generateKeyPair(): array
{
$key = openssl_pkey_new([
'private_key_bits' => 2048,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
]);
if ($key === false || ! openssl_pkey_export($key, $privateKey)) {
throw new RuntimeException('Unable to generate channel encryption private key.');
}
$details = openssl_pkey_get_details($key);
$publicKey = is_array($details) ? ($details['key'] ?? null) : null;
if (! is_string($publicKey) || trim($publicKey) === '') {
throw new RuntimeException('Unable to generate channel encryption public key.');
}
return [
'public_key' => trim($publicKey),
'private_key' => trim($privateKey),
];
}
public static function encrypt(string $plaintext, string $publicKey): string
{
if (! openssl_public_encrypt($plaintext, $ciphertext, $publicKey, OPENSSL_PKCS1_OAEP_PADDING)) {
throw new RuntimeException('Unable to encrypt channel entry parameter.');
}
return self::base64UrlEncode($ciphertext);
}
public static function decrypt(string $ciphertext, string $privateKey): string
{
$decoded = self::base64UrlDecode($ciphertext);
if ($decoded === null
|| ! openssl_private_decrypt($decoded, $plaintext, $privateKey, OPENSSL_PKCS1_OAEP_PADDING)) {
throw new RuntimeException('Unable to decrypt channel entry parameter.');
}
return trim($plaintext);
}
private static function base64UrlEncode(string $value): string
{
return rtrim(strtr(base64_encode($value), '+/', '-_'), '=');
}
private static function base64UrlDecode(string $value): ?string
{
if ($value === '' || ! preg_match('/^[A-Za-z0-9_-]+$/', $value)) {
return null;
}
$padding = strlen($value) % 4;
if ($padding !== 0) {
$value .= str_repeat('=', 4 - $padding);
}
$decoded = base64_decode(strtr($value, '-_', '+/'), true);
return $decoded === false ? null : $decoded;
}
}