Loading src/crypto/aes.cpp +299 −542 File changed.Preview size limit exceeded, changes collapsed. Show changes src/crypto/aes.h +37 −54 Original line number Diff line number Diff line Loading @@ -26,86 +26,69 @@ *******************************************************************************/ #pragma once #include <vector> #include <stdexcept> #include <cstdint> #include <stdexcept> namespace netplus { // Type aliases for clarity (AES operates on 128-bit blocks/keys) // Keep your existing aliases using block128 = std::vector<uint8_t>; using key128 = std::vector<uint8_t>; // --- Global AES Tables (Defined in the header for easy access) --- // Note: You must fill these arrays with the correct 256-byte values. // Global tables (provided in aes.cpp) extern const uint8_t S_BOX[256]; extern const uint8_t INV_S_BOX[256]; extern const uint8_t RCON[10]; // Rcon values for key expansion (only 10 needed for AES-128) extern const uint8_t RCON[10]; class aes { private: // Stores the expanded round keys (11 keys * 16 bytes = 176 bytes for AES-128) std::vector<block128> m_roundKeys; // --- Core AES Functions --- // Key Expansion and related helpers // ---------------------------------------------------------------- // OPTIMIZED ROUND KEY STORAGE: // 11 round keys * 16 bytes = 176 bytes (AES-128) // Avoids 11 heap allocations that vector<block128> causes. // ---------------------------------------------------------------- std::vector<uint8_t> m_roundKeyBytes; // size = 176 // access helper: returns pointer to 16-byte round key inline const uint8_t* rk(int round) const { return &m_roundKeyBytes[size_t(round) * 16]; } // --- Key Expansion + helpers --- void keyExpansion(const key128& key); static uint32_t subWord(uint32_t word); static uint32_t rotWord(uint32_t word); // Round operations void subBytes(block128& state); void shiftRows(block128& state); void mixColumns(block128& state); void addRoundKey(block128& state, const block128& roundKey); // --- Round ops --- static void subBytes(uint8_t* state); static void shiftRows(uint8_t* state); static void mixColumns(uint8_t* state); static void addRoundKey(uint8_t* state, const uint8_t* roundKey); // Inverse Round operations void invSubBytes(block128& state); void invShiftRows(block128& state); void invMixColumns(block128& state); // --- Inverse ops --- static void invSubBytes(uint8_t* state); static void invShiftRows(uint8_t* state); static void invMixColumns(uint8_t* state); // Helper function for Galois Field multiplication in mixColumns // GF multiplication static uint8_t gmul(uint8_t a, uint8_t b); friend void aes_self_check(); public: /** * @brief Constructor for the aes class (AES-128). Performs key expansion. * @param key The 128-bit master key (16 bytes). */ explicit aes(const key128& key); /** * @brief Encrypts a 128-bit block of plaintext. * @param plaintext The 16-byte input block. * @return The 16-byte ciphertext block. */ // NOTE: Keeping your vector-based API, but avoids realloc/extra copies. block128 encrypt(const block128& plaintext); /** * @brief Decrypts a 128-bit block of ciphertext. * @param ciphertext The 16-byte input block. * @return The 16-byte plaintext block. */ block128 decrypt(const block128& ciphertext); /** * encryptCBC * @param plaintext: The raw data to encrypt * @param iv: 16-byte Initialization Vector * @return: Encrypted ciphertext (length will be multiple of 16) */ std::vector<uint8_t> encryptCBC(const std::vector<uint8_t>& plaintext, const std::vector<uint8_t>& iv); /** * decryptCBC * @param ciphertext: The encrypted data * @param iv: 16-byte Initialization Vector * @return: Decrypted and unpadded plaintext */ std::vector<uint8_t> decryptCBC(const std::vector<uint8_t>& ciphertext, const std::vector<uint8_t>& iv); // TLS CBC helpers std::vector<uint8_t> encryptCBC(const std::vector<uint8_t>& plaintext, const std::vector<uint8_t>& iv); std::vector<uint8_t> decryptCBC(const std::vector<uint8_t>& ciphertext, const std::vector<uint8_t>& iv); }; } // namespace netplus src/crypto/rsa.cpp +93 −23 Original line number Diff line number Diff line Loading @@ -27,9 +27,9 @@ #include <iomanip> #include <algorithm> #include <stdexcept> #include <random> #include <sstream> #include "random.h" #include "rsa.h" namespace netplus { Loading Loading @@ -432,19 +432,26 @@ namespace netplus { } void netplus::rsa::generateSecureRandom(bigInt& n, size_t bits) { size_t words = (bits + 31) / 32; n.reserve(words); std::random_device rd; for (size_t i = 0; i < words; ++i) { n.data[i] = rd(); } n.reserve(words); n.used = words; // Ensure the top bit is set for the requested bit-length fillRandomBytes(reinterpret_cast<uint8_t*>(n.data.get()), words * sizeof(uint32_t)); n.data[words - 1] |= (1U << ((bits - 1) % 32)); uint32_t excess = (uint32_t)(words * 32 - bits); if (excess > 0) { uint32_t mask = 0xFFFFFFFFu >> excess; n.data[words - 1] &= mask; n.data[words - 1] |= (1U << ((bits - 1) % 32)); // Ensure it's odd for primality testing n.data[0] |= 1; } n.data[0] |= 1U; } rsa::bigInt rsa::gcd(bigInt a, bigInt b) { while (!b.isZero()) { Loading Loading @@ -507,17 +514,79 @@ namespace netplus { } bool rsa::isProbablyPrime(const bigInt& n, int k) { // Correctly initialize constants using the (value, capacity) constructor bigInt one(1U, 1); bigInt two(2U, 1); bigInt one(1U, n.capacity); bigInt two(2U, n.capacity); bigInt three(3U, n.capacity); // nm1 = n - 1 bigInt nm1(n.capacity); subtract(n, one, nm1); // Initial checks // trivial checks if (compare(n, one) <= 0) return false; if (n.isEven()) return compare(n, two) == 0; // Find d and s such that n - 1 = 2^s * d // ------------------------------------------------------------ // Lambda: randomBigIntBits(out,bits) // ------------------------------------------------------------ auto randomBigIntBits = [&](bigInt& out, size_t bits) { size_t words = (bits + 31) / 32; out.reserve(words); out.used = words; // fill random words for (size_t i = 0; i < words; ++i) { fillRandomBytes(reinterpret_cast<uint8_t*>(&out.data[i]), sizeof(uint32_t)); } // mask unused high bits size_t extra = words * 32 - bits; if (extra > 0) { uint32_t mask = 0xFFFFFFFFu >> extra; out.data[words - 1] &= mask; } // optional normalize if you have it: // out.normalize(); }; // ------------------------------------------------------------ // Lambda: randomBelow(limit) -> uniform r in [0..limit-1] // ------------------------------------------------------------ auto randomBelow = [&](const bigInt& limit) -> bigInt { size_t bits = limit.bitLength(); bigInt r(limit.capacity); for (;;) { randomBigIntBits(r, bits); if (compare(r, limit) < 0) return r; } }; // ------------------------------------------------------------ // Lambda: randomWitnessA(n) -> uniform a in [2..n-2] // ------------------------------------------------------------ auto randomWitnessA = [&]() -> bigInt { // nMinusThree = n - 3 bigInt nMinusThree(n.capacity); subtract(n, three, nMinusThree); // n-3 // r ∈ [0..n-4] bigInt r = randomBelow(nMinusThree); // a = r + 2 => [2..n-2] bigInt a(n.capacity); add(r, two, a); return a; }; // ------------------------------------------------------------ // factor n-1 = 2^s * d // ------------------------------------------------------------ bigInt d = nm1; size_t s = 0; while (d.isEven()) { Loading @@ -525,32 +594,33 @@ namespace netplus { s++; } // ------------------------------------------------------------ // Miller-Rabin rounds std::random_device rd; std::mt19937 gen(rd()); // ------------------------------------------------------------ for (int i = 0; i < k; i++) { // Simplified witness: for production RSA, 'a' should be a random // value in range [2, n-2]. For now, using small primes as witnesses: uint32_t witness_val = (i == 0) ? 2 : (i == 1 ? 3 : 5 + (i * 2)); bigInt a(witness_val, n.capacity); bigInt a = randomWitnessA(); bigInt x = modPow(a, d, n); // if x == 1 or x == n - 1 // x == 1 or x == n-1 if ((x.used == 1 && x.data[0] == 1) || compare(x, nm1) == 0) continue; bool composite = true; for (size_t r = 1; r < s; r++) { x = modPow(x, two, n); // Square: x = x^2 % n x = modPow(x, two, n); if (compare(x, nm1) == 0) { composite = false; break; } } if (composite) return false; } return true; } Loading src/event/epoll.cpp +49 −46 Original line number Diff line number Diff line Loading @@ -265,67 +265,72 @@ namespace netplus { if (!c->csock) return; try { // ---------------------------- // 1) TLS handshake stage // ---------------------------- if (!c->csock->getHandshakeDone()) { // Peer already closed? if (events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR)) { rearm.disarm(); CloseEventHandler(fd, tid, args); return; } // ------------------------------------------------- // 1) TLS handshake // ------------------------------------------------- if (!c->csock->getHandshakeDone()) { c->csock->handshake_after_accept(); // try flush once if something queued if (c->csock->hasPendingWrite()) { try { c->csock->flush_out(); } catch (NetException& e) { if (e.getErrorType() != NetException::Note) throw; if (e.getErrorType() == NetException::Note) return; // wait EPOLLOUT throw; } } // if still not done, stop here // still not done -> wait for next IO event if (!c->csock->getHandshakeDone()) return; } // ---------------------------- // 2) EPOLLIN: receive application data // ---------------------------- // ------------------------------------------------- // 2) EPOLLIN: receive one chunk // ------------------------------------------------- if (events & EPOLLIN) { bool got = false; for (;;) { buffer buf(BLOCKSIZE); size_t rcv = 0; try { rcv = c->csock->recvData(buf, 0); } catch (NetException& e) { if (e.getErrorType() == NetException::Note) break; if (e.getErrorType() == NetException::Note) { // nothing to read right now rcv = 0; } else { throw; } } if (rcv == 0) { // If peer closed => recvData must return 0. // Note case already handled. // In TLS, alert/EOF => close. rearm.disarm(); CloseEventHandler(fd, tid, args); return; } c->RecvData.append(buf.data.buf, rcv); got = true; } if (got && !c->RecvData.empty()) { evconnection->RequestEvent(*c, tid, args); } } // ---------------------------- // 3) EPOLLOUT: flush + send queued responses // ---------------------------- // ------------------------------------------------- // 3) EPOLLOUT: flush + send one chunk // ------------------------------------------------- if (events & EPOLLOUT) { // always flush TLS pending first // flush pending TLS output if (c->csock->hasPendingWrite()) { try { c->csock->flush_out(); Loading @@ -336,8 +341,8 @@ namespace netplus { } } // now send queued app data while (!c->SendData.empty()) { // send exactly one chunk from SendData if (!c->SendData.empty()) { size_t sendlen = std::min((size_t)BLOCKSIZE, c->SendData.size()); buffer out(c->SendData.data(), sendlen); Loading @@ -351,25 +356,23 @@ namespace netplus { } catch (NetException& e) { if (e.getErrorType() == NetException::Note) break; return; throw; } if (consumed == 0) break; c->SendData.erase(c->SendData.begin(), c->SendData.begin() + consumed); if (consumed > 0) { c->SendData.erase(c->SendData.begin(), c->SendData.begin() + consumed); } } // if nothing pending, signal response done if (c->SendData.empty() && !c->csock->hasPendingWrite()) { evconnection->ResponseEvent(*c, tid, args); } } } catch (NetException& e) { if (e.getErrorType() == NetException::Note) return; if (e.getErrorType() == NetException::Note) return; rearm.disarm(); CloseEventHandler(fd, tid, args); Loading src/random.h +1 −2 Original line number Diff line number Diff line Loading @@ -10,6 +10,5 @@ namespace netplus { inline void fillRandom(std::vector<uint8_t>& v) { if (!v.empty()) fillRandomBytes(v.data(), v.size()); } } }; Loading
src/crypto/aes.cpp +299 −542 File changed.Preview size limit exceeded, changes collapsed. Show changes
src/crypto/aes.h +37 −54 Original line number Diff line number Diff line Loading @@ -26,86 +26,69 @@ *******************************************************************************/ #pragma once #include <vector> #include <stdexcept> #include <cstdint> #include <stdexcept> namespace netplus { // Type aliases for clarity (AES operates on 128-bit blocks/keys) // Keep your existing aliases using block128 = std::vector<uint8_t>; using key128 = std::vector<uint8_t>; // --- Global AES Tables (Defined in the header for easy access) --- // Note: You must fill these arrays with the correct 256-byte values. // Global tables (provided in aes.cpp) extern const uint8_t S_BOX[256]; extern const uint8_t INV_S_BOX[256]; extern const uint8_t RCON[10]; // Rcon values for key expansion (only 10 needed for AES-128) extern const uint8_t RCON[10]; class aes { private: // Stores the expanded round keys (11 keys * 16 bytes = 176 bytes for AES-128) std::vector<block128> m_roundKeys; // --- Core AES Functions --- // Key Expansion and related helpers // ---------------------------------------------------------------- // OPTIMIZED ROUND KEY STORAGE: // 11 round keys * 16 bytes = 176 bytes (AES-128) // Avoids 11 heap allocations that vector<block128> causes. // ---------------------------------------------------------------- std::vector<uint8_t> m_roundKeyBytes; // size = 176 // access helper: returns pointer to 16-byte round key inline const uint8_t* rk(int round) const { return &m_roundKeyBytes[size_t(round) * 16]; } // --- Key Expansion + helpers --- void keyExpansion(const key128& key); static uint32_t subWord(uint32_t word); static uint32_t rotWord(uint32_t word); // Round operations void subBytes(block128& state); void shiftRows(block128& state); void mixColumns(block128& state); void addRoundKey(block128& state, const block128& roundKey); // --- Round ops --- static void subBytes(uint8_t* state); static void shiftRows(uint8_t* state); static void mixColumns(uint8_t* state); static void addRoundKey(uint8_t* state, const uint8_t* roundKey); // Inverse Round operations void invSubBytes(block128& state); void invShiftRows(block128& state); void invMixColumns(block128& state); // --- Inverse ops --- static void invSubBytes(uint8_t* state); static void invShiftRows(uint8_t* state); static void invMixColumns(uint8_t* state); // Helper function for Galois Field multiplication in mixColumns // GF multiplication static uint8_t gmul(uint8_t a, uint8_t b); friend void aes_self_check(); public: /** * @brief Constructor for the aes class (AES-128). Performs key expansion. * @param key The 128-bit master key (16 bytes). */ explicit aes(const key128& key); /** * @brief Encrypts a 128-bit block of plaintext. * @param plaintext The 16-byte input block. * @return The 16-byte ciphertext block. */ // NOTE: Keeping your vector-based API, but avoids realloc/extra copies. block128 encrypt(const block128& plaintext); /** * @brief Decrypts a 128-bit block of ciphertext. * @param ciphertext The 16-byte input block. * @return The 16-byte plaintext block. */ block128 decrypt(const block128& ciphertext); /** * encryptCBC * @param plaintext: The raw data to encrypt * @param iv: 16-byte Initialization Vector * @return: Encrypted ciphertext (length will be multiple of 16) */ std::vector<uint8_t> encryptCBC(const std::vector<uint8_t>& plaintext, const std::vector<uint8_t>& iv); /** * decryptCBC * @param ciphertext: The encrypted data * @param iv: 16-byte Initialization Vector * @return: Decrypted and unpadded plaintext */ std::vector<uint8_t> decryptCBC(const std::vector<uint8_t>& ciphertext, const std::vector<uint8_t>& iv); // TLS CBC helpers std::vector<uint8_t> encryptCBC(const std::vector<uint8_t>& plaintext, const std::vector<uint8_t>& iv); std::vector<uint8_t> decryptCBC(const std::vector<uint8_t>& ciphertext, const std::vector<uint8_t>& iv); }; } // namespace netplus
src/crypto/rsa.cpp +93 −23 Original line number Diff line number Diff line Loading @@ -27,9 +27,9 @@ #include <iomanip> #include <algorithm> #include <stdexcept> #include <random> #include <sstream> #include "random.h" #include "rsa.h" namespace netplus { Loading Loading @@ -432,19 +432,26 @@ namespace netplus { } void netplus::rsa::generateSecureRandom(bigInt& n, size_t bits) { size_t words = (bits + 31) / 32; n.reserve(words); std::random_device rd; for (size_t i = 0; i < words; ++i) { n.data[i] = rd(); } n.reserve(words); n.used = words; // Ensure the top bit is set for the requested bit-length fillRandomBytes(reinterpret_cast<uint8_t*>(n.data.get()), words * sizeof(uint32_t)); n.data[words - 1] |= (1U << ((bits - 1) % 32)); uint32_t excess = (uint32_t)(words * 32 - bits); if (excess > 0) { uint32_t mask = 0xFFFFFFFFu >> excess; n.data[words - 1] &= mask; n.data[words - 1] |= (1U << ((bits - 1) % 32)); // Ensure it's odd for primality testing n.data[0] |= 1; } n.data[0] |= 1U; } rsa::bigInt rsa::gcd(bigInt a, bigInt b) { while (!b.isZero()) { Loading Loading @@ -507,17 +514,79 @@ namespace netplus { } bool rsa::isProbablyPrime(const bigInt& n, int k) { // Correctly initialize constants using the (value, capacity) constructor bigInt one(1U, 1); bigInt two(2U, 1); bigInt one(1U, n.capacity); bigInt two(2U, n.capacity); bigInt three(3U, n.capacity); // nm1 = n - 1 bigInt nm1(n.capacity); subtract(n, one, nm1); // Initial checks // trivial checks if (compare(n, one) <= 0) return false; if (n.isEven()) return compare(n, two) == 0; // Find d and s such that n - 1 = 2^s * d // ------------------------------------------------------------ // Lambda: randomBigIntBits(out,bits) // ------------------------------------------------------------ auto randomBigIntBits = [&](bigInt& out, size_t bits) { size_t words = (bits + 31) / 32; out.reserve(words); out.used = words; // fill random words for (size_t i = 0; i < words; ++i) { fillRandomBytes(reinterpret_cast<uint8_t*>(&out.data[i]), sizeof(uint32_t)); } // mask unused high bits size_t extra = words * 32 - bits; if (extra > 0) { uint32_t mask = 0xFFFFFFFFu >> extra; out.data[words - 1] &= mask; } // optional normalize if you have it: // out.normalize(); }; // ------------------------------------------------------------ // Lambda: randomBelow(limit) -> uniform r in [0..limit-1] // ------------------------------------------------------------ auto randomBelow = [&](const bigInt& limit) -> bigInt { size_t bits = limit.bitLength(); bigInt r(limit.capacity); for (;;) { randomBigIntBits(r, bits); if (compare(r, limit) < 0) return r; } }; // ------------------------------------------------------------ // Lambda: randomWitnessA(n) -> uniform a in [2..n-2] // ------------------------------------------------------------ auto randomWitnessA = [&]() -> bigInt { // nMinusThree = n - 3 bigInt nMinusThree(n.capacity); subtract(n, three, nMinusThree); // n-3 // r ∈ [0..n-4] bigInt r = randomBelow(nMinusThree); // a = r + 2 => [2..n-2] bigInt a(n.capacity); add(r, two, a); return a; }; // ------------------------------------------------------------ // factor n-1 = 2^s * d // ------------------------------------------------------------ bigInt d = nm1; size_t s = 0; while (d.isEven()) { Loading @@ -525,32 +594,33 @@ namespace netplus { s++; } // ------------------------------------------------------------ // Miller-Rabin rounds std::random_device rd; std::mt19937 gen(rd()); // ------------------------------------------------------------ for (int i = 0; i < k; i++) { // Simplified witness: for production RSA, 'a' should be a random // value in range [2, n-2]. For now, using small primes as witnesses: uint32_t witness_val = (i == 0) ? 2 : (i == 1 ? 3 : 5 + (i * 2)); bigInt a(witness_val, n.capacity); bigInt a = randomWitnessA(); bigInt x = modPow(a, d, n); // if x == 1 or x == n - 1 // x == 1 or x == n-1 if ((x.used == 1 && x.data[0] == 1) || compare(x, nm1) == 0) continue; bool composite = true; for (size_t r = 1; r < s; r++) { x = modPow(x, two, n); // Square: x = x^2 % n x = modPow(x, two, n); if (compare(x, nm1) == 0) { composite = false; break; } } if (composite) return false; } return true; } Loading
src/event/epoll.cpp +49 −46 Original line number Diff line number Diff line Loading @@ -265,67 +265,72 @@ namespace netplus { if (!c->csock) return; try { // ---------------------------- // 1) TLS handshake stage // ---------------------------- if (!c->csock->getHandshakeDone()) { // Peer already closed? if (events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR)) { rearm.disarm(); CloseEventHandler(fd, tid, args); return; } // ------------------------------------------------- // 1) TLS handshake // ------------------------------------------------- if (!c->csock->getHandshakeDone()) { c->csock->handshake_after_accept(); // try flush once if something queued if (c->csock->hasPendingWrite()) { try { c->csock->flush_out(); } catch (NetException& e) { if (e.getErrorType() != NetException::Note) throw; if (e.getErrorType() == NetException::Note) return; // wait EPOLLOUT throw; } } // if still not done, stop here // still not done -> wait for next IO event if (!c->csock->getHandshakeDone()) return; } // ---------------------------- // 2) EPOLLIN: receive application data // ---------------------------- // ------------------------------------------------- // 2) EPOLLIN: receive one chunk // ------------------------------------------------- if (events & EPOLLIN) { bool got = false; for (;;) { buffer buf(BLOCKSIZE); size_t rcv = 0; try { rcv = c->csock->recvData(buf, 0); } catch (NetException& e) { if (e.getErrorType() == NetException::Note) break; if (e.getErrorType() == NetException::Note) { // nothing to read right now rcv = 0; } else { throw; } } if (rcv == 0) { // If peer closed => recvData must return 0. // Note case already handled. // In TLS, alert/EOF => close. rearm.disarm(); CloseEventHandler(fd, tid, args); return; } c->RecvData.append(buf.data.buf, rcv); got = true; } if (got && !c->RecvData.empty()) { evconnection->RequestEvent(*c, tid, args); } } // ---------------------------- // 3) EPOLLOUT: flush + send queued responses // ---------------------------- // ------------------------------------------------- // 3) EPOLLOUT: flush + send one chunk // ------------------------------------------------- if (events & EPOLLOUT) { // always flush TLS pending first // flush pending TLS output if (c->csock->hasPendingWrite()) { try { c->csock->flush_out(); Loading @@ -336,8 +341,8 @@ namespace netplus { } } // now send queued app data while (!c->SendData.empty()) { // send exactly one chunk from SendData if (!c->SendData.empty()) { size_t sendlen = std::min((size_t)BLOCKSIZE, c->SendData.size()); buffer out(c->SendData.data(), sendlen); Loading @@ -351,25 +356,23 @@ namespace netplus { } catch (NetException& e) { if (e.getErrorType() == NetException::Note) break; return; throw; } if (consumed == 0) break; c->SendData.erase(c->SendData.begin(), c->SendData.begin() + consumed); if (consumed > 0) { c->SendData.erase(c->SendData.begin(), c->SendData.begin() + consumed); } } // if nothing pending, signal response done if (c->SendData.empty() && !c->csock->hasPendingWrite()) { evconnection->ResponseEvent(*c, tid, args); } } } catch (NetException& e) { if (e.getErrorType() == NetException::Note) return; if (e.getErrorType() == NetException::Note) return; rearm.disarm(); CloseEventHandler(fd, tid, args); Loading
src/random.h +1 −2 Original line number Diff line number Diff line Loading @@ -10,6 +10,5 @@ namespace netplus { inline void fillRandom(std::vector<uint8_t>& v) { if (!v.empty()) fillRandomBytes(v.data(), v.size()); } } };