diff --git a/td/telegram/SecureStorage.cpp b/td/telegram/SecureStorage.cpp index 74dedcba..1e9b890b 100644 --- a/td/telegram/SecureStorage.cpp +++ b/td/telegram/SecureStorage.cpp @@ -43,7 +43,7 @@ Result calc_value_hash(DataView &data_view) { } BufferSlice gen_random_prefix(int64 data_size) { - BufferSlice buff(((32 + 15 + data_size) & -16) - data_size); + BufferSlice buff(narrow_cast(((32 + 15 + data_size) & -16) - data_size)); Random::secure_bytes(buff.as_slice()); buff.as_slice()[0] = narrow_cast(buff.size()); CHECK((buff.size() + data_size) % 16 == 0); @@ -58,7 +58,7 @@ int64 FileDataView::size() { } Result FileDataView::pread(int64 offset, int64 size) { - auto slice = BufferSlice(size); + auto slice = BufferSlice(narrow_cast(size)); TRY_RESULT(actual_size, fd_.pread(slice.as_slice(), offset)); if (static_cast(actual_size) != size) { return Status::Error("Not enough data in file"); @@ -69,14 +69,14 @@ Result FileDataView::pread(int64 offset, int64 size) { BufferSliceDataView::BufferSliceDataView(BufferSlice buffer_slice) : buffer_slice_(std::move(buffer_slice)) { } int64 BufferSliceDataView::size() { - return buffer_slice_.size(); + return narrow_cast(buffer_slice_.size()); } Result BufferSliceDataView::pread(int64 offset, int64 size) { auto end_offset = size + offset; if (this->size() < end_offset) { return Status::Error("Not enough data in BufferSlice"); } - return BufferSlice(buffer_slice_.as_slice().substr(offset, size)); + return BufferSlice(buffer_slice_.as_slice().substr(narrow_cast(offset), narrow_cast(size))); } ConcatDataView::ConcatDataView(DataView &left, DataView &right) : left_(left), right_(right) { diff --git a/tdutils/td/utils/crypto.cpp b/tdutils/td/utils/crypto.cpp index afacf153..25e7679e 100644 --- a/tdutils/td/utils/crypto.cpp +++ b/tdutils/td/utils/crypto.cpp @@ -15,14 +15,14 @@ #if TD_HAVE_OPENSSL #include -#include +#include #include #include #include #include -#include #include #include +#include #endif #if TD_HAVE_ZLIB @@ -557,8 +557,17 @@ uint64 crc64(Slice data) { return crc64_partial(data, static_cast(-1)) ^ static_cast(-1); } +static int get_evp_pkey_type(EVP_PKEY *pkey) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + return EVP_PKEY_type(pkey->type); +#else + return EVP_PKEY_base_id(pkey); +#endif +} + Result rsa_encrypt_pkcs1_oaep(Slice public_key, Slice data) { - BIO *mem_bio = BIO_new_mem_buf(public_key.data(), narrow_cast(public_key.size())); + BIO *mem_bio = BIO_new_mem_buf(const_cast(static_cast(public_key.data())), + narrow_cast(public_key.size())); SCOPE_EXIT { BIO_vfree(mem_bio); }; @@ -567,30 +576,43 @@ Result rsa_encrypt_pkcs1_oaep(Slice public_key, Slice data) { if (!pkey) { return Status::Error("Cannot read public key"); } + SCOPE_EXIT { + EVP_PKEY_free(pkey); + }; + if (get_evp_pkey_type(pkey) != EVP_PKEY_RSA) { + return Status::Error("Wrong key type, expected RSA"); + } + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, nullptr); if (!ctx) { return Status::Error("Cannot create EVP_PKEY_CTX"); } + SCOPE_EXIT { + EVP_PKEY_CTX_free(ctx); + }; + if (EVP_PKEY_encrypt_init(ctx) <= 0) { return Status::Error("Cannot init EVP_PKEY_CTX"); } if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) { return Status::Error("Cannot set RSA_PKCS1_OAEP padding in EVP_PKEY_CTX"); } + size_t outlen; if (EVP_PKEY_encrypt(ctx, nullptr, &outlen, data.ubegin(), data.size()) <= 0) { return Status::Error("Cannot calculate encrypted length"); } BufferSlice res(outlen); if (EVP_PKEY_encrypt(ctx, res.as_slice().ubegin(), &outlen, data.ubegin(), data.size()) <= 0) { - ERR_print_errors_fp(stderr); + // ERR_print_errors_fp(stderr); return Status::Error("Cannot encrypt"); } return std::move(res); } Result rsa_decrypt_pkcs1_oaep(Slice private_key, Slice data) { - BIO *mem_bio = BIO_new_mem_buf(private_key.data(), narrow_cast(private_key.size())); + BIO *mem_bio = BIO_new_mem_buf(const_cast(static_cast(private_key.data())), + narrow_cast(private_key.size())); SCOPE_EXIT { BIO_vfree(mem_bio); }; @@ -599,16 +621,28 @@ Result rsa_decrypt_pkcs1_oaep(Slice private_key, Slice data) { if (!pkey) { return Status::Error("Cannot read private key"); } + SCOPE_EXIT { + EVP_PKEY_free(pkey); + }; + if (get_evp_pkey_type(pkey) != EVP_PKEY_RSA) { + return Status::Error("Wrong key type, expected RSA"); + } + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, nullptr); if (!ctx) { return Status::Error("Cannot create EVP_PKEY_CTX"); } + SCOPE_EXIT { + EVP_PKEY_CTX_free(ctx); + }; + if (EVP_PKEY_decrypt_init(ctx) <= 0) { return Status::Error("Cannot init EVP_PKEY_CTX"); } if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) { return Status::Error("Cannot set RSA_PKCS1_OAEP padding in EVP_PKEY_CTX"); } + size_t outlen; if (EVP_PKEY_decrypt(ctx, nullptr, &outlen, data.ubegin(), data.size()) <= 0) { return Status::Error("Cannot calculate decrypted length"); diff --git a/tdutils/td/utils/crypto.h b/tdutils/td/utils/crypto.h index 6e32e08a..fc59b6d0 100644 --- a/tdutils/td/utils/crypto.h +++ b/tdutils/td/utils/crypto.h @@ -6,9 +6,9 @@ // #pragma once +#include "td/utils/buffer.h" #include "td/utils/common.h" #include "td/utils/Slice.h" -#include "td/utils/buffer.h" #include "td/utils/Status.h" namespace td { @@ -85,7 +85,7 @@ void hmac_sha256(Slice key, Slice message, MutableSlice dest); // Interface may be improved Result rsa_encrypt_pkcs1_oaep(Slice public_key, Slice data); -Result rsa_decrypt_pkcs1_oaep(Slice public_key, Slice data); +Result rsa_decrypt_pkcs1_oaep(Slice private_key, Slice data); void init_openssl_threads(); #endif diff --git a/test/secure_storage.cpp b/test/secure_storage.cpp index 912e5ca8..5fdcdb5b 100644 --- a/test/secure_storage.cpp +++ b/test/secure_storage.cpp @@ -29,20 +29,22 @@ TEST(SecureStorage, simple) { BufferSlice value("Small tale about cucumbers"); auto value_secret = Secret::create_new(); - auto value_view = BufferSliceDataView(value.copy()); - BufferSlice prefix = gen_random_prefix(value_view.size()); - auto prefix_view = BufferSliceDataView(std::move(prefix)); - auto full_value_view = ConcatDataView(prefix_view, value_view); - auto hash = calc_value_hash(full_value_view).move_as_ok(); + { + auto value_view = BufferSliceDataView(value.copy()); + BufferSlice prefix = gen_random_prefix(value_view.size()); + auto prefix_view = BufferSliceDataView(std::move(prefix)); + auto full_value_view = ConcatDataView(prefix_view, value_view); + auto hash = calc_value_hash(full_value_view).move_as_ok(); - Encryptor encryptor(calc_aes_cbc_state(PSLICE() << value_secret.as_slice() << hash.as_slice()), full_value_view); - auto encrypted_value = encryptor.pread(0, encryptor.size()).move_as_ok(); + Encryptor encryptor(calc_aes_cbc_state(PSLICE() << value_secret.as_slice() << hash.as_slice()), full_value_view); + auto encrypted_value = encryptor.pread(0, encryptor.size()).move_as_ok(); - Decryptor decryptor(calc_aes_cbc_state(PSLICE() << value_secret.as_slice() << hash.as_slice())); - auto res = decryptor.append(encrypted_value.copy()).move_as_ok(); - auto decrypted_hash = decryptor.finish().ok(); - ASSERT_TRUE(decrypted_hash.as_slice() == hash.as_slice()); - ASSERT_TRUE(res.as_slice() == value.as_slice()); + Decryptor decryptor(calc_aes_cbc_state(PSLICE() << value_secret.as_slice() << hash.as_slice())); + auto res = decryptor.append(encrypted_value.copy()).move_as_ok(); + auto decrypted_hash = decryptor.finish().ok(); + ASSERT_TRUE(decrypted_hash.as_slice() == hash.as_slice()); + ASSERT_TRUE(res.as_slice() == value.as_slice()); + } { auto encrypted_value = encrypt_value(value_secret, value.as_slice()).move_as_ok();