mirror of
https://github.com/LizardByte/Sunshine.git
synced 2025-02-21 00:39:59 +00:00
Don't keep reinitializing the cipher context for gcm
This commit is contained in:
parent
a587338701
commit
25aa8b41a5
@ -54,71 +54,82 @@ const char *cert_chain_t::verify(x509_t::element_type *cert) {
|
||||
return X509_verify_cert_error_string(err_code);
|
||||
}
|
||||
|
||||
cipher_t::cipher_t(const crypto::aes_t &key) : ctx { EVP_CIPHER_CTX_new() }, key { key }, padding { true } {}
|
||||
int cipher_t::decrypt(const std::string_view &cipher, std::vector<std::uint8_t> &plaintext) {
|
||||
int len;
|
||||
|
||||
auto fg = util::fail_guard([this]() {
|
||||
EVP_CIPHER_CTX_reset(ctx.get());
|
||||
});
|
||||
|
||||
// Gen 7 servers use 128-bit AES ECB
|
||||
if(EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_ecb(), nullptr, key.data(), nullptr) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX_set_padding(ctx.get(), padding);
|
||||
|
||||
plaintext.resize((cipher.size() + 15) / 16 * 16);
|
||||
auto size = (int)plaintext.size();
|
||||
// Encrypt into the caller's buffer, leaving room for the auth tag to be prepended
|
||||
if(EVP_DecryptUpdate(ctx.get(), plaintext.data(), &size, (const std::uint8_t *)cipher.data(), cipher.size()) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(EVP_DecryptFinal_ex(ctx.get(), plaintext.data(), &len) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
plaintext.resize(len + size);
|
||||
return 0;
|
||||
namespace cipher {
|
||||
gcm_t::gcm_t(const crypto::aes_t &key, const crypto::aes_t &iv, bool padding)
|
||||
: cipher_t { nullptr, nullptr, key, padding } {
|
||||
this->iv = iv;
|
||||
}
|
||||
|
||||
int cipher_t::decrypt_gcm(aes_t &iv, const std::string_view &tagged_cipher,
|
||||
std::vector<std::uint8_t> &plaintext) {
|
||||
auto cipher = tagged_cipher.substr(16);
|
||||
auto tag = tagged_cipher.substr(0, 16);
|
||||
static int init_decrypt_gcm(cipher_ctx_t &ctx, aes_t *key, aes_t *iv, bool padding) {
|
||||
ctx.reset(EVP_CIPHER_CTX_new());
|
||||
|
||||
auto fg = util::fail_guard([this]() {
|
||||
EVP_CIPHER_CTX_reset(ctx.get());
|
||||
});
|
||||
if(!ctx) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_gcm(), nullptr, nullptr, nullptr) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, iv.size(), nullptr) != 1) {
|
||||
if(EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, iv->size(), nullptr) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(EVP_DecryptInit_ex(ctx.get(), nullptr, nullptr, key.data(), iv.data()) != 1) {
|
||||
if(EVP_DecryptInit_ex(ctx.get(), nullptr, nullptr, key->data(), iv->data()) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX_set_padding(ctx.get(), padding);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_encrypt_gcm(cipher_ctx_t &ctx, aes_t *key, aes_t *iv, bool padding) {
|
||||
ctx.reset(EVP_CIPHER_CTX_new());
|
||||
|
||||
// Gen 7 servers use 128-bit AES ECB
|
||||
if(EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_gcm(), nullptr, nullptr, nullptr) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, iv->size(), nullptr) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(EVP_EncryptInit_ex(ctx.get(), nullptr, nullptr, key->data(), iv->data()) != 1) {
|
||||
return -1;
|
||||
}
|
||||
EVP_CIPHER_CTX_set_padding(ctx.get(), padding);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gcm_t::decrypt(const std::string_view &tagged_cipher, std::vector<std::uint8_t> &plaintext) {
|
||||
if(!decrypt_ctx && init_decrypt_gcm(decrypt_ctx, &key, &iv, padding)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Calling with cipher == nullptr results in a parameter change
|
||||
// without requiring a reallocation of the internal cipher ctx.
|
||||
if(EVP_DecryptInit_ex(decrypt_ctx.get(), nullptr, nullptr, nullptr, iv.data()) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto cipher = tagged_cipher.substr(16);
|
||||
auto tag = tagged_cipher.substr(0, 16);
|
||||
|
||||
plaintext.resize((cipher.size() + 15) / 16 * 16);
|
||||
|
||||
int size;
|
||||
if(EVP_DecryptUpdate(ctx.get(), plaintext.data(), &size, (const std::uint8_t *)cipher.data(), cipher.size()) != 1) {
|
||||
if(EVP_DecryptUpdate(decrypt_ctx.get(), plaintext.data(), &size, (const std::uint8_t *)cipher.data(), cipher.size()) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, tag.size(), const_cast<char *>(tag.data())) != 1) {
|
||||
if(EVP_CIPHER_CTX_ctrl(decrypt_ctx.get(), EVP_CTRL_GCM_SET_TAG, tag.size(), const_cast<char *>(tag.data())) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int len = size;
|
||||
if(EVP_DecryptFinal_ex(ctx.get(), plaintext.data() + size, &len) != 1) {
|
||||
if(EVP_DecryptFinal_ex(decrypt_ctx.get(), plaintext.data() + size, &len) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -126,28 +137,28 @@ int cipher_t::decrypt_gcm(aes_t &iv, const std::string_view &tagged_cipher,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cipher_t::encrypt(const std::string_view &plaintext, std::vector<std::uint8_t> &cipher) {
|
||||
int len;
|
||||
|
||||
auto fg = util::fail_guard([this]() {
|
||||
EVP_CIPHER_CTX_reset(ctx.get());
|
||||
});
|
||||
|
||||
// Gen 7 servers use 128-bit AES ECB
|
||||
if(EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_ecb(), nullptr, key.data(), nullptr) != 1) {
|
||||
int gcm_t::encrypt(const std::string_view &plaintext, std::vector<std::uint8_t> &cipher) {
|
||||
if(!encrypt_ctx && init_encrypt_gcm(encrypt_ctx, &key, &iv, padding)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX_set_padding(ctx.get(), padding);
|
||||
// Calling with cipher == nullptr results in a parameter change
|
||||
// without requiring a reallocation of the internal cipher ctx.
|
||||
if(EVP_EncryptInit_ex(encrypt_ctx.get(), nullptr, nullptr, nullptr, iv.data()) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int len;
|
||||
|
||||
cipher.resize((plaintext.size() + 15) / 16 * 16);
|
||||
auto size = (int)cipher.size();
|
||||
|
||||
// Encrypt into the caller's buffer
|
||||
if(EVP_EncryptUpdate(ctx.get(), cipher.data(), &size, (const std::uint8_t *)plaintext.data(), plaintext.size()) != 1) {
|
||||
if(EVP_EncryptUpdate(encrypt_ctx.get(), cipher.data(), &size, (const std::uint8_t *)plaintext.data(), plaintext.size()) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(EVP_EncryptFinal_ex(ctx.get(), cipher.data() + size, &len) != 1) {
|
||||
if(EVP_EncryptFinal_ex(encrypt_ctx.get(), cipher.data() + size, &len) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -155,6 +166,70 @@ int cipher_t::encrypt(const std::string_view &plaintext, std::vector<std::uint8_
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ecb_t::decrypt(const std::string_view &cipher, std::vector<std::uint8_t> &plaintext) {
|
||||
int len;
|
||||
|
||||
auto fg = util::fail_guard([this]() {
|
||||
EVP_CIPHER_CTX_reset(decrypt_ctx.get());
|
||||
});
|
||||
|
||||
// Gen 7 servers use 128-bit AES ECB
|
||||
if(EVP_DecryptInit_ex(decrypt_ctx.get(), EVP_aes_128_ecb(), nullptr, key.data(), nullptr) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX_set_padding(decrypt_ctx.get(), padding);
|
||||
|
||||
plaintext.resize((cipher.size() + 15) / 16 * 16);
|
||||
auto size = (int)plaintext.size();
|
||||
// Decrypt into the caller's buffer, leaving room for the auth tag to be prepended
|
||||
if(EVP_DecryptUpdate(decrypt_ctx.get(), plaintext.data(), &size, (const std::uint8_t *)cipher.data(), cipher.size()) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(EVP_DecryptFinal_ex(decrypt_ctx.get(), plaintext.data(), &len) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
plaintext.resize(len + size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ecb_t::encrypt(const std::string_view &plaintext, std::vector<std::uint8_t> &cipher) {
|
||||
auto fg = util::fail_guard([this]() {
|
||||
EVP_CIPHER_CTX_reset(encrypt_ctx.get());
|
||||
});
|
||||
|
||||
// Gen 7 servers use 128-bit AES ECB
|
||||
if(EVP_EncryptInit_ex(encrypt_ctx.get(), EVP_aes_128_ecb(), nullptr, key.data(), nullptr) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX_set_padding(encrypt_ctx.get(), padding);
|
||||
|
||||
int len;
|
||||
|
||||
cipher.resize((plaintext.size() + 15) / 16 * 16);
|
||||
auto size = (int)cipher.size();
|
||||
|
||||
// Encrypt into the caller's buffer
|
||||
if(EVP_EncryptUpdate(encrypt_ctx.get(), cipher.data(), &size, (const std::uint8_t *)plaintext.data(), plaintext.size()) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(EVP_EncryptFinal_ex(encrypt_ctx.get(), cipher.data() + size, &len) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cipher.resize(len + size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ecb_t::ecb_t(const aes_t &key, bool padding)
|
||||
: cipher_t { EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_new(), key, padding } {}
|
||||
|
||||
} // namespace cipher
|
||||
|
||||
aes_t gen_aes_key(const std::array<uint8_t, 16> &salt, const std::string_view &pin) {
|
||||
aes_t key;
|
||||
|
||||
|
@ -66,24 +66,46 @@ private:
|
||||
x509_store_ctx_t _cert_ctx;
|
||||
};
|
||||
|
||||
namespace cipher {
|
||||
|
||||
class cipher_t {
|
||||
public:
|
||||
cipher_t(const aes_t &key);
|
||||
cipher_t(cipher_t &&) noexcept = default;
|
||||
cipher_t &operator=(cipher_t &&) noexcept = default;
|
||||
cipher_ctx_t decrypt_ctx;
|
||||
cipher_ctx_t encrypt_ctx;
|
||||
|
||||
int encrypt(const std::string_view &plaintext, std::vector<std::uint8_t> &cipher);
|
||||
|
||||
int decrypt_gcm(aes_t &iv, const std::string_view &cipher, std::vector<std::uint8_t> &plaintext);
|
||||
int decrypt(const std::string_view &cipher, std::vector<std::uint8_t> &plaintext);
|
||||
|
||||
private:
|
||||
cipher_ctx_t ctx;
|
||||
aes_t key;
|
||||
|
||||
public:
|
||||
bool padding;
|
||||
};
|
||||
|
||||
class ecb_t : public cipher_t {
|
||||
public:
|
||||
ecb_t() = default;
|
||||
ecb_t(ecb_t &&) noexcept = default;
|
||||
ecb_t &operator=(ecb_t &&) noexcept = default;
|
||||
|
||||
ecb_t(const aes_t &key, bool padding = true);
|
||||
|
||||
int encrypt(const std::string_view &plaintext, std::vector<std::uint8_t> &cipher);
|
||||
int decrypt(const std::string_view &cipher, std::vector<std::uint8_t> &plaintext);
|
||||
};
|
||||
|
||||
class gcm_t : public cipher_t {
|
||||
public:
|
||||
gcm_t() = default;
|
||||
gcm_t(gcm_t &&) noexcept = default;
|
||||
gcm_t &operator=(gcm_t &&) noexcept = default;
|
||||
|
||||
gcm_t(const crypto::aes_t &key, const crypto::aes_t &iv, bool padding = true);
|
||||
|
||||
int encrypt(const std::string_view &plaintext, std::vector<std::uint8_t> &cipher);
|
||||
int decrypt(const std::string_view &cipher, std::vector<std::uint8_t> &plaintext);
|
||||
|
||||
aes_t &get_iv() { return iv; }
|
||||
|
||||
aes_t iv;
|
||||
};
|
||||
} // namespace cipher
|
||||
} // namespace crypto
|
||||
|
||||
#endif //SUNSHINE_CRYPTO_H
|
||||
|
@ -222,8 +222,7 @@ void serverchallengeresp(pair_session_t &sess, pt::ptree &tree, const args_t &ar
|
||||
auto encrypted_response = util::from_hex_vec(args.at("serverchallengeresp"s), true);
|
||||
|
||||
std::vector<uint8_t> decrypted;
|
||||
crypto::cipher_t cipher(*sess.cipher_key);
|
||||
cipher.padding = false;
|
||||
crypto::cipher::ecb_t cipher(*sess.cipher_key, false);
|
||||
|
||||
cipher.decrypt(encrypted_response, decrypted);
|
||||
|
||||
@ -242,8 +241,7 @@ void serverchallengeresp(pair_session_t &sess, pt::ptree &tree, const args_t &ar
|
||||
void clientchallenge(pair_session_t &sess, pt::ptree &tree, const args_t &args) {
|
||||
auto challenge = util::from_hex_vec(args.at("clientchallenge"s), true);
|
||||
|
||||
crypto::cipher_t cipher(*sess.cipher_key);
|
||||
cipher.padding = false;
|
||||
crypto::cipher::ecb_t cipher(*sess.cipher_key, false);
|
||||
|
||||
std::vector<uint8_t> decrypted;
|
||||
cipher.decrypt(challenge, decrypted);
|
||||
|
@ -224,12 +224,11 @@ struct session_t {
|
||||
} audio;
|
||||
|
||||
struct {
|
||||
crypto::cipher::gcm_t cipher;
|
||||
|
||||
net::peer_t peer;
|
||||
} control;
|
||||
|
||||
crypto::aes_t gcm_key;
|
||||
crypto::aes_t iv;
|
||||
|
||||
safe::mail_raw_t::event_t<bool> shutdown_event;
|
||||
safe::signal_t controlEnd;
|
||||
|
||||
@ -495,11 +494,10 @@ void controlBroadcastThread(control_server_t *server) {
|
||||
auto tagged_cipher_length = util::endian::big(*(int32_t *)payload.data());
|
||||
std::string_view tagged_cipher { payload.data() + sizeof(tagged_cipher_length), (size_t)tagged_cipher_length };
|
||||
|
||||
crypto::cipher_t cipher { session->gcm_key };
|
||||
cipher.padding = false;
|
||||
|
||||
std::vector<uint8_t> plaintext;
|
||||
if(cipher.decrypt_gcm(session->iv, tagged_cipher, plaintext)) {
|
||||
|
||||
auto &cipher = session->control.cipher;
|
||||
if(cipher.decrypt(tagged_cipher, plaintext)) {
|
||||
// something went wrong :(
|
||||
|
||||
BOOST_LOG(error) << "Failed to verify tag"sv;
|
||||
@ -508,8 +506,8 @@ void controlBroadcastThread(control_server_t *server) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(tagged_cipher_length >= 16 + session->iv.size()) {
|
||||
std::copy(payload.end() - 16, payload.end(), std::begin(session->iv));
|
||||
if(tagged_cipher_length >= 16 + sizeof(crypto::aes_t)) {
|
||||
std::copy(payload.end() - 16, payload.end(), std::begin(cipher.get_iv()));
|
||||
}
|
||||
|
||||
input::print(plaintext.data());
|
||||
@ -532,14 +530,13 @@ void controlBroadcastThread(control_server_t *server) {
|
||||
auto tagged_cipher_length = length - 4;
|
||||
std::string_view tagged_cipher { (char *)header->payload(), (size_t)tagged_cipher_length };
|
||||
|
||||
auto &cipher = session->control.cipher;
|
||||
crypto::aes_t iv {};
|
||||
iv[0] = (char)seq;
|
||||
|
||||
crypto::cipher_t cipher { session->gcm_key };
|
||||
cipher.padding = false;
|
||||
iv[0] = (char)seq;
|
||||
cipher.get_iv() = iv;
|
||||
|
||||
std::vector<uint8_t> plaintext;
|
||||
if(cipher.decrypt_gcm(iv, tagged_cipher, plaintext)) {
|
||||
if(cipher.decrypt(tagged_cipher, plaintext)) {
|
||||
// something went wrong :(
|
||||
|
||||
BOOST_LOG(error) << "Failed to verify tag"sv;
|
||||
@ -1109,9 +1106,11 @@ std::shared_ptr<session_t> alloc(config_t &config, crypto::aes_t &gcm_key, crypt
|
||||
|
||||
session->shutdown_event = mail->event<bool>(mail::shutdown);
|
||||
|
||||
session->config = config;
|
||||
session->gcm_key = gcm_key;
|
||||
session->iv = iv;
|
||||
session->config = config;
|
||||
|
||||
session->control.cipher = crypto::cipher::gcm_t {
|
||||
gcm_key, iv, false
|
||||
};
|
||||
|
||||
session->video.idr_events = mail->event<video::idr_t>(mail::idr);
|
||||
session->video.lowseq = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user