在http://en.wikipedia.org/wiki/Diffie-Hellman上面给出了这个密钥交换协议的历史,原理,重要文献的链接,以及演示代码。它的数学基础就是离散对数这个数学难题。用它进行密钥交换的过程简述如下:
选取两个大数p和g并公开,其中p是一个素数,g是p的一个模p本原单位根(primitive root module p),所谓本原单位根就是指在模p乘法运算下,g的1次方,2次方……(p-1)次方这p-1个数互不相同,并且取遍1到p-1;
对于Alice(其中的一个通信者),随机产生一个整数a,a对外保密,计算Ka = g^a mod p,将Ka发送给Bob;
对于Bob(另一个通信者),随机产生一个整数b,b对外保密,计算Kb = g^b mod p,将Kb发送给Alice;
在Alice方面,收到Bob送来的Kb后,计算出密钥为:key = Kb^a mod p=(g^b)^a=g^(b*a) mod p;
对于Bob,收到Alice送来的Ka后,计算出密钥为:key = Ka ^ b mod p=(g^a)^b=g^(a*b) mod p。
攻击者知道p和g,并且截获了Ka和Kb,但是当它们都是非常大的数的时候,依靠这四个数来计算a和b非常困难,这就是离散对数数学难题。
要实现Diffie-Hellman密钥交换协议,需要能够快速计算大数模幂,在模幂算法中,仍需计算大数的乘法和模运算,所以整个过程需要三个算法:高精度乘法,高精度除法(用来同时求出一个大数除以另一个大数的商和余数),快速模幂算法。
高精度的乘法和除法可以程序模拟手算。快速模幂算法也是从手算中总结出规律来,例如:
5^8 = (5^2)^4 = (25)^4 = (25^2)^2 = (625)^2,这样,原来计算5^8需要做8次乘法,而现在则只需要三次乘法,分别是:5^2, 25^2, 625^2。这就是快速模幂算法的基础。将算法描述出来,那就是:
算法M:输入整数a,b,p,计算a^b mod p:
M1.初始化c = 1
M2.如果b为0, 则c就是所要计算的结果。返回c的值。算法结束。
M3.如果b为奇数,则令c = c *a mod p, 令b = b-1,转到M2。
M4.如果b为偶数,则令a = a * a mod p, 令b = b / 2,转到M2。
高精度试除法原理简单,但是代码实现起来需要仔细考虑一些细节。
我的演示代码如下:
高精度运算类:
- class SuperNumber {
- public:
- SuperNumber() {
- memset(data, 0, MAX_SIZE);
- high = 0;
- }
- // 一般整型到SuperNumber的转换,该版本中不支持负数
- SuperNumber(unsigned long l) {
- memset(data, 0, MAX_SIZE);
- high = 0;
- while(l) {
- data[++high] = l % 10;
- l /= 10;
- }
- }
- // str为字符串形式表示的十进制数
- SuperNumber(const char* str) {
- assert(str != NULL);
- high = strlen(str);
- for(int i = high, j = 0; i >= 1; i--, j++) {
- data[i] = str[j] - '0';
- }
- }
- SuperNumber(const SuperNumber& s) {
- memcpy(data, s.data, MAX_SIZE);
- high = s.high;
- }
- operator const char*() const {
- return toString(10);
- }
- SuperNumber& operator=(const SuperNumber& s) {
- if(this != &s) {