現代密碼學實驗5 數字簽名ElGamal簽名方案

讚賞碼 & 聯繫方式 & 個人閒話

【實驗名稱】數字簽名ElGamal簽名方案

 

【實驗目的】

1、瞭解數字簽名的過程,包括簽名過程和認證過程;

2、掌握ElGamal簽名方案。

 

【實驗原理】

ElGamal公鑰密碼算法是在密碼協議中有着重要應用的一類公鑰密碼算法,它是基於1985年提出的公鑰密碼體制和橢圓曲線加密體系,其安全性是基於有限域上離散對數學問題的難解性。它至今仍是一個安全性良好的公鑰密碼算法。它既可用於加密又可用於數字簽名的公鑰密碼體制。

數字簽名就是附加在數據單元上的一些數據,或是對數據單元所作的密碼變換。這種數據或變換允許數據單元的接收者用以確認數據單元的來源和數據單元的完整性並保護數據,防止被人(例如接收者)進行僞造。

 

【實驗內容】

實驗內容: 生成各自的密鑰,並公佈給相鄰同學自己的公鑰(p,g,y),A和B之間約定簽署的消息m(如學號),A簽署消息m,將三元組(m,r,s)發給B,B驗證簽名。

代碼:(代碼解釋見代碼中註釋)

#include<iostream>
#include<time.h>
using namespace std;
#define  LL long long

//冪次運算,含模運算,防止溢出
LL My_Pow(LL a, LL m, LL input)
{
	LL result = 1;
	for (LL i = 0; i < m; i++)
	{
		result = (result*a) % input;
	}
	return result;
}

//用輾轉相除法求最大公約數
LL gcd(LL a, LL b)
{
	LL temp = b;
	while (a%b != 0)
	{
		temp = a % b;
		a = b;
		b = temp;
	}
	return temp;
}

//擴展歐幾里得法,遞歸法
LL extend(LL a, LL b, LL&x, LL&y)
{
	if (b == 0)
	{
		x = 1;
		y = 0;
		return a;
	}
	LL r = extend(b, a % b, x, y);
	LL t = x;
	x = y;
	y = t - a / b * y;
	return r;
}

//藉助遞歸擴展歐幾里得求逆
LL inv(LL a, LL b)
{
	LL x, y;
	LL r = extend(a, b, x, y);
	if (r != 1)
	{
		return 0;
	}
	x = x % b;
	if (x < 0)
	{
		x = x + b;
	}
	return x;
}


int main()
{
	//密鑰產生
	cout << "***   密鑰產生環節   ***" << endl;
	LL p, g;
	cout << "請輸入大素數p和本原根g:";
	cin >> p >> g;
	srand((unsigned)time(NULL));
	LL x = 0;
	while (x <= 0)
	{
		x = rand() % (p - 1);
	}
	cout << "祕密整數x隨機選擇完畢" << endl;
	LL y = My_Pow(g, x, p);
	cout << "公鑰計算完畢" << endl;
	cout << "公鑰爲:(" << p << "," << g << "," << y << ")" << endl;

	//數字簽名
	LL m;
	cout << "\n***   數字簽名環節   ***" << endl;
	cout << "請輸入簽名消息m:";
	cin >> m;
	LL k = 0;
	while (gcd(k, p - 1) != 1 || k <= 0)
	{
		k = rand() % (p - 1);
	}
	cout << "安全隨機數k選擇完畢" << endl;
	LL r = My_Pow(g, k, p);
	//cout << k<<" "<<inv(k, p-1) << (m - x * r)<<endl;
	LL s = inv(k, p - 1)*(m - x * r) % (p - 1);
	//cout << s << endl;
	if (s < 0)
	{
		s = s + p - 1;
	}
	cout << "簽署消息生成完畢" << endl;
	cout << "簽署消息爲:(" << m << "," << r << "," << s << ")" << endl;

	cout << "\nA將簽名傳送給B" << endl;

	//簽名驗證
	cout << "\n***   簽名驗證環節   ***" << endl;
	cout << "請輸入收到的簽署消息:";
	cin >> m >> r >> s;
	LL temp1, temp2;
	temp1 = My_Pow(y, r, p);
	temp2 = My_Pow(r, s, p);
	LL v1 = (temp1 * temp2) % p;
	LL v2 = My_Pow(g, m, p);
	cout << "開始驗證..." << endl;
	cout << "結果:v1 = " << v1 << "  v2 = " << v2 << endl;
	if (v1 == v2)
	{
		cout << "經驗證,該簽名有效\n" << endl;
	}
	else
	{
		cout << "請注意簽名已失效!\n" << endl;
	}

	return 0;
}

運行演示:

 

【小結或討論】

這次實驗總體難度不是很大,我覺得重要的是理解ElGamal加密算法和數字簽名算法。密碼學的很多加密算法都對離散數學有着很高的要求,但是這一部分又是十分抽象晦澀的,即使我們學過離散數學和信息安全數學基礎,對密碼學裏的很多算法理解上也是會遇到不小的困難的,所以這就需要反覆琢磨,仔細思考,而且還需要時常溫習。

這次算法其實比之前的加密算法要容易懂一些,我覺得ElGamal設計的十分巧妙,利用了有限域上離散對數的困難性,通過模數的逆在雙方都不知道具體密鑰數值的情況下,卻能實現祕密信息的準確傳達,而且利用的還是隨機密鑰,這就意味着即使相同的明文加密後的密文每次也是不一樣的,這又進一步加強了算法的安全性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章