RSA encrypt/decrypt and warning fixes.

GitOrigin-RevId: 6d556509d911678c1dd7d489132c07f942f3be0f
This commit is contained in:
levlam 2018-03-26 21:14:15 +03:00
parent 372196280c
commit b6637ccfc5
4 changed files with 59 additions and 23 deletions

View File

@ -43,7 +43,7 @@ Result<ValueHash> calc_value_hash(DataView &data_view) {
} }
BufferSlice gen_random_prefix(int64 data_size) { BufferSlice gen_random_prefix(int64 data_size) {
BufferSlice buff(((32 + 15 + data_size) & -16) - data_size); BufferSlice buff(narrow_cast<size_t>(((32 + 15 + data_size) & -16) - data_size));
Random::secure_bytes(buff.as_slice()); Random::secure_bytes(buff.as_slice());
buff.as_slice()[0] = narrow_cast<uint8>(buff.size()); buff.as_slice()[0] = narrow_cast<uint8>(buff.size());
CHECK((buff.size() + data_size) % 16 == 0); CHECK((buff.size() + data_size) % 16 == 0);
@ -58,7 +58,7 @@ int64 FileDataView::size() {
} }
Result<BufferSlice> FileDataView::pread(int64 offset, int64 size) { Result<BufferSlice> FileDataView::pread(int64 offset, int64 size) {
auto slice = BufferSlice(size); auto slice = BufferSlice(narrow_cast<size_t>(size));
TRY_RESULT(actual_size, fd_.pread(slice.as_slice(), offset)); TRY_RESULT(actual_size, fd_.pread(slice.as_slice(), offset));
if (static_cast<int64>(actual_size) != size) { if (static_cast<int64>(actual_size) != size) {
return Status::Error("Not enough data in file"); return Status::Error("Not enough data in file");
@ -69,14 +69,14 @@ Result<BufferSlice> FileDataView::pread(int64 offset, int64 size) {
BufferSliceDataView::BufferSliceDataView(BufferSlice buffer_slice) : buffer_slice_(std::move(buffer_slice)) { BufferSliceDataView::BufferSliceDataView(BufferSlice buffer_slice) : buffer_slice_(std::move(buffer_slice)) {
} }
int64 BufferSliceDataView::size() { int64 BufferSliceDataView::size() {
return buffer_slice_.size(); return narrow_cast<int64>(buffer_slice_.size());
} }
Result<BufferSlice> BufferSliceDataView::pread(int64 offset, int64 size) { Result<BufferSlice> BufferSliceDataView::pread(int64 offset, int64 size) {
auto end_offset = size + offset; auto end_offset = size + offset;
if (this->size() < end_offset) { if (this->size() < end_offset) {
return Status::Error("Not enough data in BufferSlice"); 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<size_t>(offset), narrow_cast<size_t>(size)));
} }
ConcatDataView::ConcatDataView(DataView &left, DataView &right) : left_(left), right_(right) { ConcatDataView::ConcatDataView(DataView &left, DataView &right) : left_(left), right_(right) {

View File

@ -15,14 +15,14 @@
#if TD_HAVE_OPENSSL #if TD_HAVE_OPENSSL
#include <openssl/aes.h> #include <openssl/aes.h>
#include <openssl/engine.h> #include <openssl/bio.h>
#include <openssl/crypto.h> #include <openssl/crypto.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/hmac.h> #include <openssl/hmac.h>
#include <openssl/md5.h> #include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/pem.h> #include <openssl/pem.h>
#include <openssl/rsa.h> #include <openssl/rsa.h>
#include <openssl/sha.h>
#endif #endif
#if TD_HAVE_ZLIB #if TD_HAVE_ZLIB
@ -557,8 +557,17 @@ uint64 crc64(Slice data) {
return crc64_partial(data, static_cast<uint64>(-1)) ^ static_cast<uint64>(-1); return crc64_partial(data, static_cast<uint64>(-1)) ^ static_cast<uint64>(-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<BufferSlice> rsa_encrypt_pkcs1_oaep(Slice public_key, Slice data) { Result<BufferSlice> rsa_encrypt_pkcs1_oaep(Slice public_key, Slice data) {
BIO *mem_bio = BIO_new_mem_buf(public_key.data(), narrow_cast<int>(public_key.size())); BIO *mem_bio = BIO_new_mem_buf(const_cast<void *>(static_cast<const void *>(public_key.data())),
narrow_cast<int>(public_key.size()));
SCOPE_EXIT { SCOPE_EXIT {
BIO_vfree(mem_bio); BIO_vfree(mem_bio);
}; };
@ -567,30 +576,43 @@ Result<BufferSlice> rsa_encrypt_pkcs1_oaep(Slice public_key, Slice data) {
if (!pkey) { if (!pkey) {
return Status::Error("Cannot read public key"); 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); EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, nullptr);
if (!ctx) { if (!ctx) {
return Status::Error("Cannot create EVP_PKEY_CTX"); return Status::Error("Cannot create EVP_PKEY_CTX");
} }
SCOPE_EXIT {
EVP_PKEY_CTX_free(ctx);
};
if (EVP_PKEY_encrypt_init(ctx) <= 0) { if (EVP_PKEY_encrypt_init(ctx) <= 0) {
return Status::Error("Cannot init EVP_PKEY_CTX"); return Status::Error("Cannot init EVP_PKEY_CTX");
} }
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) { 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"); return Status::Error("Cannot set RSA_PKCS1_OAEP padding in EVP_PKEY_CTX");
} }
size_t outlen; size_t outlen;
if (EVP_PKEY_encrypt(ctx, nullptr, &outlen, data.ubegin(), data.size()) <= 0) { if (EVP_PKEY_encrypt(ctx, nullptr, &outlen, data.ubegin(), data.size()) <= 0) {
return Status::Error("Cannot calculate encrypted length"); return Status::Error("Cannot calculate encrypted length");
} }
BufferSlice res(outlen); BufferSlice res(outlen);
if (EVP_PKEY_encrypt(ctx, res.as_slice().ubegin(), &outlen, data.ubegin(), data.size()) <= 0) { 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 Status::Error("Cannot encrypt");
} }
return std::move(res); return std::move(res);
} }
Result<BufferSlice> rsa_decrypt_pkcs1_oaep(Slice private_key, Slice data) { Result<BufferSlice> rsa_decrypt_pkcs1_oaep(Slice private_key, Slice data) {
BIO *mem_bio = BIO_new_mem_buf(private_key.data(), narrow_cast<int>(private_key.size())); BIO *mem_bio = BIO_new_mem_buf(const_cast<void *>(static_cast<const void *>(private_key.data())),
narrow_cast<int>(private_key.size()));
SCOPE_EXIT { SCOPE_EXIT {
BIO_vfree(mem_bio); BIO_vfree(mem_bio);
}; };
@ -599,16 +621,28 @@ Result<BufferSlice> rsa_decrypt_pkcs1_oaep(Slice private_key, Slice data) {
if (!pkey) { if (!pkey) {
return Status::Error("Cannot read private key"); 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); EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, nullptr);
if (!ctx) { if (!ctx) {
return Status::Error("Cannot create EVP_PKEY_CTX"); return Status::Error("Cannot create EVP_PKEY_CTX");
} }
SCOPE_EXIT {
EVP_PKEY_CTX_free(ctx);
};
if (EVP_PKEY_decrypt_init(ctx) <= 0) { if (EVP_PKEY_decrypt_init(ctx) <= 0) {
return Status::Error("Cannot init EVP_PKEY_CTX"); return Status::Error("Cannot init EVP_PKEY_CTX");
} }
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) { 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"); return Status::Error("Cannot set RSA_PKCS1_OAEP padding in EVP_PKEY_CTX");
} }
size_t outlen; size_t outlen;
if (EVP_PKEY_decrypt(ctx, nullptr, &outlen, data.ubegin(), data.size()) <= 0) { if (EVP_PKEY_decrypt(ctx, nullptr, &outlen, data.ubegin(), data.size()) <= 0) {
return Status::Error("Cannot calculate decrypted length"); return Status::Error("Cannot calculate decrypted length");

View File

@ -6,9 +6,9 @@
// //
#pragma once #pragma once
#include "td/utils/buffer.h"
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include "td/utils/buffer.h"
#include "td/utils/Status.h" #include "td/utils/Status.h"
namespace td { namespace td {
@ -85,7 +85,7 @@ void hmac_sha256(Slice key, Slice message, MutableSlice dest);
// Interface may be improved // Interface may be improved
Result<BufferSlice> rsa_encrypt_pkcs1_oaep(Slice public_key, Slice data); Result<BufferSlice> rsa_encrypt_pkcs1_oaep(Slice public_key, Slice data);
Result<BufferSlice> rsa_decrypt_pkcs1_oaep(Slice public_key, Slice data); Result<BufferSlice> rsa_decrypt_pkcs1_oaep(Slice private_key, Slice data);
void init_openssl_threads(); void init_openssl_threads();
#endif #endif

View File

@ -29,20 +29,22 @@ TEST(SecureStorage, simple) {
BufferSlice value("Small tale about cucumbers"); BufferSlice value("Small tale about cucumbers");
auto value_secret = Secret::create_new(); auto value_secret = Secret::create_new();
auto value_view = BufferSliceDataView(value.copy()); {
BufferSlice prefix = gen_random_prefix(value_view.size()); auto value_view = BufferSliceDataView(value.copy());
auto prefix_view = BufferSliceDataView(std::move(prefix)); BufferSlice prefix = gen_random_prefix(value_view.size());
auto full_value_view = ConcatDataView(prefix_view, value_view); auto prefix_view = BufferSliceDataView(std::move(prefix));
auto hash = calc_value_hash(full_value_view).move_as_ok(); 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); 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(); 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())); 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 res = decryptor.append(encrypted_value.copy()).move_as_ok();
auto decrypted_hash = decryptor.finish().ok(); auto decrypted_hash = decryptor.finish().ok();
ASSERT_TRUE(decrypted_hash.as_slice() == hash.as_slice()); ASSERT_TRUE(decrypted_hash.as_slice() == hash.as_slice());
ASSERT_TRUE(res.as_slice() == value.as_slice()); ASSERT_TRUE(res.as_slice() == value.as_slice());
}
{ {
auto encrypted_value = encrypt_value(value_secret, value.as_slice()).move_as_ok(); auto encrypted_value = encrypt_value(value_secret, value.as_slice()).move_as_ok();