Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/keyPair.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <fstream>
#include <stdexcept>
#include <string>
#include <utility>

// clang-format off
#if defined(_WIN32)
Expand Down Expand Up @@ -109,6 +110,10 @@ keyPair::keyPair() {
private_key.d = d;
}

// Constructor for already deserialized key structures
keyPair::keyPair(PublicKey publicKey, PrivateKey privateKey)
: public_key(std::move(publicKey)), private_key(std::move(privateKey)) {}

// Import Constructor: Imports keys from Base64 encoded serialized strings
keyPair::keyPair(const std::string &publicKey, const std::string &privateKey) {
const std::vector<uint8_t> pubBytes = base64Decode(publicKey);
Expand Down Expand Up @@ -190,6 +195,26 @@ bool keyPair::s_deserialize(const std::vector<uint8_t> &data, operations::Base25
return true;
}

// Static factory that creates a keyPair from populated PublicKey and PrivateKey structs
keyPair keyPair::create(const PublicKey &publicKey, const PrivateKey &privateKey) {
return keyPair(publicKey, privateKey);
}

// Static factory that deserializes raw binary data and creates a keyPair
keyPair keyPair::create(const std::vector<uint8_t> &pubData, const std::vector<uint8_t> &privData) {
PublicKey pub;
PrivateKey priv;

if (!s_deserialize(pubData, pub.n, pub.e)) {
throw std::runtime_error("Failed to deserialize public key data.");
}
if (!s_deserialize(privData, priv.n, priv.d)) {
throw std::runtime_error("Failed to deserialize private key data.");
}

return keyPair(pub, priv);
}

std::string keyPair::base64Encode(const std::vector<uint8_t> &data) {
std::vector<uint8_t> result;
size_t index = 0;
Expand Down
8 changes: 8 additions & 0 deletions src/keyPair.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,17 @@ class keyPair {

keyPair(const std::string &publicKey, const std::string &privateKey);

// Constructor to build a keyPair without triggering expensive prime generation
keyPair(PublicKey publicKey, PrivateKey privateKey);

PublicKey getPublicKey() { return public_key; }
PrivateKey getPrivateKey() { return private_key; }

// Static factory methods to safely create a keyPair
static keyPair create(const PublicKey &publicKey, const PrivateKey &privateKey);
static keyPair create(const std::vector<uint8_t> &pubData,
const std::vector<uint8_t> &privData);

static std::vector<uint8_t> s_serialize(const operations::Base256 &first,
const operations::Base256 &second);
static bool s_deserialize(const std::vector<uint8_t> &data, operations::Base256 &outFirst,
Expand Down
51 changes: 51 additions & 0 deletions tests/test_rsa.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,55 @@ TEST_CASE("RSA Core: Key Serialization and Base64 Import/Export") {
std::string recovered = decrypt(importedPair, ciphertext);

REQUIRE(recovered == plaintext);
}

TEST_CASE("RSA Core: Key Creation and Struct-based Initialization") {
static keyPair originalPair;

SECTION("Creating keyPair from deserialized PublicKey and PrivateKey structs") {
PublicKey pub = originalPair.getPublicKey();
PrivateKey priv = originalPair.getPrivateKey();

// 1. Verify the new struct-based constructor
keyPair constructedPair(pub, priv);

std::string plaintext = "Struct Constructor Roundtrip Verification";
std::vector<uint8_t> ciphertext = encrypt(constructedPair, plaintext);
std::string recovered = decrypt(originalPair, ciphertext);

REQUIRE(recovered == plaintext);

// 2. Verify the static factory method 'create' with structs
keyPair factoryStructPair = keyPair::create(pub, priv);

std::vector<uint8_t> ciphertext2 = encrypt(originalPair, plaintext);
std::string recovered2 = decrypt(factoryStructPair, ciphertext2);

REQUIRE(recovered2 == plaintext);
}

SECTION("Creating keyPair from raw serialized byte vectors") {
std::vector<uint8_t> pubBytes = originalPair.getPublicKey().serialize();
std::vector<uint8_t> privBytes = originalPair.getPrivateKey().serialize();

REQUIRE_FALSE(pubBytes.empty());
REQUIRE_FALSE(privBytes.empty());

// Verify the static factory method 'create' with raw byte vectors (bypassing Base64)
keyPair factoryBytesPair = keyPair::create(pubBytes, privBytes);

std::string plaintext = "Binary Serialization Factory Verification";
std::vector<uint8_t> ciphertext = encrypt(factoryBytesPair, plaintext);
std::string recovered = decrypt(originalPair, ciphertext);

REQUIRE(recovered == plaintext);
}

SECTION("Creating keyPair from invalid/corrupt serialized bytes throws exception") {
std::vector<uint8_t> invalidPub = {1, 2, 3, 4}; // Invalid size and payload
std::vector<uint8_t> invalidPriv = {5, 6, 7, 8};

// Expect std::runtime_error as specified in keyPair::create
REQUIRE_THROWS_AS(keyPair::create(invalidPub, invalidPriv), std::runtime_error);
}
}
Loading