In. Its mathematical basis is the mathematical difficulty of discrete logarithm. The key exchange process is described as follows:
Select two large numbers p and g and make them public. p is a prime number, and g is a module p of p. The original unit root (primitive root module p ), the original unit root refers to the power 1 and power 2 of g under the modulo p multiplication operation ...... (P-1) the numbers of the first power are different from each other and are retrieved from 1 to the first power;
For Alice (one of them), a random integer a is generated, a is kept confidential, Ka = g ^ a mod p is calculated, and Ka is sent to Bob;
For Bob (another contact), a random integer B is generated, B is kept confidential, Kb = g ^ B mod p is calculated, and Kb is sent to Alice;
For Alice, after receiving the Kb sent by Bob, the calculated key is: key = Kb ^ a mod p = (g ^ B) ^ a = g ^ (B *) mod p;
For Bob, after receiving the Ka sent by Alice, the calculated key is: key = Ka ^ B mod p = (g ^ a) ^ B = g ^ (a * B) mod p.
The attacker knows p and g and intercepts Ka and Kb. However, when they are all very large numbers, it is very difficult to calculate a and B Based on these four numbers, this is the mathematical problem of discrete logarithm.
To implement the Diffie-Hellman Key Exchange Protocol, you must be able to quickly calculate the power of a big digital model. In the modulo algorithm, you still need to calculate the multiplication and modulo operations of large numbers. Therefore, the entire process requires three algorithms: high-Precision multiplication and high-precision Division (used to calculate the quotient and remainder of A large number divided by another large number at the same time), a fast Modulo-power algorithm.
High-Precision multiplication and division can be simulated by a program. The quick modulo algorithm also summarizes the rule from the manual calculation, for example:
5 ^ 8 = (5 ^ 2) ^ 4 = (25) ^ 4 = (25 ^ 2) ^ 2 = (625) ^ 2. In this way, originally, 8 multiplications were required for calculation of 5 ^ 8, but now only three multiplications are required: 5 ^ 2, 25 ^ 2,625 ^ 2. This is the basis of the rapid Modulo-power algorithm. Describe the algorithm, that is:
Algorithm M: Input integer A, B, P, calculate a ^ B mod P:
M1. initialize c = 1
M2. if B is 0, C is the result to be calculated. Returns the value of C. The algorithm ends.
M3. If B is odd, C = C * a mod P, B = B-1, to M2.
M4. if B is an even number, convert a = A * a mod P, and B = B/2 to M2.
The high-precision Trial Division principle is simple, but the code implementation requires careful consideration of some details.
My DEMO code is as follows:
High-Precision computing:
- Class supernumber {
- Public:
- Supernumber (){
- Memset (data, 0, max_size );
- High = 0;
- }
- // General integer to supernumber conversion. This version does not support negative numbers
- Supernumber (unsigned long l ){
- Memset (data, 0, max_size );
- High = 0;
- While (l ){
- Data [++ high] = l % 10;
- L/= 10;
- }
- }
- // STR represents the decimal number in the string format
- 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;
- }
- // Set the data to 0
- Void reset (){
- Memset (data, 0, max_size );
- High = 0;
- }
- // Str represents the decimal number in the string format
- 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 ';
- }
- }
- // Convert the data to a base-specified string. The default value is decimal.
- Const char * toString (int base = 10) const {
- Static char buf [MAX_SIZE];
- Const char table [] = "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
- If (high = 0) return "0 ";
- Assert (base> = 2); // The specified hexadecimal value should not be less than 2
- // Hexadecimal conversion
- Buf [MAX_SIZE-1] = '/0 ';
- Int begin = MAX_SIZE-1;
- Char temp [MAX_SIZE];
- Memcpy (temp, data, MAX_SIZE );
- While (1 ){
- // Locate the start position of the highest bit
- Int h = high;
- While (temp [h] = 0 & h> = 1) h --;
- If (h = 0) break;
- // Except the base
- 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;
- }
- // Multiplication
- SuperNumber operator * (const SuperNumber & s) const {
- SuperNumber result; // default set to 0
- Int I, j;
- // Multiply
- 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;
- }
- }
- // Carry
- 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;
- }
- }
- // Determine the highest bit
- For (I = MAX_SIZE-1; I> = 1 & result. Data [I] = 0; I --);
- Result. High = I;
- Return result;
- }
- // Division, which is implemented by calling doDivide internally
- SuperNumber operator/(const SuperNumber & s) const {
- SuperNumber q, r;
- DoDivide (s, q, r );
- Return q;
- }
- // Modulo operation, which is implemented by calling doDivide internally
- SuperNumber operator % (const SuperNumber & s) const {
- SuperNumber q, r;
- DoDivide (s, q, r );
- Return r;
- }
- // Division operation. In a division operation, the operator and remainder, operators, and % are reloaded simultaneously.
- // This function is called internally. dest is the divisor, Q is the quotient, and R is the remainder. The algorithm uses the Trial Division.
- Void doDivide (const SuperNumber & dest, SuperNumber & Q, SuperNumber & R) const {
- Int I, j, t;
- Q. reset ();
- Q. high = high-dest. high + 1; // initial bid of the operator
- R = * This; // the remainder is actually the dividend.
- T = DeST. High;
- // Judge whether the Division ends
- While (r> = DEST ){
- // Perform cyclic subtraction for Trial Division
- While (DEST> = R. sub (1, t )){
- Q. Data [q. High --] = 0;
- ++ T;
- }
- While (R. sub (1, t)> = DEST ){
- // When I is subtraction, the lowest subscript OF THE devisor and J is the lowest subscript OF THE devisor.
- 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;
- }
- // The maximum subscript of the Updater after a Trial Division is completed
- Q. high-= 1;
- // Update the highest subscript of the divisor.
- While (R. data [R. high] = 0 ){
- R. high --;
- T --;
- }
- T + = 1; // The next Divisor
- }
- 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;
- }
- // Big digital-to-analog power algorithm. It is a simple natural algorithm, that is, to break down an index into binary values.
- // More simply, it is to constantly find the square modulo power, instead of multiplying all squares before
- // Perform a final modulo operation
- // A. power_mod (p, n) calculates 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 );
- }
- // Start from the highest digit in decimal format, count to the first digit, and intercept consecutive digits from the second digit.
- // The c-digit to form a new number. For example, if the data is 12345678925698
- // Sub (3, 5) returns the number 34567. If the number is not enough, run
- // Sub (3, 5), because 34567 is 5 from the high digits, and the remaining number is 3rd,
- // There are three at most, and five are not enough. At this time, 567 is returned and no error is returned.
- SuperNumber sub (int I, int c) const {
- SuperNumber ret;
- Assert (high> = I); // ensure intercept
- I = high-I + 1; // subscript of the I-th digit starting from the high digit
- 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 --;
- }
- }
- // Filter the leading 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}; // maximum decimal digits
- // Note that using data [0] to store the subscript of the highest bit is a bit clever. Later
- // This is a huge error during debugging, but it can be handled for this question.
- Char data [MAX_SIZE]; // internal representation of the data, in decimal format
- // Where data [0] stores the subscript of the highest bit, data [1]
- // The bitwise of the stored data, that is, the bitwise
- Int high;
- };
Main function:
- Int main (INT argc, char ** argv ){
- Freopen ("in.txt", "r", stdin );
- Supernumbertest st;
- // St. Run ();
- // Both g and n are prime numbers greater than 2 ^ 127. They are made public in DH algorithms.
- 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;
- }
Running result:
G = 170141183460469231731687303715884105757
N = 170141183460469231731687303715884106309
This is Alice:
Alice get a random integer a = 20276
Alice computer G ^ A mod N:
Alice compute out Ka = 102075421398841759242347870420481896337
This is Bob:
Bob get a random integer B = 28664
Bob compute G ^ B mod N:
Bob compute out kb = 62348451302684698452476840835428450852
Alice get Kb from Bob, she compute out key is:
80402514625208456390620786920929643017
Bob get Ka from Alice, he compute out key is:
80402514625208456390620786920929643017
The Demo code of the algorithm implemented using the gnu gmp library is given in the http://oldpiewiki.yoonkn.com/cgi-bin/moin.cgi/DiffieHellmanKeyExchange.