\section{Conclusion}
+% http://en.wikipedia.org/wiki/RSA_%28cryptosystem%29
%\bibliographystyle{plain}
%\bibliography{main}
#include <gmpxx.h>
+/**
+ * All random functions uses "/dev/urandom".
+ */
class Rand
{
public:
#include "Rsa.h"
+#include <iostream>
using namespace std;
-#include "Rand.h"
-#include "Utils.h"
-
-pair<Rsa::KeyPub, Rsa::KeyPriv> Rsa::generateRSAKeys(uint exponent, uint keySizeBits)
-{
- mpz_class p, q, phi;
- KeyPub kPub;
- KeyPriv kPriv;
-
- do
- {
- kPub.e = exponent;
- p = Rand::randPrime(keySizeBits / 2);
- q = Rand::randPrime(keySizeBits / 2);
-
- kPriv.n = kPub.n = p * q;
- phi = (p - 1) * (q - 1);
-
- } while (mpz_invert(kPriv.d.get_mpz_t(), kPub.e.get_mpz_t(), phi.get_mpz_t()) == 0);
-
-// For debugging purpose.
-// print("p", p);
-// print("q", q);
-// print("n", kPub.n);
-// print("phi", phi);
-// print("d", kPriv.d);
-
- return make_pair(kPub, kPriv);
-}
-
-mpz_class Rsa::sign(const mpz_class& m, const KeyPriv& kPriv)
-{
- mpz_class result;
- mpz_powm_sec(result.get_mpz_t(), m.get_mpz_t(), kPriv.d.get_mpz_t(), kPriv.n.get_mpz_t());
- return result;
-}
-
bool Rsa::verifySignature(const mpz_class& m, const mpz_class& sig, const KeyPub& kPub)
{
- mpz_class mPrime;
- mpz_powm_sec(mPrime.get_mpz_t(), sig.get_mpz_t(), kPub.e.get_mpz_t(), kPub.n.get_mpz_t());
- return m == mPrime;
+ mpz_class m2;
+ mpz_powm_sec(m2.get_mpz_t(), sig.get_mpz_t(), kPub.e.get_mpz_t(), kPub.n.get_mpz_t());
+ return m == m2;
}
#ifndef RSA_H
#define RSA_H
-#include <utility>
#include <gmpxx.h>
class Rsa
{
public:
struct KeyPub {
- mpz_class n;
- mpz_class e;
+ mpz_class n; // Modulus.
+ mpz_class e; // Exponent.
};
- struct KeyPriv {
- mpz_class n;
- mpz_class d;
- };
-
- static std::pair<KeyPub, KeyPriv> generateRSAKeys(uint exponent, uint keySizeBits);
-
- static mpz_class sign(const mpz_class& m, const KeyPriv& kPriv);
-
static bool verifySignature(const mpz_class& m, const mpz_class& sig, const KeyPub& kPub);
};
#include "RsaCrt.h"
+
+using namespace std;
+
+#include "Rand.h"
+#include "Utils.h"
+
+pair<Rsa::KeyPub, RsaCrt::KeyPriv> RsaCrt::generateRSAKeys(uint exponent, uint keySizeBits)
+{
+ mpz_class phi;
+ Rsa::KeyPub kPub;
+ KeyPriv kPriv;
+
+ do
+ {
+ kPub.e = kPriv.e = exponent;
+ kPriv.p = Rand::randPrime(keySizeBits / 2);
+ kPriv.q = Rand::randPrime(keySizeBits / 2);
+
+ kPriv.n = kPub.n = kPriv.p * kPriv.q;
+ phi = (kPriv.p - 1) * (kPriv.q - 1);
+
+ } while (mpz_invert(kPriv.d.get_mpz_t(), kPub.e.get_mpz_t(), phi.get_mpz_t()) == 0);
+
+ kPriv.dp = kPriv.d % (kPriv.p - 1);
+ kPriv.dq = kPriv.d % (kPriv.q - 1);
+
+ mpz_invert(kPriv.qInv.get_mpz_t(), kPriv.q.get_mpz_t(), kPriv.p.get_mpz_t());
+
+ return make_pair(kPub, kPriv);
+}
+
+mpz_class RsaCrt::sign(const mpz_class& m, const KeyPriv& kPriv)
+{
+ mpz_class sp, sq;
+
+ mpz_powm_sec(sp.get_mpz_t(), m.get_mpz_t(), kPriv.dp.get_mpz_t(), kPriv.p.get_mpz_t());
+ mpz_powm_sec(sq.get_mpz_t(), m.get_mpz_t(), kPriv.dq.get_mpz_t(), kPriv.q.get_mpz_t());
+
+ return sq + ((kPriv.qInv * (sp - sq)) % kPriv.p) * kPriv.q;
+}
#ifndef RSACRT_H
#define RSACRT_H
+#include <utility>
+
#include <gmpxx.h>
+#include "Rsa.h"
+
class RsaCrt
{
public:
- RsaCrt();
+ struct KeyPriv {
+ mpz_class n; // Modulus.
+ uint e; // Exponent.
- struct KeyPrivCRT {
mpz_class p;
mpz_class q;
mpz_class dp;
mpz_class dq;
mpz_class qInv;
+ mpz_class d;
};
+
+ static std::pair<Rsa::KeyPub, KeyPriv> generateRSAKeys(uint exponent, uint keySizeBits);
+
+ static mpz_class sign(const mpz_class& m, const KeyPriv& kPriv);
};
#endif
--- /dev/null
+#include "RsaStd.h"
+
+using namespace std;
+
+#include "Rand.h"
+#include "Utils.h"
+
+pair<Rsa::KeyPub, RsaStd::KeyPriv> RsaStd::generateRSAKeys(uint exponent, uint keySizeBits)
+{
+ mpz_class p, q, phi;
+ Rsa::KeyPub kPub;
+ KeyPriv kPriv;
+
+ do
+ {
+ kPub.e = exponent;
+ p = Rand::randPrime(keySizeBits / 2);
+ q = Rand::randPrime(keySizeBits / 2);
+
+ kPriv.n = kPub.n = p * q;
+ phi = (p - 1) * (q - 1);
+
+ } while (mpz_invert(kPriv.d.get_mpz_t(), kPub.e.get_mpz_t(), phi.get_mpz_t()) == 0); // If 'd' is not invertible we try another primes.
+
+// For debugging purpose.
+// Utils::print("p", p);
+// Utils::print("q", q);
+// Utils::print("n", kPub.n);
+// Utils::print("phi", phi);
+// Utils::print("d", kPriv.d);
+
+ return make_pair(kPub, kPriv);
+}
+
+mpz_class RsaStd::sign(const mpz_class& m, const KeyPriv& kPriv)
+{
+ mpz_class result;
+ mpz_powm_sec(result.get_mpz_t(), m.get_mpz_t(), kPriv.d.get_mpz_t(), kPriv.n.get_mpz_t());
+ return result;
+}
--- /dev/null
+#ifndef RSASTD_H
+#define RSASTD_H
+
+#include <utility>
+#include <gmpxx.h>
+
+#include "Rsa.h"
+
+class RsaStd
+{
+public:
+ struct KeyPriv {
+ mpz_class n;
+ mpz_class d;
+ };
+
+ static std::pair<Rsa::KeyPub, KeyPriv> generateRSAKeys(uint exponent, uint keySizeBits);
+
+ static mpz_class sign(const mpz_class& m, const KeyPriv& kPriv);
+};
+
+#endif
return chrono::duration_cast<chrono::milliseconds>(chrono::high_resolution_clock::now() - this->time).count();
}
+void Timer::reset()
+{
+ this->time = chrono::high_resolution_clock::now();
+}
+
ostream& operator<<(ostream& os, const Timer& t)
{
os << t.ms() << " ms";
public:
Timer();
int ms() const;
+ void reset();
friend std::ostream& operator<<(std::ostream& os, const Timer& t);
private:
name: "lab3"
type: "application"
- files: ["main.cpp", "Rand.h", "Rand.cpp", "Rsa.h", "Rsa.cpp", "RsaCrt.h", "RsaCrt.cpp", "Utils.h", "Utils.cpp"]
+ files: ["main.cpp", "Rand.h", "Rand.cpp", "Rsa.h", "Rsa.cpp", "RsaStd.h", "RsaStd.cpp", "RsaCrt.h", "RsaCrt.cpp", "Utils.h", "Utils.cpp"]
- cpp.commonCompilerFlags: ["-std=c++11"]
+ cpp.commonCompilerFlags: ["-std=c++14"]
cpp.staticLibraries: ["gmp", "gmpxx"]
Properties {
#include <gmpxx.h>
+#include "Utils.h"
+#include "Rand.h"
#include "Rsa.h"
+#include "RsaStd.h"
#include "RsaCrt.h"
const uint KEY_SIZE_BITS = 1024;
const uint RSA_PUBLIC_EXPONENT = 65537;
+bool testRsaStandard()
+{
+ const auto& keys = RsaStd::generateRSAKeys(RSA_PUBLIC_EXPONENT, KEY_SIZE_BITS);
+ const auto& kPub = keys.first;
+ const auto& kPriv = keys.second;
+
+ mpz_class message = Rand::randSize(KEY_SIZE_BITS / 2);
+ mpz_class signature = RsaStd::sign(message, kPriv);
+
+ return Rsa::verifySignature(message, signature, kPub) && !Rsa::verifySignature(message + 1, signature, kPub);
+}
+
+bool testRsaCrt()
+{
+ const auto& keys = RsaCrt::generateRSAKeys(RSA_PUBLIC_EXPONENT, KEY_SIZE_BITS);
+ const auto& kPub = keys.first;
+ const auto& kPriv = keys.second;
+
+ mpz_class message = Rand::randSize(KEY_SIZE_BITS / 2);
+ mpz_class signature = RsaCrt::sign(message, kPriv);
+
+ return Rsa::verifySignature(message, signature, kPub) && !Rsa::verifySignature(message + 1, signature, kPub);
+}
+
+int timeSignRsaStd(int N)
+{
+ Timer timer;
+ const auto& keys = RsaStd::generateRSAKeys(RSA_PUBLIC_EXPONENT, KEY_SIZE_BITS);
+
+ for (int i = 0; i < N; i++)
+ {
+ mpz_class message = Rand::randSize(KEY_SIZE_BITS / 2);
+ RsaStd::sign(message, keys.second);
+ }
+
+ return timer.ms();
+}
+
+int timeSignRsaCRT(int N)
+{
+ Timer timer;
+ const auto& keys = RsaCrt::generateRSAKeys(RSA_PUBLIC_EXPONENT, KEY_SIZE_BITS);
+
+ for (int i = 0; i < N; i++)
+ {
+ mpz_class message = Rand::randSize(KEY_SIZE_BITS / 2);
+ RsaCrt::sign(message, keys.second);
+ }
+
+ return timer.ms();
+}
+
+void measuresRsaDurations()
+{
+ const int N = 10000;
+ int timeRsaStd = timeSignRsaStd(N);
+ int timeRsaCRT = timeSignRsaCRT(N);
+
+ cout << N << " x RSA standard: " << timeRsaStd << " ms" << endl;
+ cout << N << " x RSA CRT: " << timeRsaCRT << " ms" << endl;
+ cout << "Speedup: " << (double(timeRsaStd) / double(timeRsaCRT)) << endl;
+}
+
int main(int argc, char** argv)
{
vector<string> args;
for (int i = 0; i < argc; i++)
args.push_back(string(argv[i]));
- const auto& keys = Rsa::generateRSAKeys(RSA_PUBLIC_EXPONENT, KEY_SIZE_BITS);
- const auto& kPub = keys.first;
- const auto& kPriv = keys.second;
-
- mpz_class message(42);
- mpz_class signature = Rsa::sign(message, kPriv);
+ if (!testRsaStandard())
+ cout << "RSA standard failed!" << endl;
- mpz_class message2(42);
- cout << "verify: " << Rsa::verifySignature(message2, signature, kPub) << endl;
+ if (!testRsaCrt())
+ cout << "RSA CRT failed!" << endl;
- mpz_class message3(43);
- cout << "verify: " << Rsa::verifySignature(message3, signature, kPub) << endl;
+ measuresRsaDurations();
return 0;
}