Skip to content

Instantly share code, notes, and snippets.

@akosma
Last active December 17, 2017 22:41
Show Gist options
  • Save akosma/05b42ced007af375684906f5320a2366 to your computer and use it in GitHub Desktop.
Save akosma/05b42ced007af375684906f5320a2366 to your computer and use it in GitHub Desktop.
RSA using the C++ interface of the GMP library
/*
CmakeLists.txt:
cmake_minimum_required(VERSION 3.6)
project(rsa)
set(CMAKE_CXX_STANDARD 14)
set(SOURCE_FILES main.cpp)
add_executable(rsa ${SOURCE_FILES})
target_link_libraries(rsa gmpxx gmp)
*/
#include <iostream>
#include <gmpxx.h>
#include <assert.h>
#include <map>
using std::cout;
using std::endl;
using std::pair;
using std::map;
using std::make_pair;
using std::string;
using keyset = map<string, pair<mpz_class, mpz_class>>;
// Calculation of the RSA keyset using GMP
// https://gmplib.org/
// Based on an earlier version in PHP
// https://gist.github.com/akosma/9058c43c76da2e6691637b1332058ddc
keyset rsa_keys(const mpz_t p, const mpz_t q, const mpz_t e) {
mpz_t d, lambda, gcd;
mpz_inits(d, lambda, gcd, NULL);
mpz_class pc{p};
mpz_class qc{q};
mpz_class nc = pc * qc;
mpz_class pc_1 = pc - 1;
mpz_class qc_1 = qc - 1;
mpz_lcm(lambda, pc_1.get_mpz_t(), qc_1.get_mpz_t());
mpz_class lambdac{lambda};
cout << "lambda = " << lambdac << endl;
// e must be bigger than 1
mpz_class ec{e};
assert(ec > 1);
// e must be smaller than lambda
assert(ec < lambdac);
// GCD(e, lambda) must be 1
mpz_gcd(gcd, e, lambda);
mpz_class gcdc{gcd};
assert(gcdc == 1);
mpz_invert(d, e, lambda);
mpz_class dc{d};
// e * d MOD lambda must be 1
mpz_class calc = ec * dc % lambdac;
assert(calc == 1);
keyset result{{"public", make_pair(ec, nc)},
{"private", make_pair(dc, nc)}};
mpz_clears(d, gcd, lambda, NULL);
return result;
}
// RSA encryption
mpz_class encrypt(const mpz_t message,
const mpz_t e,
const mpz_t n) {
mpz_t encrypted;
mpz_init(encrypted);
mpz_powm(encrypted, message, e, n);
mpz_class result{encrypted};
mpz_clear(encrypted);
return result;
}
// RSA decryption
mpz_class decrypt(const mpz_t encrypted,
const mpz_t d,
const mpz_t n) {
mpz_t original;
mpz_init(original);
mpz_powm(original, encrypted, d, n);
mpz_class result{original};
mpz_clear(original);
return result;
}
void display(mpz_class message, keyset k) {
mpz_class e = k["public"].first;
mpz_class d = k["private"].first;
mpz_class n = k["public"].second;
mpz_class encrypted = encrypt(message.get_mpz_t(), e.get_mpz_t(), n.get_mpz_t());
mpz_class decrypted = decrypt(encrypted.get_mpz_t(), d.get_mpz_t(), n.get_mpz_t());
// The decrypted message must be equal to the original
assert(message == decrypted);
cout << "Public key = (e: " << e << ", n: " << n << ")" << endl;
cout << "Private key = (d: " << d << ", n: " << n << ")" << endl;
cout << "Original message: " << message << endl;
cout << "Encrypted message: " << encrypted << endl;
cout << "Decrypted message: " << decrypted << endl;
cout << endl;
}
template<typename T>
void display(T msg, T pi, T qi, T ei) {
cout << "Initializing with p = " << pi << ", q = " << qi << ", e = " << ei << endl;
mpz_t n, d;
mpz_inits(n, d, NULL);
mpz_class p{pi};
mpz_class q{qi};
mpz_class e{ei};
mpz_class original{msg};
auto k = rsa_keys(p.get_mpz_t(), q.get_mpz_t(), e.get_mpz_t());
display(original, k);
mpz_clears(n, d, NULL);
}
int main() {
// Example taken from Wikipedia
// https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Key_generation
display(65, 61, 53, 17);
// Example from Twitter
// https://twitter.com/kosamari/status/838738015010848769
mpz_class msg{123};
mpz_class n{323};
mpz_class e{5};
mpz_class d{29};
keyset k{{"public", make_pair(e, n)},
{"private", make_pair(d, n)}};
display(msg, k);
// Very small prime numbers
display(123, 13, 19, 17);
// With some prime numbers from
// http://www.bigprimes.net/
display(67890, 541, 461, 107);
display(123456, 1181, 929, 173);
// The PHP version takes around 10 seconds on a MacBook Air
display(123456, 1181, 929, 1987);
// The PHP takes around 40 seconds in a MacBook Air
display(123456, 1181, 929, 17);
// Very big numbers; using Mersenne primes,
// something impossible in the PHP version
display("1111119999999999911111111",
"162259276829213363391578010288127",
"618970019642690137449562111",
"170141183460469231731687303715884105727");
return 0;
}
@aabedraba
Copy link

Hey @selango2017 I have just tried this and it did work with me.
Be sure to have copied the CMakeList or, otherwise, compile with -lgmpxx -lgmp options.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment