码迷,mamicode.com
首页 > 其他好文 > 详细

rsa_gmp

时间:2020-11-24 12:38:56      阅读:6      评论:0      收藏:0      [点我收藏+]

标签:mod   就是   ini   测试   一个   大数   art   default   can   

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "gmp.h"

#define MILLER_RABIN_TEST_NUM 5
#define PRIME_BIT 512
#define CLOCKS_PER_SEC 1

typedef unsigned char Bit8;
typedef unsigned short Bit16;
typedef unsigned int Bit32;
void getRSAparam(mpz_t n, mpz_t p, mpz_t q, mpz_t e, mpz_t d);
void getPrime(mpz_t n);
int MillerRabin(const mpz_t n);
void PowerMod(const mpz_t a, const mpz_t b, const mpz_t n, mpz_t s);
int SetTestNum(const mpz_t n);
int getModInverse(const mpz_t n, const mpz_t e, mpz_t d);
void ChineseRemainderTheorem(const mpz_t a, const  mpz_t b, const  mpz_t p, const mpz_t q, mpz_t s);
void MontPowerMod(const mpz_t a, const mpz_t b, const mpz_t n, mpz_t s);
void MontMult(mpz_t A, mpz_t B, const mpz_t n, int n_bit, const mpz_t IN);
void RSA_CMP(mpz_t n, mpz_t p, mpz_t q, mpz_t e, mpz_t d);

//获取RSA算法的5个参数
void getRSAparam(mpz_t n, mpz_t p, mpz_t q, mpz_t e, mpz_t d)
{
    double long start, end;
    //获取前三个参数n,p,q
    do
    {
        getPrime(p);
        getPrime(q);
    }
    while (!mpz_cmp(p, q));    //p!=q
    gmp_printf("find p q done\n");
    mpz_mul(n, p, q);

    //获取d,e
    mpz_t p_1, q_1, n_1;   //分别代表φ(p), φ(q), φ(n)
    mpz_inits(p_1, q_1, n_1, NULL); //初始化
    mpz_sub_ui(p_1, p, 1);  //φ(p)=p-1
    mpz_sub_ui(q_1, q, 1);  //φ(q)=q-1
    mpz_mul(n_1, p_1, q_1);  //φ(n)=(p-1)(q-1)

    gmp_randstate_t state;
    gmp_randinit_default(state);//对state进行初始化
    gmp_randseed_ui(state, /*time(NULL)*/rand());//对state置初始种子

    while (1)
    {
        mpz_urandomm(e, state, n_1);   //产生随机数0=<b<=φ(n), 生成公钥
        if (getModInverse(e, n_1, d))  //使用求e模φ(n)的逆d, 作为私钥
            break;
    }

    mpz_clears(n_1, p_1, q_1, NULL);
    gmp_randclear(state);
}

//获取一个大整数,大小默认为512bit
void getPrime(mpz_t n)
{
    int i, random = 0;
    //srand(time(NULL));
    char rand_num[PRIME_BIT + 1]; //用于存放512bit的随机数
    rand_num[PRIME_BIT] = \0;
    rand_num[0] = 1;  //第一个bit设置为1,保证生成的是512位的素数
    rand_num[1] = 1;  //第二个bit设置为1,保证相乘后是1024位的素数
    rand_num[PRIME_BIT - 1] = 1;  //最后一bit设置为1,保证是奇数
    while(1)
    {
        for (i = 2; i < PRIME_BIT - 1; i++)
        {
            random = rand();
            rand_num[i] = 0 + (0x1 & random);
        }
        mpz_set_str(n, rand_num, 2);
        if (SetTestNum(n))
            break;
    }
}

//设置素性检测的次数,并调用MillerRabin算法进行检测
int SetTestNum(const mpz_t n)
{
    for (int i = 0; i < MILLER_RABIN_TEST_NUM; i++)
        if (!MillerRabin(n))
            return 0;
    return 1;
}

