// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
+#include <array>
#include <openssl/evp.h>
#include "crypto_onwire.h"
#define dout_subsys ceph_subsys_ms
+namespace ceph::crypto::onwire {
+
+static constexpr const std::size_t AESGCM_KEY_LEN{16};
+static constexpr const std::size_t AESGCM_IV_LEN{12};
+static constexpr const std::size_t AESGCM_TAG_LEN{16};
+static constexpr const std::size_t AESGCM_BLOCK_LEN{16};
+
+struct nonce_t {
+ std::uint32_t random_seq;
+ std::uint64_t random_rest;
+} __attribute__((packed));
+static_assert(sizeof(nonce_t) == AESGCM_IV_LEN);
+
+using key_t = std::array<std::uint8_t, AESGCM_KEY_LEN>;
+
// http://www.mindspring.com/~dmcgrew/gcm-nist-6.pdf
// https://www.openssl.org/docs/man1.0.2/crypto/EVP_aes_128_gcm.html#GCM-mode
// https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption
// https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
class AES128GCM_OnWireTxHandler : public ceph::crypto::onwire::TxHandler {
- static constexpr const std::size_t AESGCM_KEY_LEN{16};
- static constexpr const std::size_t AESGCM_IV_LEN{12};
- static constexpr const std::size_t AESGCM_TAG_LEN{16};
- static constexpr const std::size_t AESGCM_BLOCK_LEN{16};
-
- using nonce_t = std::array<unsigned char, AESGCM_IV_LEN>;
-
CephContext* const cct;
std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)> ectx;
ceph::bufferlist buffer;
- // using GCC's "Tetra Integer" mode here
- ceph::uint128_t nonce;
+ nonce_t nonce;
+ static_assert(sizeof(nonce) == AESGCM_IV_LEN);
public:
AES128GCM_OnWireTxHandler(CephContext* const cct,
- const AuthConnectionMeta& auth_meta,
- const ceph::uint128_t& nonce)
+ const key_t& key,
+ const nonce_t& nonce)
: cct(cct),
ectx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free),
nonce(nonce) {
- ceph_assert_always(auth_meta.connection_secret.length() >= AESGCM_KEY_LEN);
ceph_assert_always(ectx);
+ ceph_assert_always(key.size() * CHAR_BIT == 128);
if (1 != EVP_EncryptInit_ex(ectx.get(), EVP_aes_128_gcm(),
nullptr, nullptr, nullptr)) {
}
if(1 != EVP_EncryptInit_ex(ectx.get(), nullptr, nullptr,
- reinterpret_cast<const unsigned char*>(auth_meta.connection_secret.c_str()),
- nullptr)) {
- //reinterpret_cast<const unsigned char*>(&nonce))) {
+ key.data(), nullptr)) {
throw std::runtime_error("EVP_EncryptInit_ex failed");
}
}
buffer.reserve(std::accumulate(std::begin(update_size_sequence),
std::end(update_size_sequence), AESGCM_TAG_LEN));
- // transplantate the nonce update management from OpenVPN's AES-GCM
- nonce += 1ULL << 32;
+ ++nonce.random_seq;
}
void AES128GCM_OnWireTxHandler::authenticated_encrypt_update(
return std::move(buffer);
}
-
// RX PART
class AES128GCM_OnWireRxHandler : public ceph::crypto::onwire::RxHandler {
- static constexpr const std::size_t AESGCM_KEY_LEN{16};
- static constexpr const std::size_t AESGCM_IV_LEN{12};
- static constexpr const std::size_t AESGCM_TAG_LEN{16};
- static constexpr const std::size_t AESGCM_BLOCK_LEN{16};
-
- using nonce_t = std::array<unsigned char, AESGCM_IV_LEN>;
-
CephContext* const cct;
std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)> ectx;
- // using GCC's "Tetra Integer" mode here
- ceph::uint128_t nonce;
+ nonce_t nonce;
+ static_assert(sizeof(nonce) == AESGCM_IV_LEN);
public:
AES128GCM_OnWireRxHandler(CephContext* const cct,
- const AuthConnectionMeta& auth_meta,
- const ceph::uint128_t& nonce)
+ const key_t& key,
+ const nonce_t& nonce)
: cct(cct),
ectx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free),
nonce(nonce)
{
- ceph_assert_always(auth_meta.connection_secret.length() >= AESGCM_KEY_LEN);
ceph_assert_always(ectx);
+ ceph_assert_always(key.size() * CHAR_BIT == 128);
if (1 != EVP_DecryptInit_ex(ectx.get(), EVP_aes_128_gcm(),
nullptr, nullptr, nullptr)) {
}
if(1 != EVP_DecryptInit_ex(ectx.get(), nullptr, nullptr,
- reinterpret_cast<const unsigned char*>(auth_meta.connection_secret.c_str()),
- nullptr)) {
+ key.data(), nullptr)) {
throw std::runtime_error("EVP_DecryptInit_ex failed");
}
}
reinterpret_cast<const unsigned char*>(&nonce))) {
throw std::runtime_error("EVP_DecryptInit_ex failed");
}
- nonce += 1ULL << 32;
+ ++nonce.random_seq;
}
ceph::bufferlist AES128GCM_OnWireRxHandler::authenticated_decrypt_update(
bool crossed)
{
if (auth_meta.is_mode_secure()) {
- // CLEANME, CLEANME CLEANME
- ceph_assert_always(
- auth_meta.connection_secret.length() >= 16 + 2*sizeof(ceph::uint128_t));
+ ceph_assert_always(auth_meta.connection_secret.length() >= \
+ sizeof(key_t) + 2 * sizeof(nonce_t));
+ const char* secbuf = auth_meta.connection_secret.c_str();
+
+ key_t key;
+ {
+ ::memcpy(key.data(), secbuf, sizeof(key));
+ secbuf += sizeof(key);
+ }
- ceph::uint128_t rx_nonce;
- ::memcpy(&rx_nonce, auth_meta.connection_secret.c_str() + 16, sizeof(rx_nonce));
+ nonce_t rx_nonce;
+ {
+ ::memcpy(&rx_nonce, secbuf, sizeof(rx_nonce));
+ secbuf += sizeof(rx_nonce);
+ }
+
+ nonce_t tx_nonce;
+ {
+ ::memcpy(&tx_nonce, secbuf, sizeof(tx_nonce));
+ secbuf += sizeof(tx_nonce);
+ }
- ceph::uint128_t tx_nonce;
- ::memcpy(&tx_nonce, auth_meta.connection_secret.c_str() + 16 + sizeof(rx_nonce),
- sizeof(tx_nonce));
return {
std::make_unique<AES128GCM_OnWireRxHandler>(
- cct, auth_meta, crossed ? tx_nonce : rx_nonce),
+ cct, key, crossed ? tx_nonce : rx_nonce),
std::make_unique<AES128GCM_OnWireTxHandler>(
- cct, auth_meta, crossed ? rx_nonce : tx_nonce)
+ cct, key, crossed ? rx_nonce : tx_nonce)
};
} else {
return { nullptr, nullptr };
}
}
+
+} // namespace ceph::crypto::onwire