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
78 lines
2.3 KiB
<?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;
|
|
}
|
|
}
|