//MillerRabin算法进行素性检测
int MillerRabin(const mpz_t n)
{
    gmp_randstate_t state;
    gmp_randinit_default(state);         //对state进行初始化
    gmp_randseed_ui(state, rand()/*time(NULL)*/);  //对state置初始种子

    mpz_t m, a, b, flag, n_1;
    mpz_inits(m, a, b, flag, n_1, NULL);  //初始化

    mpz_sub_ui(m, n, 1);      //m=n-1
    mpz_mod_ui(flag, m, 2);  //flag=m%2
    mpz_sub_ui(n_1, n, 1);    //n_1=n-1=-1mod n

    //下面计算二次探测的最大次数, φ(n)=n-1=2^r*m, m为奇数
    int r = 0;
    //计算r, 将n-1表示成m*2^r
    while (!mpz_tstbit(m, 1))  //测试最后一位,为1说明是奇数,终止循环。为0则说明是偶数,继续循环
    {
        mpz_tdiv_q_2exp(m, m, 1);    //m右移一位, 即m=m/2
        r++;
    }
    //随机生成一个[1,n-1]之间的随机数
    mpz_urandomm(a, state, n_1);   //产生随机数a, 0<=a<=n-2
    mpz_add_ui(a, a, 1);           //a=a+1,此时1<=a<=n-1
    PowerMod(a, m, n, b);          //计算出b=a^m mod n
    if (!mpz_cmp_ui(b, 1))     //若a^m=1, 则说明通过二次探测, 直接返回
    {
        mpz_clears(m, flag, n_1, a, b, NULL); //清理申请的大数空间
        gmp_randclear(state);
        return  1;
    }
    //n-1表示成m*2^r,如果n是一个素数,那么或者a^m mod n=1,
    //或者存在某个i使得a^(m*2^i) mod n=n-1 ( 0<=i<r )
    for (int i = 0; i < r; i++)
    {
        if (!mpz_cmp(b, n_1))    //若b=n-1,说明符合二次探测,返回true
        {
            mpz_clears(m, flag, n_1, a, b, NULL);
            gmp_randclear(state);
            return  1;
        }
        else
        {
            mpz_mul(b, b, b);//b=b^2;
            mpz_mod(b, b, n);//b=b mod n;
        }
    }

    mpz_clears(m, flag, n_1, a, b, NULL);
    gmp_randclear(state);
    return 0;
}

//模重复平方法,计算a^b(mod n),并将结果赋值给s
void PowerMod(const mpz_t a, const mpz_t b, const mpz_t n, mpz_t s)
{

    mpz_t t1, t2, t3;
    mpz_inits(t1, t2, t3, NULL);
    mpz_set_ui(t1, 1);  //t1=1;
    mpz_set(t2, a);    //t2=a;
    mpz_set(t3, b);    //t3=b;

    while (mpz_cmp_ui(t3, 0))
    {

        if (mpz_tstbit(t3, 0))  //测试t3二进制的最后一位,若为1则说明 t3 mod 2=1
        {
            //t1 = (t1*t2) mod n
            mpz_mul(t1, t1, t2);
            mpz_mod(t1, t1, n);
        }

        //t2 = (t2*t2) mod n
        mpz_mul(t2, t2, t2);
        mpz_mod(t2, t2, n);

        mpz_tdiv_q_2exp(t3, t3, 1); // 指数t3右移1位,即t3=t3/2
    }

    mpz_set(s, t1); //将最后的结果t1赋值给s
    mpz_clears(t1, t2, t3, NULL);

}

//使用拓展欧几里得算法求e的模n的逆元d
int getModInverse(const mpz_t e, const mpz_t n, mpz_t d)
{
    mpz_t a, b, c, c1, t, q, r;
    mpz_inits(a, b, c, c1, t, q, r, NULL);
    mpz_set(a, n);//a=n;
    mpz_set(b, e);//b=e;
    mpz_set_ui(c, 0);//c=0
    mpz_set_ui(c1, 1);//c1=1
    mpz_tdiv_qr(q, r, a, b);
    while (mpz_cmp_ui(r, 0))//r==0终止循环
    {
        mpz_mul(t, q, c1);//t=q*c1
        mpz_sub(t, c, t);//t=c-q*c1

        mpz_set(c, c1);   //c=c1  向后移动
        mpz_set(c1, t);   //c1=t  向后移动

        mpz_set(a, b);//a=b 除数变为被除数
        mpz_set(b, r);//b=r 余数变为除数,开始下一轮
        mpz_tdiv_qr(q, r, a, b);  //取下一个q
    }
    mpz_set(d, t);  //将最后一轮的t赋值给d, d就是e的模n的逆元

    //保证返回正整数
    mpz_add(d, d, n);
    mpz_mod(d, d, n);

    mpz_clears(a, c, t, q, r, NULL);

    if (mpz_cmp_ui(b, 1))
    {
        mpz_clear(b);
        return 0;
    }
    else
    {
        mpz_clear(b);
        return 1;
    }
}

