基于RSA的消息盲签名(控制台Edition)

盲签名体制是保证参与者匿名性的基本密码协议。自从出现对电子现金技术的研究以来,盲签名已成为其最重要的实现工具之一。

一个盲签名体制是一个协议,包括两个实体:消息发送者和签名者。它允许发送者让签名者对给定的消息签名,并且没有泄露关于消息和消息签名的任何信息。

1982年,Chaum首次提出盲签名的概念,并利用盲签名技术提出了第一个电子现金方案。利用盲签名技术可以完全保护用户的隐私权,因此,盲签名技术在诸多电子现金方案中广泛使用。

盲数字签名的基本原理是两个可换的加密算法的应用,第一个加密算法是为了隐蔽信息,可称为盲变换,第二个加密算法才是真正的签名算法。

 

盲签名的特点是:

  1. 消息的内容对签名者是盲的;
  2. 签名者不能将所签文件T(m)和实际要签的文件m联系起来,即使他保存所有签过的文件,也不能确定出所签文件的真实内容。

基于RSA的盲签名体制

签名者B选两个大素数p、q,计算n=pq,随机选择e(不必是素数)满足,再由求出d,最后选择一个单向函数f(即老外常说的TrapDoor函数)。公开n、e和f。(如果选择一个单向函数作为f(反向计算几乎不可能),就可以公开f;但如果处于某种原因使用较简单的函数作为f,就不可以公开了,否则Bob就有可能知道内容了)

设发送者Alice要求签名者Bob对消息m进行盲签名。则Alcie和Bob遵从如下协议:

(1)Alice随机选择盲因子k结合盲化函数f计算:

        并将m'发送给Bob;

 (2) Bob接收到m’后,用RSA的私钥d对其进行签名:

          并将S’发送会Alice;

(3)Alice收到s’后,计算来自Bob的签名S:

          Alice通过验证    来判断S是否是Bob的签名。

 

分析:在签名过程中,Bob从未看到过m和对m的盲签名s(实际上是对f(m)的盲签名),所以他无法将(m,s)和(m’,s’)联系起来,因而Bob无法确定他所签文件的内容。

程序实现时非常要注意的一点:

在对S’去盲计算真实签名S时,要使用S=S’/k,而不能使用 。因为请求签名方没有私钥d(要是有的话,还请求Bob干嘛呀-.-)。

但是,直接使用S’=S/k,在程序计算上是不可行的。为什么这么说呢?

举个例子: ,直接从左向右计算的话,结果为4。但是如果根据(a*b) mod c=a mod c * b mod c的话,就变成 ,结果为1(计算机整数相除默认结果取整)。这就出现了窘境。岂不是两个式子都不能用,难道盲签名无法真正投入实际应用?NO.

解决方法:既然原因是因为本来可以消掉分数的部分给“模掉”了,那么我们就给它加回来:给13加上若干个15,使得其可以整除7,然后整除7模15,done.

但是,这个运算在理论上是可行的,你看下面的证明没有任何问题:

首先给个结论,根据费马小定理,下面的等式是成立的:

证明:

代码贴上:

#include <iostream>
using std::cout;
using std::endl;

#include <cstdlib>

#include <iomanip>
using std::hex;

#include <string>
using std::string;

#include <rsa.h>
using CryptoPP::RSA;

#include <integer.h>
using CryptoPP::Integer;

#include <osrng.h>
using CryptoPP::AutoSeededRandomPool;

int main(int argc, char** argv)
{
	cout<<"======================================================="<<endl;
	cout<<"          基于RSA的盲签名演示程序                      "<<endl;
	cout<<"======================================================="<<endl;

	AutoSeededRandomPool prng;

	/////////////////////////////////////////////////////////
	/*
	 RSA::PrivateKey privKey;
	 privKey.GenerateRandomWithKeySize(prng, 128);
	 RSA::PublicKey pubKey(privKey);

	 cout << "modulus: " << hex << privKey.GetModulus() << endl;
	 cout << "private exp: " << hex << privKey.GetPrivateExponent() << endl;
	 cout << "public exp: " << hex << privKey.GetPublicExponent() << endl;
	 cout << endl;
	 */
	/////////////////////////////////////////////////////////
	
	Integer n("0xbeaadb3d839f3b5f"), e("0x11"), d("0x21a5ae37b9959db9");

	RSA::PrivateKey privKey;
	privKey.Initialize(n, e, d);

	RSA::PublicKey pubKey;
	pubKey.Initialize(n, e);

	//输出相关参数信息
	cout<<"选取的2个素数:"<<"p:"<<hex<<privKey.GetPrime1()<<"\tq:"<<hex<<privKey.GetPrime2()<<endl;
	cout<<"公钥(e,n):"<<"("<<hex<<e<<","<<hex<<n<<")"<<endl;
	cout<<"私钥(d,n):"<<"("<<hex<<d<<","<<hex<<n<<")\n\n"<<endl;
	/////////////////////////////////////////////////////////
	string message, recovered;
	Integer m, fm,c, r, k(128), m_, s_, s;
	
	message = "NCEPU Sci&Teque";
	cout << "message原文: " << message << endl;
	
	// Treat the message as a big endian array
	m = Integer((const byte *)message.data(), message.size());
	cout << "盲化的消息m: " << hex << m << endl;

	// Encrypt and Blind
	//c = pubKey.ApplyFunction(m);
	//cout << "c: " << hex << c << endl;
	fm=m;
	m_=a_exp_b_mod_c(k,e,n);
	m_=m_*fm%n;
	cout<<"加密后的盲化消息m_:"<<hex<<m_<<endl<<endl<<endl;

	// Decrypt
	//r = privKey.CalculateInverse(prng, c);
	//cout << "r: " << hex << r << endl;

	//Sign
	s_=a_exp_b_mod_c(m_,d,n);
	cout<<"签名后的加密消息s_:"<<hex<<s_<<endl;

	//unblind
	for(int nani=1;;nani++)
	{
		s_+=n;
		if(s_%k==0)
		{
			s=s_/k%n;
			cout<<"nani:"<<nani<<endl;//29
			cout<<"s:"<<hex<<s<<endl;
			break;
		}
	}
	//验证是否与上面的相等
	s=a_exp_b_mod_c(fm,d,n);
	cout<<"s:"<<hex<<s<<endl;
	cout<<"解盲后的签名s:"<<endl;
	cout<<"\n开始验证签名的合法性.."<<endl;
	bool bVerify=true;
	if(fm%n == a_exp_b_mod_c(s,e,n))
	{
		bVerify=true;
		cout<<"Verify Success!\n"<<endl;
	}
	else
	{
		bVerify=false;
		cout<<"Vefify Failed.\n"<<endl;
	}
	
	// Round trip the message

	if(bVerify)
	{
		cout<<"\n开始解密消息.."<<endl;
		size_t req=fm.MinEncodedSize();
		recovered.resize(req);
		fm.Encode((byte*)recovered.data(),recovered.size());
		cout<<"解密后的消息recovered:"<<recovered<<endl;
		cout<<"解密成功!"<<endl;
	}

	system("pause");

	return 0;
}

  结果附上:

posted @ 2013-04-26 14:38  Tup  阅读(5375)  评论(0)    收藏  举报