Jag har under helgen exprimenterat en del med krypteringsalgoritmen RSA.Så jag tänkte dela med mig lite av mitt expriment.
Jag har två versioner just nu, den första versionen använde sig av libmath.h som är standardbiblioteket för matematik i c. Libmath versionen fungerar inte bra alls. förmodligen har jag gjort fel någonstans, men vilket som, så kan man bara använda mycket små värden i den. ett resultat får aldrig överstiga 2^32, och om vi då använder lite större tal som e = 22 m = 15 så blir resultatet 15^22 mod n, redan här: 15^22 klarar inte libmath av att beräkna utan att overflowa variabler.
Den andra versionen använder GNU Multi-precision library för mer avancerad aritmetik, vilket gör det möjligt att räkna med väldigt stora tal, mer exakt, obegränsat stora. Biblioteket innehåller även en del funktioner som jag tidigare var tvungen att skriva själv, tillexempel primtalsgenerator.
libgmp:
#include <stdio.h>
#include <sys/time.h>
#include <gmp.h>
int get_prime(mpz_t rop);
int rsa_createkeys();
int rsa_process(mpz_t x, mpz_t y, mpz_t n);
int usage(char *filename);
int
get_prime(mpz_t rop) {
mpz_t n, m;
mpz_init(n);
mpz_init(m);
gmp_randstate_t state;
gmp_randinit_mt(state);
struct timeval t;
gettimeofday(&t, NULL);
gmp_randseed_ui(state, t.tv_sec * t.tv_usec);
mpz_urandomb(n, state, 120);
mpz_ui_pow_ui(m, 10, 25);
mpz_add(n, n, m);
mpz_clear(m);
mpz_nextprime(n, n);
gmp_printf("Prime: %Zd\n", n);
*rop = *n;
return 0;
}
int
rsa_createkeys() {
mpz_t p, q, n, phi, e, d;
mpz_init(p);
mpz_init(q);
mpz_init(n);
mpz_init(phi);
mpz_init(e);
mpz_init(d);
get_prime(p);
get_prime(q);
mpz_mul(n, p, q);
mpz_sub_ui(p, p, 1);
mpz_sub_ui(q, q, 1);
mpz_mul(phi, p, q);
mpz_set_ui(e, 65537);
mpz_invert(d, e, phi);
gmp_printf("Public key: %Zx %Zx\nPrivate key: %Zx %Zx\n\n", e, n, d, n);
mpz_clear(p);
mpz_clear(q);
mpz_clear(n);
mpz_clear(phi);
mpz_clear(e);
mpz_clear(d);
return 0;
}
int
rsa_process(mpz_t x, mpz_t y, mpz_t n) {
mpz_t c;
mpz_init(c);
mpz_powm(c, x, y, n);
gmp_printf(">%Zx\n\n", c);
mpz_clear(c);
return 0;
}
int
usage(char *filename) {
printf("Usage: %s [option] [<input> <key>]\n\n", filename);
printf("Options:\n\t--create-keys\tGenerates new rsa keys\n\n");
return 0;
}
int
main(int argc, char **argv) {
if (argc < 2) {
usage(argv[0]);
return 0;
}
if (!strcmp(argv[1], "--create-keys")) {
rsa_createkeys();
} else {
if (argc < 4) {
usage(argv[0]);
return 0;
}
mpz_t a, b, c;
mpz_init_set_str(a, argv[1], 16);
mpz_init_set_str(b, argv[2], 16);
mpz_init_set_str(c, argv[3], 16);
rsa_process(a, b, c);
mpz_clear(a);
mpz_clear(b);
mpz_clear(c);
}
return 0;
}
libmath:
#include <stdio.h>
#include <math.h>
#include <sys/time.h>
int modinverse(int a, int m);
int get_prime();
int rsa_createkeys();
int rsa_process();
int usage(char *filename);
int
modinverse(int a, int m) {
int i;
for (i = 1; i <= m; i++) {
if ((i * a) % m == 1)
return i;
}
}
int
get_prime() {
struct timeval t;
gettimeofday(&t, NULL);
srandom(t.tv_sec * t.tv_usec);
int n = random() % 8 + 2;
int i;
for (i = 2; i <= sqrt(n); i++) {
if (n % i == 0)
return get_prime();
}
return n;
}
int
rsa_createkeys() {
int p, q, n, phi, e, d;
p = get_prime();
q = get_prime();
n = p * q;
phi = (p-1) * (q-1);
e = 5;
d = modinverse(e, phi);
printf("Public key: %d %d\nPrivate key: %d %d\n\n", e, n, d, n);
return 0;
}
int
rsa_process(int x, int y, int n) {
int c = (int) pow(x, y) % n;
printf("> %d\n\n", c);
return 0;
}
int
usage(char *filename) {
printf("Usage: %s [option] [<input> <key>]\n\n", filename);
printf("Options:\n\t--create-keys\tGenerates new rsa keys\n\n");
return 0;
}
int
main(int argc, char **argv) {
if (argc < 2) {
usage(argv[0]);
return 0;
}
if (!strcmp(argv[1], "--create-keys")) {
rsa_createkeys();
} else {
if (argc < 4) {
usage(argv[0]);
return 0;
}
rsa_process(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]));
}
return 0;
}
GMP-versionen är skriven för ubuntu's libgmp3 från repo. Som inte är den senaste. I senare versioner finns det möjlighet att korta ned programmet avsevärt genom att slå ihop en massa mpz_clear- och init till ett funktionsanrop.
jockepockee@ubunut:~/dev/RSA$ ./new --create-keys
Prime: 702555522536586029427144464815422863
Prime: 884012733027680497026431992321487753
Public key: 10001 59fcb187d6ecd307629f5126539f9828653fbf549af419f278d7b91c2e87
Private key: 3949e9d01c617b5c194a6a44673a93c6a346847c922940749a81e3395cd1 59fcb187d6ecd307629f5126539f9828653fbf549af419f278d7b91c2e87
jockepockee@ubunut:~/dev/RSA$ ./new 1234567891011121314151617181920 10001 59fcb187d6ecd307629f5126539f9828653fbf549af419f278d7b91c2e87
> 4cb9bd3fbb9afdbf1026c962a541b8d1c0a137d5b0cfd348abd3e7a67e5b
jockepockee@ubunut:~/dev/RSA$ ./new 4cb9bd3fbb9afdbf1026c962a541b8d1c0a137d5b0cfd348abd3e7a67e5b 3949e9d01c617b5c194a6a44673a93c6a346847c922940749a81e3395cd1 59fcb187d6ecd307629f5126539f9828653fbf549af419f278d7b91c2e87
> 1234567891011121314151617181920
För att visa hur jobbig/svår algoritmen är att knäcka så kan jag bjuda på ett citat från irc:
14:37 <@kqr> när första faktorn är 37298467 så tar det uuh *time körs fortfarande* 17 sekunder
14:37 <@kqr> om första faktorn är ~ 10^35
14:37 <@kqr> .o gcalc 10^35/37298467 * 17 in hours
14:38 <@kqr> .o gcalc 10^35/37298467 * 17
14:38 < failboat> kqr: ((10^35) / 37 298 467) * 17 = 4.55782807 * 10^(28)
14:38 <@kqr> .o gcalc 10^35/37298467 * 17 seconds in hours
14:38 < failboat> kqr: ((10^35) / 37 298 467) * (17 seconds) = 1.26606335 * 10^(25) hours
14:38 <@kqr> ah
14:38 <@kqr> .o gcalc 10^35/37298467 * 17 seconds in days
14:38 < failboat> kqr: ((10^35) / 37 298 467) * (17 seconds) = 5.27526397 * 10^(23) days
14:38 <@kqr> .o gcalc 10^35/37298467 * 17 seconds in years
14:38 < failboat> kqr: ((10^35) / 37 298 467) * (17 seconds) = 1.44431941 * 10^(21) years
14:38 <@kqr> hahahahahaha