Add RSA keypair generation and signing implementation for Overte authentication
This commit is contained in:
132
src/RSAKeypair.cpp
Normal file
132
src/RSAKeypair.cpp
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
// RSAKeypair.cpp - RSA keypair generation and signing
|
||||||
|
#include "RSAKeypair.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstring>
|
||||||
|
#include <ctime>
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/bn.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
|
||||||
|
RSAKeypair::RSAKeypair() {}
|
||||||
|
|
||||||
|
RSAKeypair::~RSAKeypair() {}
|
||||||
|
|
||||||
|
bool RSAKeypair::generate() {
|
||||||
|
// Create RSA structure
|
||||||
|
RSA* keyPair = RSA_new();
|
||||||
|
if (!keyPair) {
|
||||||
|
std::cerr << "[RSAKeypair] Failed to create RSA structure" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create exponent (65537 is standard)
|
||||||
|
BIGNUM* exponent = BN_new();
|
||||||
|
if (!exponent) {
|
||||||
|
RSA_free(keyPair);
|
||||||
|
std::cerr << "[RSAKeypair] Failed to create BIGNUM for exponent" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned long RSA_KEY_EXPONENT = 65537;
|
||||||
|
BN_set_word(exponent, RSA_KEY_EXPONENT);
|
||||||
|
|
||||||
|
// Seed random number generator
|
||||||
|
srand(time(NULL));
|
||||||
|
|
||||||
|
// Generate 2048-bit keypair
|
||||||
|
const int RSA_KEY_BITS = 2048;
|
||||||
|
std::cout << "[RSAKeypair] Generating " << RSA_KEY_BITS << "-bit RSA keypair..." << std::endl;
|
||||||
|
|
||||||
|
int result = RSA_generate_key_ex(keyPair, RSA_KEY_BITS, exponent, NULL);
|
||||||
|
BN_free(exponent);
|
||||||
|
|
||||||
|
if (result != 1) {
|
||||||
|
std::cerr << "[RSAKeypair] Failed to generate keypair: " << ERR_get_error() << std::endl;
|
||||||
|
RSA_free(keyPair);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "[RSAKeypair] Keypair generated successfully" << std::endl;
|
||||||
|
|
||||||
|
// Extract public key in DER format
|
||||||
|
unsigned char* publicKeyDER = nullptr;
|
||||||
|
int publicKeyLength = i2d_RSAPublicKey(keyPair, &publicKeyDER);
|
||||||
|
|
||||||
|
if (publicKeyLength <= 0) {
|
||||||
|
std::cerr << "[RSAKeypair] Failed to encode public key: " << ERR_get_error() << std::endl;
|
||||||
|
RSA_free(keyPair);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_publicKey.assign(publicKeyDER, publicKeyDER + publicKeyLength);
|
||||||
|
OPENSSL_free(publicKeyDER);
|
||||||
|
|
||||||
|
// Extract private key in DER format
|
||||||
|
unsigned char* privateKeyDER = nullptr;
|
||||||
|
int privateKeyLength = i2d_RSAPrivateKey(keyPair, &privateKeyDER);
|
||||||
|
|
||||||
|
if (privateKeyLength <= 0) {
|
||||||
|
std::cerr << "[RSAKeypair] Failed to encode private key: " << ERR_get_error() << std::endl;
|
||||||
|
RSA_free(keyPair);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_privateKey.assign(privateKeyDER, privateKeyDER + privateKeyLength);
|
||||||
|
OPENSSL_free(privateKeyDER);
|
||||||
|
|
||||||
|
RSA_free(keyPair);
|
||||||
|
|
||||||
|
std::cout << "[RSAKeypair] Public key: " << publicKeyLength << " bytes" << std::endl;
|
||||||
|
std::cout << "[RSAKeypair] Private key: " << privateKeyLength << " bytes" << std::endl;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> RSAKeypair::sign(const std::vector<uint8_t>& plaintext) const {
|
||||||
|
if (m_privateKey.empty()) {
|
||||||
|
std::cerr << "[RSAKeypair] Cannot sign: no private key" << std::endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load private key from DER
|
||||||
|
const unsigned char* privateKeyData = m_privateKey.data();
|
||||||
|
RSA* rsaPrivateKey = d2i_RSAPrivateKey(nullptr, &privateKeyData, m_privateKey.size());
|
||||||
|
|
||||||
|
if (!rsaPrivateKey) {
|
||||||
|
std::cerr << "[RSAKeypair] Failed to load private key for signing" << std::endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash the plaintext with SHA256
|
||||||
|
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||||||
|
SHA256(plaintext.data(), plaintext.size(), hash);
|
||||||
|
|
||||||
|
// Allocate signature buffer
|
||||||
|
std::vector<uint8_t> signature(RSA_size(rsaPrivateKey));
|
||||||
|
unsigned int signatureLength = 0;
|
||||||
|
|
||||||
|
// Sign the hash
|
||||||
|
int result = RSA_sign(NID_sha256,
|
||||||
|
hash,
|
||||||
|
SHA256_DIGEST_LENGTH,
|
||||||
|
signature.data(),
|
||||||
|
&signatureLength,
|
||||||
|
rsaPrivateKey);
|
||||||
|
|
||||||
|
RSA_free(rsaPrivateKey);
|
||||||
|
|
||||||
|
if (result != 1) {
|
||||||
|
std::cerr << "[RSAKeypair] Signing failed: " << ERR_get_error() << std::endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
signature.resize(signatureLength);
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RSAKeypair::setKeys(const std::vector<uint8_t>& publicKey, const std::vector<uint8_t>& privateKey) {
|
||||||
|
m_publicKey = publicKey;
|
||||||
|
m_privateKey = privateKey;
|
||||||
|
}
|
||||||
32
src/RSAKeypair.hpp
Normal file
32
src/RSAKeypair.hpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// RSAKeypair.hpp - RSA keypair generation and signing for Overte authentication
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
class RSAKeypair {
|
||||||
|
public:
|
||||||
|
RSAKeypair();
|
||||||
|
~RSAKeypair();
|
||||||
|
|
||||||
|
// Generate a new 2048-bit RSA keypair
|
||||||
|
bool generate();
|
||||||
|
|
||||||
|
// Sign plaintext with SHA256 + RSA
|
||||||
|
std::vector<uint8_t> sign(const std::vector<uint8_t>& plaintext) const;
|
||||||
|
|
||||||
|
// Get DER-encoded keys
|
||||||
|
std::vector<uint8_t> getPublicKeyDER() const { return m_publicKey; }
|
||||||
|
std::vector<uint8_t> getPrivateKeyDER() const { return m_privateKey; }
|
||||||
|
|
||||||
|
// Set keys from DER encoding (for loading from file)
|
||||||
|
void setKeys(const std::vector<uint8_t>& publicKey, const std::vector<uint8_t>& privateKey);
|
||||||
|
|
||||||
|
// Check if keypair is valid
|
||||||
|
bool isValid() const { return !m_privateKey.empty() && !m_publicKey.empty(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<uint8_t> m_publicKey;
|
||||||
|
std::vector<uint8_t> m_privateKey;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user