⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 diffie-hellman.txt

📁 设计一个加密系统里面含Diffie-Hellman代码 DES_Tool2(直接生成密文和加密明文) DSATool.v1.3软件和一个das源代码
💻 TXT
字号:


在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) { 
            memcpy(data, s.data, MAX_SIZE); 
            high = s.high; 
        } 
        return *this; 
    } 

    // 将数据置为0 
    void reset() { 
        memset(data, 0, MAX_SIZE); 
        high = 0; 
    } 

    // str为字符串形式表示的十进制数 
    void setToStr(const char* str) { 
        assert(str != NULL); 
        high = strlen(str); 
        for(int i = high, j = 0; i >= 1; i--, j++) { 
            data[i] = str[j] - '0'; 
        } 
    } 
    // 将数据转换成以base指定的进制的字符串形式,默认为十进制 
    const char* toString(int base = 10) const { 
        static char buf[MAX_SIZE]; 
        const char table[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 

        if(high == 0) return "0"; 

        assert(base >= 2);      // 指定的进制应该不小于2 

        // 进制转换 
        buf[MAX_SIZE-1] = '\0'; 
        int begin = MAX_SIZE-1; 
        char temp[MAX_SIZE]; 
        memcpy(temp, data, MAX_SIZE); 
        while(1) { 
            // 找最高位的起始位置 
            int h = high; 
            while(temp[h] == 0 && h >= 1) h--; 
            if(h == 0) break; 

            // 除基取余 
            int t = 0; 
            while(h >= 1) { 
                t = t * 10 + temp[h]; 
                temp[h] = t / base; 
                t = t % base; 
                h--; 
            } 
            buf[--begin] = table[t]; 
        } 

        return buf+begin; 
    } 

    // 乘法 
    SuperNumber operator*(const SuperNumber& s) const { 
        SuperNumber result;     // default set to 0 
        int i, j; 
         
        // 相乘 
        for(i = 1; i <= high; i++) { 
            for(j = 1; j <= s.high; j++) { 
                int k = data[i] * s.data[j] + result.data[i+j-1]; 
                result.data[i+j-1] = k % 10; 
                result.data[i+j] += k / 10; 
            } 
        } 
        // 进位 
        for(i = 1; i < MAX_SIZE - 1; i++) { 
            if(result.data[i] >= 10) { 
                result.data[i+1] += result.data[i] / 10; 
                result.data[i] %= 10; 
            } 
        } 
        // 确定最高位 
        for(i = MAX_SIZE-1; i >= 1 && result.data[i] == 0; i--); 
        result.high = i; 

        return result; 
    } 

    // 除法,内部调用doDivide来实现 
    SuperNumber operator/(const SuperNumber& s) const { 
        SuperNumber q, r; 
        doDivide(s, q, r); 
        return q; 
    } 
    // 模运算,内部调用doDivide来实现 
    SuperNumber operator%(const SuperNumber& s) const { 
        SuperNumber q, r; 
        doDivide(s, q, r); 
        return r; 
    } 

    // 除法运算,一次除法运算中同时得到商和余数,运算符/和%的重载 
    // 内部会调用这个函数,dest为除数,Q为商,R为余数,算法使用试除法 
    void doDivide(const SuperNumber& dest, SuperNumber& Q, SuperNumber& R) const { 
        int i, j, t; 

        Q.reset(); 
        Q.high = high - dest.high + 1; // 商的初始位数 
        R = *this;                     // 余数初始实为被除数 
        t = dest.high; 
        // 判断除法是否结束 
        while(R >= dest) { 
            // 循环相减进行试除 
            while(dest >= R.sub(1, t)) { 
                Q.data[Q.high--] = 0; 
                ++t; 
            } 
            while(R.sub(1, t) >= dest) { 
                // i为相减时被除数最低下标,j为除数最低下标 
                for(i=R.high-t+1,j=1; j<=dest.high; i++,j++) { 
                    R.data[i] -= dest.data[j]; 
                    if(R.data[i] < 0) { 
                        R.data[i] += 10; 
                        R.data[i+1] -= 1; 
                    } 
                } 
                while(R.data[i] < 0 && i <= R.high) { 
                    R.data[i] += 10; 
                    R.data[i+1] -= 1; 
                    ++i; 
                } 
                Q.data[Q.high] += 1; 
            } 
            // 一次试除结束,更新商的最高位下标 
            Q.high -= 1; 
            // 更新被除数的最高位下标 
            while(R.data[R.high] == 0) { 
                R.high--; 
                t--; 
            } 
            t+=1;               // 下一位被除数 
        } 

        Q.high = high - dest.high + 1;  
        while(Q.data[Q.high] == 0) Q.high -= 1; 
        R.high = high; 
        while(R.data[R.high] == 0) R.high -= 1; 
    } 

    // 大数模幂算法,很简单的自然算法,即将指数分解为二进制,换句 
    // 更简单的话来说,就是不断地找平方模幂,而不是全部乘方后再 
    // 做一次最终的模运算 
    // a.power_mod(p, n)计算a^p mod n 
    SuperNumber power_mod(int power, SuperNumber n) const { 
        SuperNumber c("1"), t(*this); 

        while(power) { 
            if(power % 2) { 
                c = c * t % n; 
                power -= 1; 
            } else { 
                t = t * t % n; 
                power /= 2; 
            } 
        } 

        return c%n; 
    } 

    bool operator>=(const SuperNumber& s) const { 
        if(high == s.high) { 
            int k = high; 
            while(data[k] == s.data[k] && k >= 1)k--; 
            if(k < 1) return true; // equal 
            return data[k] > s.data[k]; 
        } else if(high > s.high) return true; 
        return false;         
    } 

    bool operator<(const SuperNumber& s) const { 
        return !(*this >= s); 
    } 

    // 从十进制表示的最高位开始数起,数到第i位,从第i位开始截取连续 
    // 的c位数字出来组成一个新的数。例如:数据是12345678925698,则 
    // sub(3, 5)返回数字34567,如果数字不够取,例如在34567上运行 
    // sub(3, 5),因为34567从高位数起第3个数字是5,剩下的数字是567, 
    // 最多只有三个,不够取要求的5个,这个时候返回567,不报错。 
    SuperNumber sub(int i, int c) const { 
        SuperNumber ret; 
        assert(high >= i);   // 保证可截取 

        i = high - i + 1;    // 从高位数起的第i个数位的下标 
        if(i >= c) { 
            ret.high = c; 
            while(c >= 1) ret.data[c--] = data[i--]; 
        } else { 
            ret.high = i; 
            while(i >= 1) { 
                ret.data[i] = data[i]; 
                i--; 
            } 
        }  
        // 过滤前导0 
        while(ret.data[ret.high] == 0) ret.high--; 
        return ret; 
    } 

    // I/O 
    friend istream& operator>>(istream& in, SuperNumber& s) { 
        char t[256]; 
        in >> t; 
        s.setToStr(t); 
        return in; 
    } 
    friend ostream& operator<<(ostream& out, const SuperNumber& s) { 
        return out << s.toString(10); 
    } 
private: 
    enum {MAX_SIZE=256};        // 最大十进制位数 
    // 须注意,使用data[0]存储最高位所在下标是自己的一点小聪明,后来在 
    // 调试的时候发现这是一个极大的错误,不过对于此题目来说可以应付 
    char data[MAX_SIZE];        // 数据的内部表示,字符串形式的十进制 
                                // 其中data[0]存储最高位所在下标,data[1] 
                                // 存储数据的最低位,也就是个位 
    int high; 
};