//中国剩余定理
void ChineseRemainderTheorem(const mpz_t a, const  mpz_t b, const  mpz_t p, const mpz_t q, mpz_t s)
{
    mpz_t x, y, p_0, q_0, p_1, q_1, t1, t2, n;
    mpz_inits(x, y, p_0, q_0, p_1, q_1, t1, t2, n, NULL);

    mpz_sub_ui(p_0, p, 1);  //p_0=p-1,p_0即φ(p)
    mpz_sub_ui(q_0, q, 1);  //q_0=q-1,q_0即φ(q)
    mpz_mod(p_0, b, p_0);   //p_0=b mod p_0,  即p_0=b mod φ(p)
    mpz_mod(q_0, b, q_0);   //q_0=b mod q_0,  即q_0=b mod φ(q)

    //PowerMod(a, p_0, p, x);//x=a^b%p
    //PowerMod(a, q_0, q, y);//y=a^b%q

    mpz_powm(x, a, p_0, p);
    mpz_powm(y, a, q_0, q);


    getModInverse(p, q, p_1);//求p模q的逆
    getModInverse(q, p, q_1);//求q模p的逆

    //mpz_invert(q_1, p, q);//求p模q的逆
    //mpz_invert(p_1, q, p);//求p模q的逆
    //getModInverse(q, p, p_1);//求q模p的逆
    //gmp_printf("*********%Zx", q_1);
    //gmp_printf("*********%Zx", q_1);

    //s=(x*q*q_1 + y*p*p_1) mod n

    mpz_mul(t1, x, q);    //t1=x*q
    mpz_mul(t1, t1, q_1); //t1=x*q*q_1
    mpz_mul(t2, y, p);    //t2=y*p
    mpz_mul(t2, t2, p_1); //t2=y*p*p_1

    mpz_add(s, t1, t2);   //中国剩余定理:(t1+t2)mod n
    mpz_mul(n, p, q);
    mpz_mod(s, s, n);

    mpz_clears(x, y, p_0, q_0, p_1, q_1, t1, t2, n, NULL);
}

//Montgomery算法,计算a^b(mod n),并将结果赋值给s
void MontPowerMod(const mpz_t a, const mpz_t b, const mpz_t n, mpz_t s)
{
    mpz_t R, R1, Prod, A, IN, B, e;
    mpz_inits(R, R1, Prod, A, IN, B, e, NULL);

    mpz_set(e, b);

    //IN= -n^(-1) mod 2^32
    mpz_ui_pow_ui(B, 2, 32); //B=2^32
    getModInverse(n, B, IN); //IN=n^(-1) mod B
    mpz_sub(IN, B, IN);   //-n^(-1)= B-n^(-1) mod B

    //生成比模n略大的参数R=2^n_bit
    int n_bit = mpz_sizeinbase(n, 2);
    mpz_ui_pow_ui(R, 2, n_bit);

    //Prod=Mont(1),A=Mont(a)
    mpz_mul_ui(Prod, R, 1);
    mpz_mod(Prod, Prod, n);
    mpz_mul(A, R, a);
    mpz_mod(A, A, n);

    while (mpz_cmp_ui(e, 0))
    {
        if (mpz_tstbit(e, 0))
            MontMult(Prod, A, n, n_bit, IN);
        MontMult(A, A, n, n_bit, IN);
        mpz_tdiv_q_2exp(e, e, 1); //e=e>>1
    }

    //s=MontInv(Prod)=Prod*R(-1) mod n
    getModInverse(R, n, R1);
    mpz_mul(Prod, Prod, R1);
    mpz_mod(Prod, Prod, n);
    mpz_set(s, Prod);

    mpz_clears(R, R1, Prod, A, IN, B, e, NULL);
}

