22declare(strict_types=1);
24namespace pocketmine\network\mcpe\encryption;
29use
function igbinary_serialize;
30use
function igbinary_unserialize;
31use
function openssl_error_string;
32use
function openssl_pkey_get_details;
33use
function openssl_pkey_new;
34use
function random_bytes;
38 private const TLS_KEY_ON_COMPLETION =
"completion";
40 private static ?\OpenSSLAsymmetricKey $SERVER_PRIVATE_KEY =
null;
42 private string $serverPrivateKey;
44 private ?
string $aesKey =
null;
45 private ?
string $handshakeJwt =
null;
51 private string $clientPub,
52 \Closure $onCompletion
54 if(self::$SERVER_PRIVATE_KEY ===
null){
55 $serverPrivateKey = openssl_pkey_new([
"ec" => [
"curve_name" =>
"secp384r1"]]);
56 if($serverPrivateKey ===
false){
57 throw new \RuntimeException(
"openssl_pkey_new() failed: " . openssl_error_string());
59 self::$SERVER_PRIVATE_KEY = $serverPrivateKey;
62 $this->serverPrivateKey = igbinary_serialize(openssl_pkey_get_details(self::$SERVER_PRIVATE_KEY));
63 $this->
storeLocal(self::TLS_KEY_ON_COMPLETION, $onCompletion);
68 $serverPrivDetails = igbinary_unserialize($this->serverPrivateKey);
69 $serverPriv = openssl_pkey_new($serverPrivDetails);
70 if($serverPriv ===
false)
throw new AssumptionFailedError(
"Failed to restore server signing key from details");
71 $clientPub = JwtUtils::parseDerPublicKey($this->clientPub);
72 $sharedSecret = EncryptionUtils::generateSharedSecret($serverPriv, $clientPub);
74 $salt = random_bytes(16);
75 $this->aesKey = EncryptionUtils::generateKey($sharedSecret, $salt);
76 $this->handshakeJwt = EncryptionUtils::generateServerHandshakeJwt($serverPriv, $salt);
84 $callback = $this->fetchLocal(self::TLS_KEY_ON_COMPLETION);
85 if($this->aesKey ===
null || $this->handshakeJwt ===
null){
88 $callback($this->aesKey, $this->handshakeJwt);
__construct(private string $clientPub, \Closure $onCompletion)
storeLocal(string $key, mixed $complexData)