美文网首页
ElGamal加密与解密——gmp库c++实现

ElGamal加密与解密——gmp库c++实现

作者: 201710 | 来源:发表于2017-11-18 10:42 被阅读0次

先讲一下ElGamal 密码体制:

公开全局量
q    素数
a    a<q且a是q的素根
Alice 生成的密钥
选择私钥XA    XA<q-1
计算YA        YA=a^XA mod q
公开密钥      {q,a,YA}
Box用Alice的公钥加密
明文          M
随机选择整数k   k<q
计算K     K=(YA)^k mod q
计算c1   c1=a^k mod q
计算c2   c2=KM mod q
密文     (c1,c2)
用Alice的私钥解密
密文     M
计算K   K=(c1)^XA mod q
明文    M=(c2*K^(-1)) mod q

思路根据以上,直接贴代码(有点长,不好的地方多多包涵和指出~)

#include<gmpxx.h>
#include<gmp.h>
#include<iostream>
#include<cmath>
#include<time.h>
using namespace std;
//快速幂取模运算。简单参考另一篇文章用大数实现RSA选择密文攻击(可以直接用gmp库的函数mpz_powm())
mpz_class fun(const mpz_class exponent,const mpz_class base,const mpz_class n)//base^exponent%n
{  
     mpz_class e,b,temp=1,remainder=0;  
     e=exponent;b=base;
     while(e>=1)
      {
          if(e==1)//当指数为1时,得出结果
            { 
               remainder=(temp*b)%n;
               return remainder;//返回结果
            }
           else if(e%2==0)//如果指数为偶数,将底数平方取模,指数除2
             {
               e=e/2;
               b=(b*b)%n;
             }
           else if(e%2==1)//如果指数为奇数,先提取一个底数相乘并取模,指数减1
             {
               temp=(b*temp)%n;
               e=e-1;
             }
      }  
 }  

在素数域中求乘法逆元。

mpz_class exgcd(mpz_class x,mpz_class q)//拓展欧几里德算法(辗转相除法)在GF(q)中求乘法逆元x^(-1)
{
    mpz_class r,d,t1,t2;
    mpz_class a1=1,a2=0,a3=q;//GF(p)的加法和乘法单位元分别是0和1
    mpz_class b1=0,b2=1,b3=x;
    while(1)
     {
       if(b3==0)
          cout<<"error"<<endl;
       if(b3==1)
          break;
       d=a3/b3;
       r=a3-d*b3;
       t1=a1-d*b1;
       t2=a2-d*b2;
       a3=b3;
       b3=r;
       a1=b1;
       b1=t1;
       a2=b2;
       b2=t2;
     }
   return (b2+q)%q;
}

有限域生成元的寻找方法,思路写得较简单。在此附上别人的博客链接,希望可以帮助看懂。(http://guoreason.blog.163.com/blog/static/234587682007159432178/

void Gfun(mpz_class q,mpz_class p)//好像q没有什么作用,应该可以去掉?懒得改了 
{
     mpz_class i,count=0;
     for(i=2;i<p-1;i++)
        if((i*i%p!=1)&&fun((p-1)/2,i,p)!=1)//a^2 mod p和a^(q-1)/2 mod p,如它们都不等于1,则a是生成元
           {
            cout<<i<<",";
            count=count+1;
            if(count==10)//在这里我只需输出10个生成元
                return;
            }
}
//随机素数的生成
mpz_class randbits(int bits)//base=2
{
    gmp_randclass a(gmp_randinit_default);
    a.seed(rand());
    mpz_class l(bits);
    return a.get_z_bits(l);
}
inline mpz_class randprime(int bits)
{
    mpz_class a=randbits(bits);
    mpz_class ret;
    mpz_nextprime(ret.get_mpz_t(),a.get_mpz_t());
    return ret;
}
int main()
{
   mpz_class q,a,XA,YA,M,k,K,c1,c2;
   int bits;
   cout<<"输入大数比特数:";
   cin>>bits;
   q=randprime(bits);
   cout<<"素数q:"<<q<<endl;
   cout<<"生成元:";
   Gfun((q-1)/2,q);
   cout<<"\n请输入q的素根a:";
   cin>>a;
   srand(time(0));
   XA=rand()%(q-2)+2;//随机产生一个2~q-1的数XA私钥
   YA=fun(XA,a,q);//YA=a^XA mod q  //公钥{q,a,YA}
   cout<<"请输入明文M(M<q):";
   cin>>M;
   while(M>=q)
    {
       cout<<"error!\n请重新输入明文M:";
       cin>>M;
     }
   //加密算法
   k=rand()%(q-1)+1;//随机产生一个1~q-1的数k
   K=fun(k,YA,q);//K=YA^k mod q
   c1=fun(k,a,q);//c1=a^k mod q
   c2=(K*M)%q;//c2=K*M mod q
   cout<<"加密后的密文为:("<<c1<<" , "<<c2<<")"<<endl;
   //解密算法
   K=fun(XA,c1,q);//K=c1^XA mod q
   cout<<"解密后的明文为:"<<(c2*exgcd(K,q))%q<<endl;//M=(c2*K^(-1)) mod q
   return 0;
}

终端命令

g++ ElGamal.cpp -o ElGamal -lgmp -lgmpxx -lm 
./ElGamal

代码有些长(不是一般的长?),用mpz_t可能不会这么长(?),但是我习惯用mpz_class,因为容易理解,哈哈哈。写得不好或者有误欢迎指正,不过我可能会没听懂你的指正,菜鸟一枚~

相关文章

网友评论

      本文标题:ElGamal加密与解密——gmp库c++实现

      本文链接:https://www.haomeiwen.com/subject/yjynmxtx.html