%PDF- %PDF-
| Direktori : /home/waritko/suave/ondra/ |
| Current File : //home/waritko/suave/ondra/kry-ondra.c |
/*
* File: kry.c
* Date: 11.4.2016
* Author: Ondrej Cienciala, xcienc02@usi.vutbr.cz
* Project: Projekt c. 2 - Implementation and breaking RSA
* Additional info:
* https://wis.fit.vutbr.cz/FIT/st/cwk.php?id=10888&csid=591
*/
/*===========================================================================*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <gmp.h>
/*===========================================================================*/
/*---------------------------------------------------------------------------*/
/*
* Modular exponentiation.
* R = B^E mod M
* Returns result of modular exponentiation.
*
* Params are mpz_t numbers (Result, Base, Exponent, Modulus).
*
* Tato funkce vznikla, protoze cvicici kazdy den
* zakaze a povoli pouzit jinou funkci just for fun.
*/
void modExp(mpz_t r, mpz_t B, mpz_t E, mpz_t M)
{
mpz_powm(r, B, E, M);
return;
mpz_t b, e, m, const2, temp;
mpz_set_ui(r, 1); // Set r to 1
mpz_init(b);
mpz_set(b, B);
mpz_init(e);
mpz_set(e, E);
mpz_init(m);
mpz_set(m, M);
mpz_init(const2);
mpz_set_ui(const2, 2); // Set const2 to 2
mpz_init(temp);
while (mpz_cmp_ui(e, 0) > 0) // Compare op1 and op2. Return a positive value if op1 > op2, zero if op1 = op2, or a negative value if op1 < op2.
{
mpz_mod(temp, e, const2);
if (mpz_cmp_ui(temp, 1) == 0) {
mpz_mul(r, r, b);
mpz_mod(r, r, m);
}
mpz_div_2exp(e, e, 1);
mpz_mul(b, b, b);
mpz_mod(b, b, m);
}
// gmp_printf("0x%Zx\n", r);
mpz_clear(e);
mpz_clear(m);
mpz_clear(b);
mpz_clear(temp);
mpz_clear(const2);
}
/*---------------------------------------------------------------------------*/
/*
* Compute Jacobi symbol
* (a/n) a is integer, n must be an odd integer.
*
* Params are mpz_t number a and n.
*/
int jacobi(mpz_t A, mpz_t N)
{
int res = 1;
mpz_t temp;
mpz_init(temp);
mpz_t a;
mpz_init_set(a, A);
mpz_t n;
mpz_init_set(n, N);
if (mpz_cmp_ui(a, 0) == 0) {
return 0;
}
if (mpz_cmp_ui(a, 0) < 0) {
mpz_neg(a, a);
mpz_mod_ui(temp, n, 4);
if (mpz_cmp_ui(temp, 3) == 0) {
res = -res;
}
}
if (mpz_cmp_ui(a, 1) == 0) {
return res;
}
while (mpz_cmp_ui(a, 0) != 0) {
if (mpz_cmp_ui(a, 0) < 0) {
mpz_neg(a, a);
mpz_mod_ui(temp, n, 4);
if (mpz_cmp_ui(temp, 3) == 0) {
res = -res;
}
}
mpz_mod_ui(temp, a, 2);
while (mpz_cmp_ui(temp, 0) == 0) {
mpz_fdiv_q_ui(a, a, 2); // Divide by 2 and round down (floor))
mpz_mod_ui(temp, n, 8);
if ((mpz_cmp_ui(temp, 3) == 0) || (mpz_cmp_ui(temp, 5) == 0)) {
res = -res;
}
mpz_mod_ui(temp, a, 2);
}
mpz_swap(a, n);
mpz_mod_ui(temp, a, 4);
if (mpz_cmp_ui(temp, 3) == 0) {
mpz_mod_ui(temp, n, 4);
if (mpz_cmp_ui(temp, 3) == 0) {
res = -res;
}
}
mpz_mod(a, a, n);
mpz_fdiv_q_ui(temp, n, 2); // Divide by 2 and round down (floor))
if (mpz_cmp(a, temp) > 0) {
mpz_sub(a, a, n);
}
}
if (mpz_cmp_ui(n, 1) == 0) {
return res;
}
return 0;
}
/*---------------------------------------------------------------------------*/
/*
* Solovay-Strassen primality test. Returns true if number p is prime.
*
* Param p - number to be tested.
* Param iteration - iteration count, defines prime certainty.
*/
bool solovayStrassen(mpz_t p, int iteration, gmp_randstate_t randState)
{
mpz_t temp;
mpz_init(temp);
mpz_t temp2;
mpz_init(temp2);
mpz_t a;
mpz_init(a);
int jacob;
if (mpz_cmp_ui(p, 2) < 0) {
return false;
}
mpz_mod_ui(temp, p, 2);
if ((mpz_cmp_ui(p, 2) != 0) && (mpz_cmp_ui(temp, 0) == 0)) {
return false;
}
int i;
for (i = 0; i < iteration; i++) {
mpz_sub_ui(temp2, p, 2);
mpz_urandomm(temp, randState, temp2); // temp = <0, p-3>
mpz_add_ui(a, temp, 2); // temp = temp + 2 ... <2, p-1>
// gmp_printf("a = %Zd\n", a);
// gmp_printf("p = %Zd\n", p);
jacob = jacobi(a, p);
if (jacob == 1) {
mpz_add_ui(temp, p, 1);
} else if (jacob == -1) {
mpz_sub_ui(temp, p, 1);
} else {
mpz_set(temp, p);
}
mpz_mod(temp, temp, p);
// gmp_printf("temp (jacobian) = %Zd\n", temp);
mpz_set(temp2, p);
mpz_sub_ui(temp2, temp2, 1);
mpz_fdiv_q_ui(temp2, temp2, 2);
// gmp_printf("temp2 = %Zd\n", temp2);
modExp(temp2, a, temp2, p);
// printf("jacobi = %i\n", jacobi(a, p));
// gmp_printf("temp2 = %Zd\n", temp2);
if ((jacob == 0) || (mpz_cmp(temp2, temp) != 0)) {
return false;
}
}
return true;
}
/*---------------------------------------------------------------------------*/
/*
* Generates prime number n with certain probability.
* Number n has bitCount bits.
*
* Param n - probably prime number.
* Param bitCount - bit count of n
* Param randState - settings of random number generator.
.
*/
void generateRsaFactor(mpz_t n, int bitCount, gmp_randstate_t randState) {
while (1) {
mpz_urandomb(n, randState, bitCount);
// gmp_printf("nahodne cislo je %Zd\n", n);
mpz_setbit(n, bitCount - 1);
mpz_setbit(n, bitCount - 2);
// gmp_printf("nahodne cislo po nastaveni bitu je %Zd\n", n);
if (solovayStrassen(n, 30, randState)) { // It is prime
break;
}
}
}
/*---------------------------------------------------------------------------*/
/*
* Counts modular multiplicative inverse and store result in param res.
* Returns true if result was correctly counted, otherwise false.
*
* Param res - result.
* Param A - number.
* Param M - modulus.
*/
bool modMulInverse(mpz_t res, mpz_t A, mpz_t M)
{
mpz_t m0, t, q, x0, x1, a, m;
mpz_init(m0);
mpz_init(t);
mpz_init(q);
mpz_init(x0); // Already set to 0
mpz_init(x1);
mpz_init(a);
mpz_init(m);
mpz_set(m0, m);
mpz_set_si(x1, 1);
mpz_set(a, A);
mpz_set(m, M);
if (mpz_cmp_ui(m, 1) == 0) {
mpz_set_si(res, 0);
}
while (mpz_cmp_ui(a, 1) > 0) {
mpz_fdiv_q(q, a, m);
mpz_set(t, m);
mpz_mod(m, a, m);
mpz_set(a, t);
mpz_set(t, x0);
mpz_mul(x0, q, x0);
mpz_neg(x0, x0);
mpz_add(x0, x1, x0);
mpz_set(x1, t);
}
if (mpz_cmp_ui(x1, 0) < 0) {
mpz_add(x1, x1, m0);
return false;
}
mpz_set(res, x1);
return true;
}
/*---------------------------------------------------------------------------*/
/*
* Generate and print RSA keys in hexa format:
* P Q N E D
*
* Param bitModulusCount - bit size of required public modulus.
*/
void generateKeys(int bitModulusCount)
{
mpz_t p, q, n, fiN, d, e, temp;
mpz_init(p);
mpz_init(q);
mpz_init(n);
mpz_init(fiN);
mpz_init(d);
mpz_init(e);
mpz_init(temp);
int pBit, qBit;
gmp_randstate_t randState;
gmp_randinit_mt(randState);
gmp_randseed_ui(randState, time(NULL));
pBit = bitModulusCount / 2;
if (bitModulusCount % 2 == 0) {
qBit = pBit;
} else {
qBit = pBit + 1;
}
while (true) {
generateRsaFactor(p, pBit, randState);
generateRsaFactor(q, qBit, randState);
// gmp_printf("nahodne cislo je %Zd\n", p);
// mpz_setbit(p, pBit - 1);
// mpz_setbit(p, pBit - 2);
// gmp_printf("nahodne cislo po nastaveni bitu je %Zd\n", p);
// gmp_printf("nahodne cislo po nastaveni bitu je %Zd\n", q);
mpz_mul(n, p, q);
// gmp_printf("modulus je %Zd\n", n);
mpz_sub_ui(p, p, 1);
mpz_sub_ui(q, q, 1);
mpz_mul(fiN, p, q);
mpz_add_ui(p, p, 1);
mpz_add_ui(q, q, 1);
// gmp_printf("FI n je %Zd\n", fiN);
mpz_set_ui(e, 65537); // Set public exponent to constant
mpz_mod(temp, fiN, e);
if (mpz_cmp_ui(temp, 0) == 0) {
continue;
}
if (!modMulInverse(d, e, fiN)) {
continue;
}
break;
}
// gmp_printf("Modular inverse je %Zd\n", d);
// gmp_printf("%Zd %Zd %Zd %Zd %Zd\n", p, q, n, e, d); // Decadic print
gmp_printf("0x%Zx 0x%Zx 0x%Zx 0x%Zx 0x%Zx\n", p, q, n, e, d);
}
/*---------------------------------------------------------------------------*/
/*
* Tato funkce neni implementovana - vynalozena prace neodpovida bodovemu hodnoceni.
* Factorization of given modulus N.
* Prints factor P in hexa format.
*
* Param N - string containing hex value (starting 0x) of modulus.
*/
void breakRSA(char *N)
{
}
/*---------------------------------------------------------------------------*/
/*
* Encrypt message M, given public exponent E and public modulus N.
* C = M^E mod N
* Prints ciphertext C in hexa format.
*
* Params are strings in hexa format.
*/
void encrypt(char *E, char *N, char *M)
{
mpz_t c, e, n, m;
mpz_init(c); // Default init is to 0
mpz_init_set_str(e, E, 0);
mpz_init_set_str(n, N, 0);
mpz_init_set_str(m, M, 0);
modExp(c, m, e, n);
gmp_printf("0x%Zx\n", c);
mpz_clear(c);
mpz_clear(e);
mpz_clear(n);
mpz_clear(m);
}
int main(int argc, char**argv)
{
if (argc == 3) {
if (strcmp(argv[1], "-g") == 0) {
generateKeys(atoi(argv[2]));
} else {
fprintf(stderr, "Invalid option!\n");
}
} else if (argc == 5) {
if (strcmp(argv[1], "-e") == 0 || strcmp(argv[1], "-d") == 0) {
encrypt(argv[2], argv[3], argv[4]);
} else {
fprintf(stderr, "Invalid option!\n");
}
} else {
fprintf(stderr, "Bad number of params!\n");
}
return 0;
}