ElGamal公钥密码算法及ElGamal数字签名方案实现
ElGamal公钥密码算法是在密码协议中有着重要应用的一类公钥密码算法,其安全性是基于有限域上离散对数学问题的难解性。它至今仍是一个安全性良好的公钥密码算法。它既可用于加密又可用于数字签名的公钥密码体制。
一、ElGamal公钥密码算法描述
1. 选取一个大素数p,使离散对数问题在有限域GF(p)上是难解的,选取g∈Z是一个本原元。
2. 随机选取整数x,1≤x≤p-2,计算y=g^x(mod p); y是公开的加密密钥,而x是保密的脱密密钥。
3. 明文空间为Z,密文空间为Z×Z。
4. 加密变换:对任意明文m∈Z,秘密地随机选取一个整数k,1≤k≤p-2,于是可得密文为:
c=(c1,c2)
其中
c1=g^k(mod p) , c2=my^k(mod p)
5. 脱密变换:对任意密文c=(c1,c2)∈Z×Z,明文为:
m=c2×(c1^x)^-1(mod p)
证明:
c2×(c1^x)^-1(mod p)=my^k(g^(kx))^-1 (mod p)
=mg^kx × g^(-kx) (mod p)=m (mod p)
二、ElGamal数字签名方案
1. 生成乘法群Z中的一个生成元g,p,g公开。
2. 随机选取整数x,1≤x≤p-2,计算y=g^x(mod p),y是公开密钥,而x是保密密钥。
3. 签名算法:设m∈Z是待签名的消息,秘密随机选取一个整数k,1≤k≤p-2,且(k,p-1)=1,计算
r=g^k(mod p)
s=k^-1(m-rx)(mod p-1)
则(m,r,s)为对消息m的数字签名。
4. 验证算法:对方收到对消息m的数字签名(m,r,s)后,利用签名者的公开密钥y,g,p可对签名进行以下验证:
(y^r)(r^s)=g^m(mod p)
如果上式成立,则接受该签名,否则拒绝该签名。
对m正确签名,那么有:
(y^r)(r^s)(mod p)=g^(rx+sk)(mod p)
=g^(rx+m-rx)(mod p)
=g^m (mod p)
三、ElGamal数字签名方案实现
为简化问题,我们取p=19,g=2,私钥x=9,则公钥y=29 mod 19=18。C++代码实现如下:
BigInt.h
#ifndef BIGINT_H_INCLUDED
#define BIGINT_H_INCLUDED
#include <iostream>
#include <string>
#include <cstdlib>
#include <algorithm>//reverse函数所需添加的头文件
using namespace std;
/*
大整数类
*/
class BigInt
{
private:inline int compare(string s1, string s2){if(s1.size() < s2.size())return -1;else if(s1.size() > s2.size())return 1;elsereturn s1.compare(s2);}
public:bool flag;//true表示正数,false表示负数,0默认为正数string values;//保存所有位上的数字BigInt():values("0"),flag(true){};//构造函数BigInt(string str)//类型转换构造函数(默认为正整数){values = str;flag = true;}
public:friend ostream& operator << (ostream& os, const BigInt& bigInt);//重载输出操作符friend istream& operator>>(istream& is, BigInt& bigInt);//输入操作符重载BigInt operator+(const BigInt& rhs);//加法操作重载BigInt operator-(const BigInt& rhs);//减法操作重载BigInt operator*(const BigInt& rhs);//乘法操作重载BigInt operator/(const BigInt& rhs);//除法操作重载BigInt operator%(const BigInt& rhs);//求余操作重载
};
/*
重载流提取运算符'>>',输出一个整数
*/
ostream& operator << (ostream& os, const BigInt& bigInt)
{if (!bigInt.flag){os << '-';}os << bigInt.values;return os;
}
/*
重载流插入运算符'>>',输入一个正整数
*/
istream& operator >> (istream& is, BigInt& bigInt)
{string str;is >> str;bigInt.values = str;bigInt.flag = true;return is;
}
/*
两个正整数相加
*/
BigInt BigInt::operator+(const BigInt& rhs)
{BigInt ret;ret.flag = true;//正整数相加恒为正数string lvalues(values), rvalues(rhs.values);//处理特殊情况if (lvalues == "0"){ret.values = rvalues;return ret;}if (rvalues == "0"){ret.values = lvalues;return ret;}//调整s1与s2的长度unsigned int i, lsize, rsize;lsize = lvalues.size();rsize = rvalues.size();if (lsize < rsize){for (i = 0; i < rsize - lsize; i++)//在lvalues左边补零{lvalues = "0" + lvalues;}}else{for (i = 0; i < lsize - rsize; i++)//在rvalues左边补零{rvalues = "0" + rvalues;}}//处理本质情况int n1, n2;n2 = 0;lsize = lvalues.size();string res = "";reverse(lvalues.begin(), lvalues.end());//颠倒字符串,以方便从低位算起计算reverse(rvalues.begin(), rvalues.end());for (i = 0; i < lsize; i++){n1 = (lvalues[i] - '0' + rvalues[i] - '0' + n2) % 10;//n1代表当前位的值n2 = (lvalues[i] - '0' + rvalues[i] - '0' + n2) / 10;//n2代表进位res = res + char(n1 + '0');}if (n2 == 1){res = res + "1";}reverse(res.begin(), res.end());ret.values = res;return ret;
}
/*
两个正整数相减
*/
BigInt BigInt::operator-(const BigInt& rhs)
{BigInt ret;string lvalues(values), rvalues(rhs.values);//负数减负数if(flag==false&&rhs.flag==false){string tmp = lvalues;lvalues = rvalues;rvalues = tmp;}//负数减正数if(flag==false&&rhs.flag==true){BigInt res(lvalues);ret=res+rhs;ret.flag = false;return ret;}if(flag==true&&rhs.flag==false){BigInt rel(lvalues),res(rhs.values);ret=rel+res;ret.flag = true;return ret;}//处理特殊情况if (rvalues == "0"){ret.values = lvalues;ret.flag = true;return ret;}if (lvalues == "0"){ret.values = rvalues;ret.flag = false;return ret;}//调整s1与s2的长度unsigned int i, lsize, rsize;lsize = lvalues.size();rsize = rvalues.size();if (lsize < rsize){for (i = 0; i < rsize - lsize; i++)//在lvalues左边补零{lvalues = "0" + lvalues;}}else{for (i = 0; i < lsize - rsize; i++)//在rvalues左边补零{rvalues = "0" + rvalues;}}//调整使‘-’号前边的数大于后边的数int t = lvalues.compare(rvalues);//相等返回0,str1<str2返回负数,str1>str2返回正数if (t < 0){ret.flag = false;string tmp = lvalues;lvalues = rvalues;rvalues = tmp;}else if (t == 0){ret.values = "0";ret.flag = true;return ret;}else{ret.flag = true;}//处理本质情况unsigned int j;lsize = lvalues.size();string res = "";reverse(lvalues.begin(), lvalues.end());//颠倒字符串,以方便从低位算起计算reverse(rvalues.begin(), rvalues.end());for (i = 0; i < lsize; i++){if (lvalues[i] < rvalues[i])//不足,向前借一维{j = 1;while(lvalues[i+j] == '0'){lvalues[i+j] = '9';j++;}lvalues[i+j] -= 1;res = res + char(lvalues[i] + ':' - rvalues[i]);}else{res = res + char(lvalues[i] - rvalues[i] + '0');}}reverse(res.begin(), res.end());res.erase(0, res.find_first_not_of('0'));//去掉前导零ret.values = res;return ret;
}/*
两个正整数相乘
*/
BigInt BigInt::operator*(const BigInt& rhs)
{BigInt ret;string lvalues(values), rvalues(rhs.values);//处理0或结果正负if (lvalues == "0" || rvalues == "0"){ret.values = "0";ret.flag = true;return ret;}if(flag==false||rhs.flag==false){ret.flag=false;}//处理特殊情况unsigned int lsize, rsize;lsize = lvalues.size();rsize = rvalues.size();string temp;BigInt res, itemp;//让lvalues的长度最长if (lvalues < rvalues){temp = lvalues;lvalues = rvalues;rvalues = temp;lsize = lvalues.size();rsize = rvalues.size();}//处理本质情况int i, j, n1, n2, n3, t;reverse(lvalues.begin(), lvalues.end());//颠倒字符串reverse(rvalues.begin(), rvalues.end());for (i = 0; i < rsize; i++){temp = "";n1 = n2 = n3 = 0;for (j = 0; j < i; j++){temp = temp + "0";}n3 = rvalues[i] - '0';for (j = 0; j < lsize; j++){t = (n3*(lvalues[j] - '0') + n2);n1 = t % 10;//n1记录当前位置的值n2 = t / 10;//n2记录进位的值temp = temp + char(n1 + '0');}if (n2){temp = temp + char(n2 + '0');}reverse(temp.begin(), temp.end());itemp.values = temp;res = res + itemp;}ret.values = res.values;return ret;
}
/*
两个正整数相除
*/
BigInt BigInt::operator/(const BigInt& rhs)
{BigInt ret;string lvalues(values), rvalues(rhs.values);string quotient;string temp;//处理特殊情况if(rvalues == "0"){ret.values = "error";//输出错误ret.flag = true;return ret;}if(lvalues == "0"){ret.values = "0";ret.flag = true;return ret;}if(compare(lvalues, rvalues) < 0){ret.values = "0";ret.flag = true;return ret;}else if(compare(lvalues, rvalues) == 0){ret.values = "1";ret.flag = true;return ret;}else{//处理本质情况unsigned int lsize, rsize;lsize = lvalues.size();rsize = rvalues.size();int i;if(rsize > 1) temp.append(lvalues, 0, rsize-1);for(i = rsize - 1; i < lsize; i++){temp = temp + lvalues[i];//试商for(char c = '9'; c >= '0'; c--){BigInt t = (BigInt)rvalues * (BigInt)string(1, c);BigInt s = (BigInt)temp - t;if(s.flag == true){temp = s.values;quotient = quotient + c;break;}}}}//去除前导零quotient.erase(0, quotient.find_first_not_of('0'));ret.values = quotient;ret.flag = true;return ret;
}
/*
两个正整数取余
*/
BigInt BigInt::operator%(const BigInt& rhs)
{BigInt ret,kj(values),ki(rhs.values);string lvalues(values), rvalues(rhs.values);string quotient;string temp;//处理特殊情况if(rvalues == "0"){ret.values = "error";//输出错误ret.flag = true;return ret;}if(lvalues == "0"){ret.values = "0";ret.flag = true;return ret;}if(compare(lvalues, rvalues) < 0){if(flag==false){ret.values=(ki-kj).values;ret.flag = true;return ret;}else{ret.values = lvalues;ret.flag = true;return ret;}}else if(compare(lvalues, rvalues) == 0){ret.values = "0";ret.flag = true;return ret;}else{//处理本质情况unsigned int lsize, rsize;lsize = lvalues.size();rsize = rvalues.size();int i;if(rsize > 1) temp.append(lvalues, 0, rsize-1);for(i = rsize - 1; i < lsize; i++){if(temp=="0"){temp=lvalues[i];}else{temp = temp + lvalues[i];}//试商for(char c = '9'; c >= '0'; c--){BigInt t = (BigInt)rvalues * (BigInt)string(1, c);BigInt s = (BigInt)temp - t;if(s.flag == true){//cout<<s.values<<endl;temp = s.values;quotient = quotient + c;break;}}}}//去除前导零quotient.erase(0, quotient.find_first_not_of('0'));ret.values = temp;ret.flag = true;return ret;
}
/*
一个大整数和一个小整数的取余int divMod(string ch,int num)
{int s=0;for(int i=0;ch[i]!='\0';i++)s=(s*10+ch[i]-'0')%num;return s;
}*//*
欧几里德求GCD
*/
BigInt gcd(BigInt a,BigInt b)
{BigInt stemp;//cout<<a<<endl;//cout<<b<<endl;if((a-b).flag==false)//判断大小{stemp.values=a.values;a.values=b.values;b.values=stemp.values;}if(b.values=="0") return a;else return gcd(b,a%b);
}
/*
快速幂
*/
BigInt fast(BigInt a,BigInt b)
{BigInt aa=a,t("1"),k("2");// int b2=atoi(b1[lsize-1].c_str());while(b.values!="0"){if((b%k).values!="0"){t=t*aa;}aa=aa*aa;b=b/k;}return t;
}
/*
快速幂模
*/
BigInt mod_fast(BigInt a,BigInt b,BigInt p)
{BigInt aa=a,t("1"),k("2");// int b2=atoi(b1[lsize-1].c_str());while(b.values!="0"){if((b%k).values!="0"){t=(t%p)*(aa%p)%p;}aa=(aa%p)*(aa%p)%p;b=b/k;}return t%p;
}/*
扩展欧几里德实现乘法逆
*/
BigInt extgcd(BigInt a, BigInt b, BigInt& x, BigInt& y)
{BigInt d(a.values);if(b.values != "0"){d = extgcd(b, a % b, y, x);y = y-(a / b) * x;// cout<<"a:"<<a<<endl;// cout<<"b:"<<b<<endl;// cout<<"x:"<<x<<endl;// cout<<"y:"<<y<<endl<<endl<<endl;}else {x.values = "1";y.values = "0";}return d;
}
BigInt mod_inverse(BigInt a, BigInt m)
{BigInt x, y;extgcd(a, m, x, y);if(x.flag==false){x.flag=true;x=m-x;}return (m + x % m) % m;
}#endif // BIGINT_H_INCLUDED
Main.cpp
#include <iostream>
#include"BigInt.h"using namespace std;int main()
{/*公开密钥y,g,p*/BigInt p("19"),g("2"),x("9"),y("18"),a("1");BigInt k("5"),s,r,m,k1;BigInt t1,t2;cout<<"请输入m:"<<endl;cin>>m;r=mod_fast(g,k,p);k1=mod_inverse(k,p-a);s=((m-x*r)*k1)%(p-a);cout<<"r:"<<r<<endl;cout << "s:"<<s << endl;cout<<"接下来验证签名------->"<<endl;t1=fast(y,r);t2=fast(r,s);cout << "t1:"<<t1<< endl;cout << "t2:"<<t2<< endl;if(((t1*t2)%p).values==mod_fast(g,m,p).values){cout<<"签名成功!"<<endl;}else{cout<<"签名失败!"<<endl;}return 0;
}
四、运行结果
ElGamal公钥密码算法及ElGamal数字签名方案实现相关推荐
- ElGamal公钥密码算法(Python实现)
本文目录 一.实验目的(包括实验环境.实现目标等等) 1. 实验环境 2. 实现目标 二.方案设计(包括背景.原理.必要的公式.图表.算法步骤等等) 1. 背景 2. 离散对数困难问题 3. EIGa ...
- (九)EIGamal公钥密码算法
目录 EIGamal公钥密码算法 一.相关数学基础 二.算法原理 三.算法详细流程 四.特点和安全性 EIGamal公钥密码算法 ElGamal公钥密码算法是1985年由塔希尔·盖莫尔提出,是一个基于 ...
- 信息安全——ELGamal数字签名方案的实现
ELGamal数字签名方案的实现 1. 问题描述 为简化问题,我们取p=19,g=2,私钥x=9,则公钥y=29 mod 19=18.消息m的ELGamal签名为(r,s),其中r=gk mod p, ...
- elgamal签名算法c语言,elgamal数字签名方案
Elgamal算法由T.E1Gamal在1985年发表的一篇论文中提出,是Rabin体制的一种变型.其修正形式已被美国国家标准技术研究所作为数字签名标准(DS),其核心就是著名是数字签名方法(DSA) ...
- ElGamal公钥密码和椭圆曲线密码体制
ElGamal公钥密码 基于有限域上离散对数问题的公钥密码体制,最著名的是ElGamal体制,是由T. ElGamal在1985年提出的 ElGamal有较好的安全性,同一明文在不同时刻会产生不同的密 ...
- elgamal签名算法c语言,ElGamal算法
[声明] 一.本文实用于初学者,目的在于帮助大家熟悉一些系统底层的知识. 二.本文只是为了让广大网友共同提高一些基础知识,本人决无卖弄之意,只供需要这方面知识的读者阅读,如果你是高手,或者不需要这方面 ...
- ELGamal公钥密码
ELGamal公钥密码 密钥产生 加密 解密 举例 Based on Descrete Logarithm Problem(DLP)离散对数问题 密钥产生 1.产生一个大的随机素数p 2.找出Zp的一 ...
- 一个基于RSA算法的Java数字签名例子
====================================================== 注:本文源代码点此下载 ================================= ...
- Schnorr数字签名方案
Schnorr数字签名方案 Schnorr签名算法最初由德国密码学家claus schnorr于2008年提出,在密码学中,它是一种数字签名方案,以其简单著称 Schnorr数字签名方案也是基于离散对 ...
最新文章
- LeetCode 多线程 1117. H2O 生成
- CleanMyMac for mac之偏好设置
- linux改变磁盘顺序,Linux上磁盘顺序混乱的情况
- linux 下如何给火狐安装flash插件(常用命令cd cp tar 实践)
- 快逸报表数据库密码加密解决方案
- python 小程序——快递分拣程序
- 服务器在线测速系统源码_亲测可用
- RT-Thread Studio中使用DHT11软件包
- android跳转QQ陌生人聊天或者加入QQ群
- VB编程:SelectCase多分支选择结构实例测试生肖运势-13
- LDF转Excel;LDF转位定义;Excel转LDF;Excel转位定义;MatrixCreat(一)之LIN矩阵详解
- 【问题解决】win服务器磁盘初始化
- linux全角和半角的切换,全角和半角
- C语言中的循环语句(while、dowhile、for)
- 一个JAVA渣渣的校招成长记,附BAT美团网易等20家面经总结
- BZOJ4755: [JSOI2016]扭动的回文串——题解
- The first record --两次面试
- java实现.费诺编码_信息论编码实验报告费诺编码附源代码
- 2月9号cf,c题 Anu Has a Function
- 怎么把ppt转为html代码,ppt转html格式(示例代码)