主函数: 
int main(int argc, char **argv) { 
    freopen("in.txt", "r", stdin); 

    SuperNumberTest st; 

//    st.run(); 

    // g和n都是超过2^127的素数。它们在DH算法中公开 
    SuperNumber g, n; 
    int a, b; 
    SuperNumber ka, kb, key; 

    srand(time(0)); 

    cin >> g >> n; 

    cout << "g = " << g << endl 
         << "n = " << n << endl; 

    cout << "\nThis is Alice:\n"; 
    a = rand(); 
    cout << "Alice get a random integer a = " << a << endl; 
    cout << "Alice computer g^a mod n:\n"; 
    ka = g.power_mod(a, n); 
    cout << "Alice compute out ka = " << ka << endl; 

    cout << "\nThis is Bob:\n"; 
    b = rand(); 
    cout << "Bob get a random integer b = " << b << endl; 
    cout << "Bob compute g^b mod n:\n"; 
    kb = g.power_mod(b, n); 
    cout << "Bob compute out kb = " << kb << endl; 

    cout << "\nAlice get kb from Bob, she compute out key is:\n"; 
    cout << kb.power_mod(a, n) << endl; 

    cout << "\nBob get ka from Alice, he compute out key is:\n"; 
    cout << ka.power_mod(b, n) << endl; 


    return 0; 
} 





⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -