Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions builtin-functions/kphp-light/stdlib/crypto-functions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ function openssl_encrypt($data ::: string, $method ::: string, $key ::: string,
function openssl_decrypt($data ::: string, $method ::: string, $key ::: string, $options ::: int = 0, $iv ::: string = '',
$tag ::: string = '', $aad ::: string = '') ::: string | false;

/** @kphp-extern-func-info interruptible */
function openssl_pkey_get_private ($key ::: string, $passphrase ::: string = '') ::: string | false;
/** @kphp-extern-func-info interruptible */
function openssl_pkey_get_public ($key ::: string) ::: string | false;

/** @kphp-extern-func-info interruptible */
function openssl_public_encrypt ($data ::: string, &$result ::: mixed, $key ::: string) ::: bool;
/** @kphp-extern-func-info interruptible */
function openssl_private_decrypt ($data ::: string, &$result ::: mixed, $key ::: string) ::: bool;

function hash_algos () ::: string[];
function hash_hmac_algos () ::: string[];

Expand Down Expand Up @@ -80,14 +90,6 @@ define('PKCS7_BINARY', 0x80);
define('PKCS7_DETACHED', 0x40);
define('PKCS7_NOATTR', 0x100);

/** @kphp-extern-func-info stub generation-required */
function openssl_public_encrypt ($data ::: string, &$result ::: mixed, $key ::: string) ::: bool;
/** @kphp-extern-func-info stub generation-required */
function openssl_private_decrypt ($data ::: string, &$result ::: mixed, $key ::: string) ::: bool;
/** @kphp-extern-func-info stub generation-required */
function openssl_pkey_get_private ($key ::: string, $passphrase ::: string = '') ::: string | false;
/** @kphp-extern-func-info stub generation-required */
function openssl_pkey_get_public ($key ::: string) ::: string | false;
/** @kphp-extern-func-info stub generation-required */
function openssl_x509_verify ($x509cert ::: string, $public_key ::: string) ::: int;

Expand Down
131 changes: 129 additions & 2 deletions runtime-light/stdlib/crypto/crypto-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,13 @@ kphp::coro::task<int64_t> f$openssl_verify(string data, string signature, string

auto expected_stream{kphp::component::stream::open(CRYPTO_COMPONENT_NAME, k2::stream_kind::component)};
if (!expected_stream) [[unlikely]] {
co_return false;
co_return 0;
}

auto stream{*std::move(expected_stream)};
std::array<std::byte, tl::magic{}.footprint()> response{};
if (!co_await kphp::forks::id_managed(kphp::component::query(stream, tls.view(), response))) [[unlikely]] {
co_return false;
co_return 0;
}

tl::fetcher tlf{response};
Expand Down Expand Up @@ -362,6 +362,133 @@ kphp::coro::task<Optional<string>> f$openssl_decrypt(string data, string method,
co_return string{response.inner.value.data(), static_cast<string::size_type>(response.inner.value.size())};
}

kphp::coro::task<Optional<string>> f$openssl_pkey_get_public(string key) noexcept {
tl::GetPublicKey get_public_key{.key = {.value = {key.c_str(), key.size()}}};
tl::storer tls{get_public_key.footprint()};
get_public_key.store(tls);

auto expected_stream{kphp::component::stream::open(CRYPTO_COMPONENT_NAME, k2::stream_kind::component)};
if (!expected_stream) [[unlikely]] {
co_return false;
}

auto stream{*std::move(expected_stream)};
kphp::stl::vector<std::byte, kphp::memory::script_allocator> response_bytes{};
if (!co_await kphp::forks::id_managed(kphp::component::query(stream, tls.view(), kphp::component::read_ext::append(response_bytes)))) [[unlikely]] {
co_return false;
}

tl::fetcher tlf{response_bytes};
tl::Maybe<tl::string> response;
kphp::log::assertion(response.fetch(tlf));
if (!response.opt_value) {
co_return false;
}

co_return string{(*response.opt_value).value.data(), static_cast<string::size_type>((*response.opt_value).value.size())};
}

kphp::coro::task<Optional<string>> f$openssl_pkey_get_private(string key, string passphrase) noexcept {
tl::GetPrivateKey get_private_key{
.key = {.value = {key.c_str(), key.size()}},
.passphrase = {.value = {passphrase.c_str(), passphrase.size()}},
};
tl::storer tls{get_private_key.footprint()};
get_private_key.store(tls);

auto expected_stream{kphp::component::stream::open(CRYPTO_COMPONENT_NAME, k2::stream_kind::component)};
if (!expected_stream) [[unlikely]] {
co_return false;
}

auto stream{*std::move(expected_stream)};
kphp::stl::vector<std::byte, kphp::memory::script_allocator> response_bytes{};
if (!co_await kphp::forks::id_managed(kphp::component::query(stream, tls.view(), kphp::component::read_ext::append(response_bytes)))) [[unlikely]] {
co_return false;
}

tl::fetcher tlf{response_bytes};
tl::Maybe<tl::string> response;
kphp::log::assertion(response.fetch(tlf));
if (!response.opt_value) {
co_return false;
}

co_return string{(*response.opt_value).value.data(), static_cast<string::size_type>((*response.opt_value).value.size())};
}

kphp::coro::task<bool> f$openssl_public_encrypt(string data, string& encrypted_data, string public_key) noexcept {
tl::PublicEncrypt public_encrypt{
.key = {.value = {public_key.c_str(), public_key.size()}},
.data = {.value = {data.c_str(), data.size()}},
};
tl::storer tls{public_encrypt.footprint()};
public_encrypt.store(tls);

auto expected_stream{kphp::component::stream::open(CRYPTO_COMPONENT_NAME, k2::stream_kind::component)};
if (!expected_stream) [[unlikely]] {
co_return false;
}

auto stream{*std::move(expected_stream)};
kphp::stl::vector<std::byte, kphp::memory::script_allocator> response_bytes{};
if (!co_await kphp::forks::id_managed(kphp::component::query(stream, tls.view(), kphp::component::read_ext::append(response_bytes)))) [[unlikely]] {
co_return false;
}

tl::fetcher tlf{response_bytes};
tl::String response{};
kphp::log::assertion(response.fetch(tlf));
encrypted_data = {response.inner.value.data(), static_cast<string::size_type>(response.inner.value.size())};
co_return true;
}

kphp::coro::task<bool> f$openssl_public_encrypt(string data, mixed& result, string key) noexcept {
string result_string;
if (co_await f$openssl_public_encrypt(data, result_string, key)) {
result = std::move(result_string);
co_return true;
}
result = mixed{};
co_return false;
}

kphp::coro::task<bool> f$openssl_private_decrypt(string data, string& decrypted_data, string private_key) noexcept {
tl::PrivateDecrypt private_decrypt{
.key = {.value = {private_key.c_str(), private_key.size()}},
.data = {.value = {data.c_str(), data.size()}},
};
tl::storer tls{private_decrypt.footprint()};
private_decrypt.store(tls);

auto expected_stream{kphp::component::stream::open(CRYPTO_COMPONENT_NAME, k2::stream_kind::component)};
if (!expected_stream) [[unlikely]] {
co_return false;
}

auto stream{*std::move(expected_stream)};
kphp::stl::vector<std::byte, kphp::memory::script_allocator> response_bytes{};
if (!co_await kphp::forks::id_managed(kphp::component::query(stream, tls.view(), kphp::component::read_ext::append(response_bytes)))) [[unlikely]] {
co_return false;
}

tl::fetcher tlf{response_bytes};
tl::String response{};
kphp::log::assertion(response.fetch(tlf));
decrypted_data = {response.inner.value.data(), static_cast<string::size_type>(response.inner.value.size())};
co_return true;
}

kphp::coro::task<bool> f$openssl_private_decrypt(string data, mixed& result, string key) noexcept {
string result_string;
if (co_await f$openssl_private_decrypt(data, result_string, key)) {
result = std::move(result_string);
co_return true;
}
result = mixed{};
co_return false;
}

namespace {

constexpr std::array<std::pair<std::string_view, tl::HashAlgorithm>, 6> HASH_ALGOS = {{{"md5", tl::HashAlgorithm::MD5},
Expand Down
8 changes: 8 additions & 0 deletions runtime-light/stdlib/crypto/crypto-functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ kphp::coro::task<Optional<string>> f$openssl_encrypt(string data, string method,
kphp::coro::task<Optional<string>> f$openssl_decrypt(string data, string method, string key, int64_t options = 0, string iv = string{}, string tag = string{},
string aad = string{}) noexcept;

kphp::coro::task<Optional<string>> f$openssl_pkey_get_public(string key) noexcept;

kphp::coro::task<Optional<string>> f$openssl_pkey_get_private(string key, string passphrase = string{}) noexcept;

kphp::coro::task<bool> f$openssl_public_encrypt(string data, mixed& result, string key) noexcept;

kphp::coro::task<bool> f$openssl_private_decrypt(string data, mixed& result, string key) noexcept;

array<string> f$hash_algos() noexcept;

array<string> f$hash_hmac_algos() noexcept;
Expand Down
19 changes: 19 additions & 0 deletions runtime-light/stdlib/crypto/crypto_schema.tl
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,25 @@ cbcEncrypt#6d4ee36a
data : string
= String;

getPublicKey#4b1e7d3d
key : string
= Maybe string;

getPrivateKey#34eadfdb
key : string
passphrase : string
= Maybe string;

publicEncrypt#7612f4ad
key : string
data : string
= String;

privateDecrypt#c6e91d4d
key : string
data : string
= String;

hash#50732a27
algorithm : HashAlgorithm
data : string
Expand Down
62 changes: 62 additions & 0 deletions runtime-light/tl/tl-functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ inline constexpr uint32_t DIGEST_SIGN_MAGIC = 0xd345'f658;
inline constexpr uint32_t DIGEST_VERIFY_MAGIC = 0x5760'bd0e;
inline constexpr uint32_t CBC_DECRYPT_MAGIC = 0x7f2e'e1e4;
inline constexpr uint32_t CBC_ENCRYPT_MAGIC = 0x6d4e'e36a;
inline constexpr uint32_t GET_PUBLIC_KEY_MAGIC = 0x4b1e'7d3d;
inline constexpr uint32_t GET_PRIVATE_KEY_MAGIC = 0x34ea'dfdb;
inline constexpr uint32_t PUBLIC_ENCRYPT_MAGIC = 0x7612'f4ad;
inline constexpr uint32_t PRIVATE_DECRYPT_MAGIC = 0xc6e9'1d4d;
inline constexpr uint32_t HASH_MAGIC = 0x5073'2a27;
inline constexpr uint32_t HASH_HMAC_MAGIC = 0x8dcb'3d9d;

Expand Down Expand Up @@ -150,6 +154,64 @@ struct CbcEncrypt final {
}
};

struct GetPublicKey final {
tl::string key;

void store(tl::storer& tls) const noexcept {
tl::magic{.value = GET_PUBLIC_KEY_MAGIC}.store(tls);
key.store(tls);
}

constexpr size_t footprint() const noexcept {
return tl::magic{.value = GET_PUBLIC_KEY_MAGIC}.footprint() + key.footprint();
}
};

struct GetPrivateKey final {
tl::string key;
tl::string passphrase;

void store(tl::storer& tls) const noexcept {
tl::magic{.value = GET_PRIVATE_KEY_MAGIC}.store(tls);
key.store(tls);
passphrase.store(tls);
}

constexpr size_t footprint() const noexcept {
return tl::magic{.value = GET_PRIVATE_KEY_MAGIC}.footprint() + key.footprint() + passphrase.footprint();
}
};

struct PublicEncrypt final {
tl::string key;
tl::string data;

void store(tl::storer& tls) const noexcept {
tl::magic{.value = PUBLIC_ENCRYPT_MAGIC}.store(tls);
key.store(tls);
data.store(tls);
}

constexpr size_t footprint() const noexcept {
return tl::magic{.value = PUBLIC_ENCRYPT_MAGIC}.footprint() + key.footprint() + data.footprint();
}
};

struct PrivateDecrypt final {
tl::string key;
tl::string data;

void store(tl::storer& tls) const noexcept {
tl::magic{.value = PRIVATE_DECRYPT_MAGIC}.store(tls);
key.store(tls);
data.store(tls);
}

constexpr size_t footprint() const noexcept {
return tl::magic{.value = PRIVATE_DECRYPT_MAGIC}.footprint() + key.footprint() + data.footprint();
}
};

struct Hash final {
tl::HashAlgorithm algorithm{};
tl::string data;
Expand Down
2 changes: 1 addition & 1 deletion tests/phpt/openssl/1_openssl_basic.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@ok k2_skip
@ok
<?php

$ads_public_key = <<<EOF
Expand Down
Loading