//蒙哥马利模乘,A=(A*B)mod n
void MontMult(mpz_t A, mpz_t B, const mpz_t n, int n_bit, const mpz_t IN)
{
    mpz_t T, T1, t0, b_32;
    mpz_inits(T, T1, t0, b_32, NULL);

    mpz_mul(T, A, B);  //T=A*B
    mpz_set_ui(b_32, 0xFFFFFFFF);

    int t = n_bit >> 5;
    for(int i = 0; i < t; i++)
    {
        mpz_and(t0, T, b_32);
        mpz_mul(t0, IN, t0);
        mpz_and(t0, t0, b_32);

        //T1=T+n*t0
        mpz_mul(T1, n, t0);
        mpz_add(T1, T, T1);

        //T1>>32,T=T1
        mpz_tdiv_q_2exp(T1, T1, 32);
        mpz_set(T, T1);

    }

    if (mpz_cmp(T1, n) > 0)   //T1>n,A=T1-n
    {
        mpz_sub(T1, T1, n);
        mpz_set(A, T1);
    }
    else
        mpz_set(A, T1);
    mpz_clears(T, T1, t0, b_32, NULL);
}

int main(void)
{
    int cmd = 0, find_pqed = 0, plain_in=0;

    mpz_t n, p, q, e, d;
    mpz_inits(n, p, q, e, d, NULL);

    mpz_t x, y, tmp;
    mpz_inits(x, y, tmp, NULL);
    
    while(1)
    {
        gmp_printf("\n===================请输入命令=================\n");
        gmp_printf("  1.生成RSA的5个参数  2.获取明文数据  3.模重复平方  4.中国剩余定理  5.Montgomery  0.退出\n");

        scanf("%d", &cmd);
        if((!find_pqed || !plain_in) && (cmd==4 || cmd==5 || cmd==6))
        {
            gmp_printf("初始化未完成 find_pqed=%d, plain_in=%d\n", find_pqed, plain_in);
            continue;
        }
        switch (cmd)
        {
        case 1:
            gmp_printf("\n正在获取5个参数,请等待......\n\n");
            getRSAparam(n, p, q, e, d); //获得RSA的5个参数
            find_pqed = 1;
            gmp_printf("Hex: %Zx\n\n", p);
            gmp_printf("Hex: 0x%Zx\n\n", q);
            gmp_printf("Hex: 0x%Zx\n\n", n);
            gmp_printf("Hex: 0x%Zx\n\n", e);
            gmp_printf("Hex: 0x%Zx\n\n", d);
            break;
        case 2:
            gmp_printf("\n  请输入将要被加密的数据(请输入整数):\n  ");
            gmp_scanf("%Zx", x);
            plain_in = 1;
            break;
        case 3:
            PowerMod(x, e, n, y);  //使用公钥e加密明文x,得到密文y
            gmp_printf("密文为:\n  %Zx\n\n", y);
            PowerMod(y, d, n, tmp);
            gmp_printf("解密后,明文为:\n  %Zx\n", tmp);
            break;
        case 4:
            PowerMod(x, e, n, y);
            gmp_printf("密文为:\n  %Zx\n\n", y);
            ChineseRemainderTheorem(y, d, p, q, tmp);
            gmp_printf("解密后,明文为:\n  %Zx\n", tmp);
            break;
        case 5:
            MontPowerMod(x, e, n, y);  //使用公钥e加密明文x,得到密文y
            gmp_printf("密文为:\n  %Zx\n\n", y);
            MontPowerMod(y, d, n, tmp);
            gmp_printf("解密后,明文为:\n  %Zx\n", tmp);
            break;
        case 0:
            goto EXIT;
            break;
        default:
            break;
        }
        gmp_printf("按回车继续......");
        getchar();
        getchar();
    }
EXIT:
    mpz_clears(n, p, q, e, d, NULL);
    return 0;
}

 

rsa_gmp

标签:mod   就是   ini   测试   一个   大数   art   default   can   

原文地址:https://www.cnblogs.com/to7str/p/14010344.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!