Skip to content

Commit f5dd325

Browse files
T-y-c-o-o-nNikita Siniachenko
andauthored
[k2] public_encrypt, private_decrypt, pkey_get_public, pkey_get_private (#1421)
Implemented builtins in runtime-lightweight: > openssl_pkey_get_public > openssl_pkey_get_private > openssl_public_encrypt > openssl_private_decrypt --------- Co-authored-by: Nikita Siniachenko <n.sinyachenko@vk.team>
1 parent b0ad768 commit f5dd325

6 files changed

Lines changed: 229 additions & 11 deletions

File tree

builtin-functions/kphp-light/stdlib/crypto-functions.txt

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,16 @@ function openssl_encrypt($data ::: string, $method ::: string, $key ::: string,
4242
function openssl_decrypt($data ::: string, $method ::: string, $key ::: string, $options ::: int = 0, $iv ::: string = '',
4343
$tag ::: string = '', $aad ::: string = '') ::: string | false;
4444

45+
/** @kphp-extern-func-info interruptible */
46+
function openssl_pkey_get_private ($key ::: string, $passphrase ::: string = '') ::: string | false;
47+
/** @kphp-extern-func-info interruptible */
48+
function openssl_pkey_get_public ($key ::: string) ::: string | false;
49+
50+
/** @kphp-extern-func-info interruptible */
51+
function openssl_public_encrypt ($data ::: string, &$result ::: mixed, $key ::: string) ::: bool;
52+
/** @kphp-extern-func-info interruptible */
53+
function openssl_private_decrypt ($data ::: string, &$result ::: mixed, $key ::: string) ::: bool;
54+
4555
function hash_algos () ::: string[];
4656
function hash_hmac_algos () ::: string[];
4757

@@ -80,14 +90,6 @@ define('PKCS7_BINARY', 0x80);
8090
define('PKCS7_DETACHED', 0x40);
8191
define('PKCS7_NOATTR', 0x100);
8292

83-
/** @kphp-extern-func-info stub generation-required */
84-
function openssl_public_encrypt ($data ::: string, &$result ::: mixed, $key ::: string) ::: bool;
85-
/** @kphp-extern-func-info stub generation-required */
86-
function openssl_private_decrypt ($data ::: string, &$result ::: mixed, $key ::: string) ::: bool;
87-
/** @kphp-extern-func-info stub generation-required */
88-
function openssl_pkey_get_private ($key ::: string, $passphrase ::: string = '') ::: string | false;
89-
/** @kphp-extern-func-info stub generation-required */
90-
function openssl_pkey_get_public ($key ::: string) ::: string | false;
9193
/** @kphp-extern-func-info stub generation-required */
9294
function openssl_x509_verify ($x509cert ::: string, $public_key ::: string) ::: int;
9395

runtime-light/stdlib/crypto/crypto-functions.cpp

Lines changed: 129 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,13 +144,13 @@ kphp::coro::task<int64_t> f$openssl_verify(string data, string signature, string
144144

145145
auto expected_stream{kphp::component::stream::open(CRYPTO_COMPONENT_NAME, k2::stream_kind::component)};
146146
if (!expected_stream) [[unlikely]] {
147-
co_return false;
147+
co_return 0;
148148
}
149149

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

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

365+
kphp::coro::task<Optional<string>> f$openssl_pkey_get_public(string key) noexcept {
366+
tl::GetPublicKey get_public_key{.key = {.value = {key.c_str(), key.size()}}};
367+
tl::storer tls{get_public_key.footprint()};
368+
get_public_key.store(tls);
369+
370+
auto expected_stream{kphp::component::stream::open(CRYPTO_COMPONENT_NAME, k2::stream_kind::component)};
371+
if (!expected_stream) [[unlikely]] {
372+
co_return false;
373+
}
374+
375+
auto stream{*std::move(expected_stream)};
376+
kphp::stl::vector<std::byte, kphp::memory::script_allocator> response_bytes{};
377+
if (!co_await kphp::forks::id_managed(kphp::component::query(stream, tls.view(), kphp::component::read_ext::append(response_bytes)))) [[unlikely]] {
378+
co_return false;
379+
}
380+
381+
tl::fetcher tlf{response_bytes};
382+
tl::Maybe<tl::string> response;
383+
kphp::log::assertion(response.fetch(tlf));
384+
if (!response.opt_value) {
385+
co_return false;
386+
}
387+
388+
co_return string{(*response.opt_value).value.data(), static_cast<string::size_type>((*response.opt_value).value.size())};
389+
}
390+
391+
kphp::coro::task<Optional<string>> f$openssl_pkey_get_private(string key, string passphrase) noexcept {
392+
tl::GetPrivateKey get_private_key{
393+
.key = {.value = {key.c_str(), key.size()}},
394+
.passphrase = {.value = {passphrase.c_str(), passphrase.size()}},
395+
};
396+
tl::storer tls{get_private_key.footprint()};
397+
get_private_key.store(tls);
398+
399+
auto expected_stream{kphp::component::stream::open(CRYPTO_COMPONENT_NAME, k2::stream_kind::component)};
400+
if (!expected_stream) [[unlikely]] {
401+
co_return false;
402+
}
403+
404+
auto stream{*std::move(expected_stream)};
405+
kphp::stl::vector<std::byte, kphp::memory::script_allocator> response_bytes{};
406+
if (!co_await kphp::forks::id_managed(kphp::component::query(stream, tls.view(), kphp::component::read_ext::append(response_bytes)))) [[unlikely]] {
407+
co_return false;
408+
}
409+
410+
tl::fetcher tlf{response_bytes};
411+
tl::Maybe<tl::string> response;
412+
kphp::log::assertion(response.fetch(tlf));
413+
if (!response.opt_value) {
414+
co_return false;
415+
}
416+
417+
co_return string{(*response.opt_value).value.data(), static_cast<string::size_type>((*response.opt_value).value.size())};
418+
}
419+
420+
kphp::coro::task<bool> f$openssl_public_encrypt(string data, string& encrypted_data, string public_key) noexcept {
421+
tl::PublicEncrypt public_encrypt{
422+
.key = {.value = {public_key.c_str(), public_key.size()}},
423+
.data = {.value = {data.c_str(), data.size()}},
424+
};
425+
tl::storer tls{public_encrypt.footprint()};
426+
public_encrypt.store(tls);
427+
428+
auto expected_stream{kphp::component::stream::open(CRYPTO_COMPONENT_NAME, k2::stream_kind::component)};
429+
if (!expected_stream) [[unlikely]] {
430+
co_return false;
431+
}
432+
433+
auto stream{*std::move(expected_stream)};
434+
kphp::stl::vector<std::byte, kphp::memory::script_allocator> response_bytes{};
435+
if (!co_await kphp::forks::id_managed(kphp::component::query(stream, tls.view(), kphp::component::read_ext::append(response_bytes)))) [[unlikely]] {
436+
co_return false;
437+
}
438+
439+
tl::fetcher tlf{response_bytes};
440+
tl::String response{};
441+
kphp::log::assertion(response.fetch(tlf));
442+
encrypted_data = {response.inner.value.data(), static_cast<string::size_type>(response.inner.value.size())};
443+
co_return true;
444+
}
445+
446+
kphp::coro::task<bool> f$openssl_public_encrypt(string data, mixed& result, string key) noexcept {
447+
string result_string;
448+
if (co_await f$openssl_public_encrypt(data, result_string, key)) {
449+
result = std::move(result_string);
450+
co_return true;
451+
}
452+
result = mixed{};
453+
co_return false;
454+
}
455+
456+
kphp::coro::task<bool> f$openssl_private_decrypt(string data, string& decrypted_data, string private_key) noexcept {
457+
tl::PrivateDecrypt private_decrypt{
458+
.key = {.value = {private_key.c_str(), private_key.size()}},
459+
.data = {.value = {data.c_str(), data.size()}},
460+
};
461+
tl::storer tls{private_decrypt.footprint()};
462+
private_decrypt.store(tls);
463+
464+
auto expected_stream{kphp::component::stream::open(CRYPTO_COMPONENT_NAME, k2::stream_kind::component)};
465+
if (!expected_stream) [[unlikely]] {
466+
co_return false;
467+
}
468+
469+
auto stream{*std::move(expected_stream)};
470+
kphp::stl::vector<std::byte, kphp::memory::script_allocator> response_bytes{};
471+
if (!co_await kphp::forks::id_managed(kphp::component::query(stream, tls.view(), kphp::component::read_ext::append(response_bytes)))) [[unlikely]] {
472+
co_return false;
473+
}
474+
475+
tl::fetcher tlf{response_bytes};
476+
tl::String response{};
477+
kphp::log::assertion(response.fetch(tlf));
478+
decrypted_data = {response.inner.value.data(), static_cast<string::size_type>(response.inner.value.size())};
479+
co_return true;
480+
}
481+
482+
kphp::coro::task<bool> f$openssl_private_decrypt(string data, mixed& result, string key) noexcept {
483+
string result_string;
484+
if (co_await f$openssl_private_decrypt(data, result_string, key)) {
485+
result = std::move(result_string);
486+
co_return true;
487+
}
488+
result = mixed{};
489+
co_return false;
490+
}
491+
365492
namespace {
366493

367494
constexpr std::array<std::pair<std::string_view, tl::HashAlgorithm>, 6> HASH_ALGOS = {{{"md5", tl::HashAlgorithm::MD5},

runtime-light/stdlib/crypto/crypto-functions.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ kphp::coro::task<Optional<string>> f$openssl_encrypt(string data, string method,
3232
kphp::coro::task<Optional<string>> f$openssl_decrypt(string data, string method, string key, int64_t options = 0, string iv = string{}, string tag = string{},
3333
string aad = string{}) noexcept;
3434

35+
kphp::coro::task<Optional<string>> f$openssl_pkey_get_public(string key) noexcept;
36+
37+
kphp::coro::task<Optional<string>> f$openssl_pkey_get_private(string key, string passphrase = string{}) noexcept;
38+
39+
kphp::coro::task<bool> f$openssl_public_encrypt(string data, mixed& result, string key) noexcept;
40+
41+
kphp::coro::task<bool> f$openssl_private_decrypt(string data, mixed& result, string key) noexcept;
42+
3543
array<string> f$hash_algos() noexcept;
3644

3745
array<string> f$hash_hmac_algos() noexcept;

runtime-light/stdlib/crypto/crypto_schema.tl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,25 @@ cbcEncrypt#6d4ee36a
7878
data : string
7979
= String;
8080

81+
getPublicKey#4b1e7d3d
82+
key : string
83+
= Maybe string;
84+
85+
getPrivateKey#34eadfdb
86+
key : string
87+
passphrase : string
88+
= Maybe string;
89+
90+
publicEncrypt#7612f4ad
91+
key : string
92+
data : string
93+
= String;
94+
95+
privateDecrypt#c6e91d4d
96+
key : string
97+
data : string
98+
= String;
99+
81100
hash#50732a27
82101
algorithm : HashAlgorithm
83102
data : string

runtime-light/tl/tl-functions.h

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ inline constexpr uint32_t DIGEST_SIGN_MAGIC = 0xd345'f658;
4141
inline constexpr uint32_t DIGEST_VERIFY_MAGIC = 0x5760'bd0e;
4242
inline constexpr uint32_t CBC_DECRYPT_MAGIC = 0x7f2e'e1e4;
4343
inline constexpr uint32_t CBC_ENCRYPT_MAGIC = 0x6d4e'e36a;
44+
inline constexpr uint32_t GET_PUBLIC_KEY_MAGIC = 0x4b1e'7d3d;
45+
inline constexpr uint32_t GET_PRIVATE_KEY_MAGIC = 0x34ea'dfdb;
46+
inline constexpr uint32_t PUBLIC_ENCRYPT_MAGIC = 0x7612'f4ad;
47+
inline constexpr uint32_t PRIVATE_DECRYPT_MAGIC = 0xc6e9'1d4d;
4448
inline constexpr uint32_t HASH_MAGIC = 0x5073'2a27;
4549
inline constexpr uint32_t HASH_HMAC_MAGIC = 0x8dcb'3d9d;
4650

@@ -150,6 +154,64 @@ struct CbcEncrypt final {
150154
}
151155
};
152156

157+
struct GetPublicKey final {
158+
tl::string key;
159+
160+
void store(tl::storer& tls) const noexcept {
161+
tl::magic{.value = GET_PUBLIC_KEY_MAGIC}.store(tls);
162+
key.store(tls);
163+
}
164+
165+
constexpr size_t footprint() const noexcept {
166+
return tl::magic{.value = GET_PUBLIC_KEY_MAGIC}.footprint() + key.footprint();
167+
}
168+
};
169+
170+
struct GetPrivateKey final {
171+
tl::string key;
172+
tl::string passphrase;
173+
174+
void store(tl::storer& tls) const noexcept {
175+
tl::magic{.value = GET_PRIVATE_KEY_MAGIC}.store(tls);
176+
key.store(tls);
177+
passphrase.store(tls);
178+
}
179+
180+
constexpr size_t footprint() const noexcept {
181+
return tl::magic{.value = GET_PRIVATE_KEY_MAGIC}.footprint() + key.footprint() + passphrase.footprint();
182+
}
183+
};
184+
185+
struct PublicEncrypt final {
186+
tl::string key;
187+
tl::string data;
188+
189+
void store(tl::storer& tls) const noexcept {
190+
tl::magic{.value = PUBLIC_ENCRYPT_MAGIC}.store(tls);
191+
key.store(tls);
192+
data.store(tls);
193+
}
194+
195+
constexpr size_t footprint() const noexcept {
196+
return tl::magic{.value = PUBLIC_ENCRYPT_MAGIC}.footprint() + key.footprint() + data.footprint();
197+
}
198+
};
199+
200+
struct PrivateDecrypt final {
201+
tl::string key;
202+
tl::string data;
203+
204+
void store(tl::storer& tls) const noexcept {
205+
tl::magic{.value = PRIVATE_DECRYPT_MAGIC}.store(tls);
206+
key.store(tls);
207+
data.store(tls);
208+
}
209+
210+
constexpr size_t footprint() const noexcept {
211+
return tl::magic{.value = PRIVATE_DECRYPT_MAGIC}.footprint() + key.footprint() + data.footprint();
212+
}
213+
};
214+
153215
struct Hash final {
154216
tl::HashAlgorithm algorithm{};
155217
tl::string data;

tests/phpt/openssl/1_openssl_basic.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@ok k2_skip
1+
@ok
22
<?php
33

44
$ads_public_key = <<<EOF

0 commit comments

Comments
 (0)