| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
RSA (Rivest–Shamir–Adleman) Asymmetric Encryption Algorithm Implementation — Educational Purposes
This RSA implementation now includes enhanced security features:
In terms of improvements, the C code file is a better choice.
These updates make RSA encryption and decryption in this project significantly more secure against modern cryptographic and side-channel threats.
This project provides a modern, header-only C++ implementation of the RSA cryptosystem. It is designed for learning and experimentation, featuring:
Note: This implementation is for educational purposes only and should NOT be used in production settings.
RSA stands for Rivest–Shamir–Adleman, named after its inventors Ron Rivest, Adi Shamir, and Leonard Adleman. The algorithm was first publicly described in 1977 by these three MIT researchers. It provided the first practical implementation of public-key cryptography, a concept invented by Whitfield Diffie and Martin Hellman in 1976.
The publication of RSA revolutionized the field of cryptography by introducing the concept of practical public-key cryptography, which underpins much of modern digital security, including secure web browsing, digital signatures, and secure email.
Prior to RSA and public-key cryptography, all secure communication required that both parties share a secret key in advance—a major problem for large-scale or spontaneous secure communications. RSA allows two parties to establish secure communications over an insecure channel without needing to share a secret in advance.
RSA is based on the mathematical difficulty of factoring the product of two large prime numbers. The security of RSA relies on the fact that, while it is easy to multiply two large primes together, it is computationally infeasible to factor their product back into the original primes for suitably large numbers.
Select Two Large Prime Numbers (p and q):
Compute the Modulus (n):
Calculate Euler's Totient Function (φ(n)):
Choose Public Exponent (e):
Compute Private Exponent (d):
Public and Private Keys:
Note: In practice, messages larger than n must be split, padded, or handled with hybrid cryptography. Direct use of RSA is not secure for encrypting large data or arbitrary messages (see "Security Notes" below).
The security of RSA depends on the practical difficulty of factoring the large number n back into its prime components p and q. If an attacker could factor n, they could compute φ(n) and thus recover the private key d. For large enough n, this is believed to be infeasible with current technology.
Besides encryption, RSA can be used for digital signatures:
This allows verification of both authenticity (only the private key holder could have signed) and integrity of the original message.
| Step | Symbol | Description |
|---|---|---|
| Choose Primes | p, q | Large, random primes |
| Compute Modulus | n | n = p * q |
| Totient | φ(n) | φ(n) = (p-1)*(q-1) |
| Public Exponent | e | 1 < e < φ(n), gcd(e, φ(n))=1 |
| Private Exp. | d | d ≡ e⁻¹ mod φ(n) |
| Public Key | (n, e) | Distributed openly |
| Private Key | (n, d) | Kept secret |
| Encrypt | c | c = m^e mod n |
| Decrypt | m | m = c^d mod n |
g++ -std=c++17 -lgmp -lgmpxx -o rsa_cli bin/rsa_cli.cppg++ -std=c++17 -lgmp -lgmpxx -o rsa_example src/main.cppTo create fully statically linked versions (for easier deployment on systems without GMP or C++ runtime shared libraries):
# Statically linked CLI (output: bin/srsa_cli)
g++ -o bin/srsa_cli bin/rsa_cli.cpp /usr/lib/x86_64-linux-gnu/libgmp.a -lgmpxx -static-libgcc -static-libstdc++Both binaries will be completely self-contained and should run on any compatible Linux system without requiring GMP or C++ runtime to be installed.
#include "rsa.hpp"
int main() {
// Generate a 2048-bit key pair
RSA::KeyPair keys = RSA::GenerateKeyPair(RSA::KeySize::Bits2048);
// Save as PEM (PKCS#1 for private, PKCS#1 for public)
keys.public_key.save_pem("public.pem");
keys.private_key.save_pem("private.pem");
// Save private key as PKCS#8 (X.509 format)
keys.private_key.save_pkcs8_pem("private_pkcs8.pem");
// Save public key as X.509 SubjectPublicKeyInfo
keys.public_key.save_x509_pem("public_x509.pem");
}#include "rsa.hpp"
int main() {
// Load public key (PKCS#1 PEM)
auto pub1 = RSA::RSAPublicKey::load_pem("public.pem");
// Load public key (X.509 PEM)
auto pub2 = RSA::RSAPublicKey::load_x509_pem("public_x509.pem");
// Load private key (PKCS#1 PEM)
auto priv1 = RSA::RSAPrivateKey::load_pem("private.pem");
// Load private key (PKCS#8 PEM)
auto priv2 = RSA::RSAPrivateKey::load_pkcs8_pem("private_pkcs8.pem");
}#include "rsa.hpp"
#include <iostream>
int main() {
std::string message = "Hello, RSA!";
// In-memory keys
RSA::KeyPair keys = RSA::GenerateKeyPair(RSA::KeySize::Bits1024);
// Encrypt with public, decrypt with private (in-memory)
std::string encrypted = RSA::MESSAGE::Encrypt(message, keys.public_key)
.toFormat(RSA::OutputFormat::Base64)
.toString();
std::string decrypted = RSA::MESSAGE::Decrypt(encrypted, keys.private_key, RSA::OutputFormat::Base64);
std::cout << "Decrypted: " << decrypted << std::endl;
// Using loaded keys (X.509 public, PKCS#8 private)
auto pub = RSA::RSAPublicKey::load_x509_pem("public_x509.pem");
auto priv = RSA::RSAPrivateKey::load_pkcs8_pem("private_pkcs8.pem");
std::string encrypted2 = RSA::MESSAGE::Encrypt(message, pub)
.toFormat(RSA::OutputFormat::Base64)
.toString();
std::string decrypted2 = RSA::MESSAGE::Decrypt(encrypted2, priv, RSA::OutputFormat::Base64);
std::cout << "Decrypted (X.509/PKCS#8): " << decrypted2 << std::endl;
}#include "rsa.hpp"
int main() {
// Load keys
auto pub = RSA::RSAPublicKey::load_x509_pem("public_x509.pem");
auto priv = RSA::RSAPrivateKey::load_pkcs8_pem("private_pkcs8.pem");
// Encrypt file
RSA::FILE::Encrypt("plain.txt", "enc.bin", pub, RSA::OutputFormat::Binary);
// Decrypt file
RSA::FILE::Decrypt("enc.bin", "dec.txt", priv, RSA::OutputFormat::Binary);
}#include "rsa.hpp"
#include <iostream>
int main() {
std::string message = "Format test!";
RSA::KeyPair keys = RSA::GenerateKeyPair(RSA::KeySize::Bits1024);
// Encrypt to hex
std::string hex_cipher = RSA::MESSAGE::Encrypt(message, keys.public_key)
.toFormat(RSA::OutputFormat::Hex)
.toString();
std::string hex_plain = RSA::MESSAGE::Decrypt(hex_cipher, keys.private_key, RSA::OutputFormat::Hex);
// Encrypt to base64
std::string b64_cipher = RSA::MESSAGE::Encrypt(message, keys.public_key)
.toFormat(RSA::OutputFormat::Base64)
.toString();
std::string b64_plain = RSA::MESSAGE::Decrypt(b64_cipher, keys.private_key, RSA::OutputFormat::Base64);
std::cout << "Hex decrypted: " << hex_plain << std::endl;
std::cout << "Base64 decrypted: " << b64_plain << std::endl;
}// Generate keys
RSA::KeyPair keys = RSA::GenerateKeyPair(RSA::KeySize::Bits2048);
// Load public key
auto pub_pem = RSA::RSAPublicKey::load_pem("public.pem");
auto pub_x509 = RSA::RSAPublicKey::load_x509_pem("public_x509.pem");
// Load private key
auto priv_pem = RSA::RSAPrivateKey::load_pem("private.pem");
auto priv_pkcs8 = RSA::RSAPrivateKey::load_pkcs8_pem("private_pkcs8.pem");The project includes a robust CLI tool, rsa_cli, for generating keys, encrypting, and decrypting messages or files.
It handles user prompts, colored output, and supports all core library functionality.
Statically linked CLI binary (srsa_cli) is available in bin/ for easy deployment.
./rsa_cli <command> [options]Or, for the statically linked version:
./srsa_cli <command> [options]| Command | Required Flags | Optional Flags & Arguments | Description |
|---|---|---|---|
| genkey | --pub <pub.pem> --priv <priv.pem> |
--bits <size> --pem-type <pkcs1|x509> --quick --force --no-color |
Generate RSA keypair |
| encrypt | --pub <pub.pem> --in <file|msg> --out <file> |
<binary|base64|hex> --pem-type <pkcs1|x509> --msg --quick --force --no-color |
Encrypt file or message |
| decrypt | --priv <priv.pem> --in <file|msg> --out <file> |
<binary|base64|hex> --pem-type <pkcs1|x509> --msg --quick --force --no-color |
Decrypt file or message |
| --help --version |
Show help/version info |
Generate a key pair (default PKCS#1):
./rsa_cli genkey --pub public.pem --priv private.pem --bits 2048 --quickGenerate a key pair with X.509/PKCS#8 encoding:
./rsa_cli genkey --pub public.pem --priv private.pem --bits 2048 --pem-type x509 --quickEncrypt a file using a specific PEM type:
./rsa_cli encrypt --pub public.pem --in myfile.txt --out encrypted.bin --pem-type pkcs1Decrypt a file with X.509/PKCS#8:
./rsa_cli decrypt --priv private.pem --in encrypted.bin --out decrypted.txt --pem-type x509All commands above also work with ./srsa_cli, the statically linked version.
MIT License (see LICENSE file).
For questions, improvements, or bug reports, please open an issue or pull request!
Warning:
Do NOT use this implementation for protecting real secrets or in production systems. For professional cryptography, use vetted libraries and protocols.
| Back | FazBrowse Home | New Git URL |