1. calculation principle of large numbers
The RSA algorithm relies on the calculation of large numbers. Currently, mainstream RSA Algorithms are based on the calculation of large numbers ranging from 512 to 1024 bits. Therefore, we need to first master the calculation principle of large numbers (such as 1024 bits.
Most compilers only support 32-bit (or 64-bit) integer operations, that is, the integer used in the operation must be smaller than or equal to 32 bits, that is, 0 xFFFFFFFF, this far does not meet the needs of RSA, so we need to build a large number computing database to solve this problem.
The simplest way is to treat a large number as a string, that is, to represent a large number in an array of 10-digit characters, then it simulates the manual "vertical calculation" process to write its addition, subtraction, multiplication, division function. However, this is very inefficient. Of course, its advantage is that algorithms conform to people's daily habits and are easy to understand.
Another idea is to process large numbers as a binary stream and perform addition, subtraction, multiplication, division, and Division operations using various shift and logical operations. However, the code design is very complicated and the readability is very low, difficult to understand and debug.
Here we adopt the idea between the two: Think of a large number as an N-base array. For the current 32-bit system, N can take the power of 2 to the power of 32, that is, 0x100000000. If a large number of 1024 bits is converted into 0x0000000, it is changed to 32 bits, and the value range of each bits is 0-0xFFFFFFFF. we can use an unsigned long integer to represent this value. Therefore, the large number of the 1024 bits is an unsigned long array with 32 elements. In addition, the array arrangement of 0x00000000 and the binary stream are actually the same thing for the computer, but we can perform "vertical calculation" for the unsigned long array ", the loop scale is reduced to 32 times, and the algorithm is easy to understand.
However, considering the multiplication and division, both of them must be extended to perform rapid calculation (if Division is changed to subtraction without expansion, the speed will be slow and intolerable ). So we take N to the power of 2, that is, 0xFFFF. each bit is represented by unsigned short. When multiplication and division operations are performed, short is extended to long, which is supported by the compiler. Therefore, this algorithm is faster.
2. Various operations on large numbers
These operations are both common and common. To implement the RSA algorithm, you must first implement these operations for large numbers.
1) Comparison of large numbers. Compare the sizes of two unsigned or signed large numbers. Compare large numbers with General integers. Values greater than, equal to, less than, and different return values are used to compare different results.
2) assign a value to a large number. Assign values and symbols of a large number to another large number by bit. Assign the value and symbol of a general integer to a large number.
3) Addition of large numbers. The two large numbers are added by bit from the low to the high, so the carry problem must be taken into account. Or the addition of a large number and a general integer.
4) subtraction of large numbers. The two large numbers subtract from the low position to the high position, and the borrow space must be considered. Or subtract a large number from a general integer.
5) multiplication of large numbers. Multiplication of two large numbers, from the low to the high of a large number, multiply by one with the other, and then add the results to the low alignment. Carry should be considered, similar to normal vertical multiplication. Or multiplication of A large number and a general integer.
6) Division of large numbers. Division of two large numbers, from the high to the low of a large number, is gradually divided with the other large number, consider the borrow space, similar to the normal vertical division. Or multiplication of A large number and a general integer.
7) return the remainder of a large number. The remainder of the two large numbers is similar to the division of the large numbers, but when the Division ends, the return result is the remainder, and there is also the borrow problem. Or return the remainder of a general integer.
8) Euclidean Algorithm for large numbers. It is known big numbers A and B. Finding X that satisfies AX limit 1 mod B is an extension of the maximum common number algorithm and also uses the moving phase division. In the recursive process, both parameters need to be used to change. For more information about the algorithm, see source code.
9) Montessori Algorithm for large numbers. It is known big numbers A, B, and C. Evaluate the value of X = A ^ B MOD C. Gradually downgrades the index until it reaches the power of 2, that is, converts it to multiplication and remainder operations. For more information about downgrading methods and algorithms, see related books and source code.
10) the maximum common divisor of a large number. Calculate the maximum common divisor of two large numbers and divide them by the moving phase.
RSA Algorithm Implementation
A. Generate the key function
GChar gGenerateKey (gBigInt * n, gBigInt * e, gBigInt * d );
Function: This function enables the generation of keys. First generate two random large prime numbers p and q, then calculate n = p × q, randomly generate (or fix) a large number e, calculate d, make ed limit 1 MOD (p-1) q-1 ).
Parameters:
N: the product of two large numbers. It is combined with e or d to form an encryption key or decryption key.
E: A large number used as the encryption key.
D: A large number that is different from e and serves as the decryption key.
Return Value: 1-success, 0-failure.
B. Data Encryption Functions
Char gEncRSA (unsigned char * indata, unsigned long inlen, gBigInt * e, gBigInt * n ,\
Unsigned char * outdata, unsigned long * outlen, int flg );
Function: uses the encryption key e and n to encrypt the plaintext data in segments.
The encrypted data is put into the memory outdata in advance, its length outlen should not be less than (inlen + K-12)/(K-11) * k, Here k is the number of digits of n.
Parameters:
Indata: pointer to plaintext data.
Inlen: the length of incoming data, that is, the length of plaintext data.
E and n: two large numbers, used as the encryption key.
Outdata: a pointer to the encrypted ciphertext data.
Outlen: the length of the incoming outdata, that is, the length of the ciphertext data.
Flg: indicates public key encryption or private key encryption. g_PUBLIC-public key and g_PRIVATE-private key.
Return Value: 1-success, 0-failure.
C. Data decryption functions
Char gDecRSA (unsigned char * indata, unsigned long inlen, gBigInt * d, gBigInt * n ,\
Unsigned char * outdata, unsigned long * outlen, int flg );
Function: segments the ciphertext data to be decrypted with the decryption key e and n.
The decrypted data is put into the memory outdata in advance, and its length outlen cannot be less than (inlen) * k/(K-11 ),
Here k is the number of digits in n.
Parameters:
Indata: pointer to ciphertext data.
Inlen: the length of the input data, that is, the length of the ciphertext data.
D and n: two large numbers, used as the encryption key.
Outdata: a pointer to the plaintext data after decryption.
Outlen: the length of incoming outdata, that is, the length of plaintext data.
Flg: indicates public key encryption or private key encryption. g_PUBLIC-public key and g_PRIVATE-private key.
Return Value: 1-success, 0-failure.
D. Use a small prime number for Detection
GChar gIsNotPrime (gBigInt * p );
Function: checks whether the random large number p can be divisible by a small prime number.
Parameters:
P: the random large number to be detected.
Return Value: 0-may be a prime number, and other-is a small prime number or 1 that can divide p.
E. Rabin-Miller Detection
GChar gRabinMillerTest (gBigInt * p, int tNum );
Function: uses the Rabin-Miller algorithm to perform tNum detection on the large number of p and determine whether p may be a prime number.
Parameters:
P: the random large number to be detected.
TNum: the number of detection times, which determines the reliability of the detection.
Return Value: 0-failed or fail, 1-succeeded and passed, indicating that p may be a prime number.
F. Random generation of large prime numbers
GChar gGeneratePrime (gBigInt * p );
Function: generate a large prime number randomly.
Parameters:
P: A large random prime number.
Return Value: 0-failed, 1-success.
G. Search for large prime numbers in sequence
GChar gGeneratePrimeEx (gBigInt * p, int flg );
Function: Search for large prime numbers near p progressively or progressively according to flg.
Parameters:
P: The searched prime number.
Flg: direction sign, g_INCREASE-incrementing, g_DECREASE-decreasing.
Return Value: 0-failed, 1-success.
H. Conversion of strings and large numbers
GChar gStr2BigInt (gBigInt * gbi, char * str, int flg );
Function: converts string 'str' in hexadecimal or hexadecimal format into a large gbi String Based on the flg flag.
Parameters:
Gbi: convert to a large number.
Str: string to be converted.
Flg: sign, OCT_FLG-8 into the system, DEC_FLG-10 into the system, HEX_FLG-16 into the system.
Return Value: 0-failed, 1-success.
GChar gBigInt2Str (char * str, gBigInt * gbi, int flg );
Function: convert a large number of gbi into a string expressed in hexadecimal or hexadecimal notation Based on the flg flag.
Parameters:
Str: string to be converted.
Gbi: The large number to be converted.
Flg: sign, OCT_FLG-8 into the system, DEC_FLG-10 into the system, HEX_FLG-16 into the system.
Return Value: 0-failed, 1-success.
I. multiplication and division of General Integers
GUInt gIntMul (gUInt * a, gUInt B );
Function: Multiplication of integers. In the function, the integers a and B are extended, multiplied by B, and the result is placed in a to return. The carry value is used as the return value.
Parameters:
A: input an integer to output the result of multiplication.
B: input an integer as the multiplier.
Return Value: Carry that is multiplied by two integers. 0 is returned if a failure occurs.
GUInt gIntDiv (gUInt * ah, gUInt * al, gUInt B );
Function: Division of integers. In the function, the integers ah and al are combined into an extended integer, divided by integer B, and the result is placed in the high position of ah, and the low position is returned in the al, and the remainder is returned as the return value.
Parameters:
Ah: an integer is input as the high value of the divisor; the high value of the result after the output division.
Al: an integer is input as the low position of the divisor, and the low value of the result of outgoing division.
B: input an integer as the divisor.
Return Value: the remainder of the Division. 0 is returned if a failure occurs.
J. Comparison of large numbers
GChar gCmp (gBigInt * a, gBigInt * B );
Function: Compare the values of a and B without considering their symbols.
Parameters:
A: input a large number.
B: Input another large number.
Return Value:-1-a is smaller than B, 0-a is equal to B, + 1-a is greater than B.
GChar gCmpEx (gBigInt * a, gBigInt * B );
Function: Compare large numbers a and B. Consider their symbols. The integer is greater than negative.
Parameters:
A: input a large number.
B: Input another large number.
Return Value:-1-a is smaller than B, 0-a is equal to B, + 1-a is greater than B.
GChar gCmpInt (gBigInt * a, gUInt B );
Function: Compares large numbers with integers. Compare large numbers a with General integers B without considering their symbols.
Parameters:
A: input a large number.
B: input a general integer.
Return Value:-1-large number a is smaller than B, 0-large number a is equal to B, + 1-large number a is greater than B.
K. assign values to large numbers
GChar gMov (gBigInt * a, gBigInt * B );
Function: Assign the value of a large number B to a large number a and consider their symbols.
Parameters:
A: returns the output value.
B: Input another large number.
Return Value: 0-failed, 1-success.
GChar gMovInt (gBigInt * a, gUInt B );
Function: Assign the value of integer B to the number a and consider their symbols.
Parameters:
A: returns the output value.
B: input a general integer.
Return Value: 0-failed, 1-success.
L. Addition of large numbers
GChar gAdd (gBigInt * a, gBigInt * B); // Add
Function: adds large numbers a and B to consider their symbols.
Parameters:
A: input a large number and output the result of the sum.
B: Input another large number.
Return Value: 0-failed, 1-success.
GChar gAddInt (gBigInt * a, gSInt B );
Function: adds large numbers a and integer B to consider their symbols.
Parameters:
A: input a large number and output the result of the sum.
B: input a general integer.
Return Value: 0-failed, 1-success.
M. subtraction of large numbers
GChar gSub (gBigInt * a, gBigInt * B); // subtract
Function: Perform subtraction on the numbers a and B, and consider their symbols.
Parameters:
A: input a large number to indicate the result of subtraction.
B: Input another large number.
Return Value: 0-failed, 1-success.
GChar gSubInt (gBigInt * a, gSInt B );
Function: Perform subtraction on large numbers a and integer B to consider their symbols.
Parameters:
A: input a large number to indicate the result of subtraction.
B: input a general integer.
Return Value: 0-failed, 1-success.
N. Multiplication of large numbers
GChar gMul (gBigInt * a, gBigInt * B); // multiply
Function: Perform multiplication on the numbers a and B, and consider their symbols.
Parameters:
A: input a large number and output the result of multiplication.
B: Input another large number.
Return Value: 0-failed, 1-success.
GChar gMulInt (gBigInt * a, gSInt B );
Function: Perform multiplication on the numbers a and B, and consider their symbols.
Parameters:
A: input a large number and output the result of multiplication.
B: input a general integer.
Return Value: 0-failed, 1-success.
O. Division of large numbers
GChar gDiv (gBigInt * a, gBigInt * B); // Division
Function: divide large numbers a and B to consider their symbols.
Parameters:
A: input a large number to indicate the result of division.
B: Input another large number.
Return Value: 0-failed, 1-success.
GChar gDivInt (gBigInt * a, gSInt B );
Function: divide large numbers a and integer B to consider their symbols.
Parameters:
A: input a large number to indicate the result of division.
B: input a general integer.
Return Value: 0-failed, 1-success.
P. Return the remainder of a Large Number
GChar gMod (gBigInt * a, gBigInt * B); // obtain the remainder
Function: Perform the remainder operation on the numbers a and B, and consider their symbols.
Parameters:
A: input a large number and output the result of the remainder operation.
B: Input another large number.
Return Value: 0-failed, 1-success.
GChar gModInt (gBigInt * a, gSInt B );
Function: Perform the remainder operation on the numbers a and B, and consider their symbols.
Parameters:
A: input a large number and output the result of the remainder operation.
B: input a general integer.
Return Value: 0-failed, 1-success.
Q. Euclidean Algorithm
GChar gEuc (gBigInt * a, gBigInt * B); // Euclidean Algorithm
Function: Execute the Euclidean algorithm on the numbers a and B, and put the result into. That is, to obtain the value of X that satisfies the value of aX branch 1 MOD B, that is, to obtain the values of X and Y that meet the value of a smaller number of aX-bY = 1.
The recursive idea is used. After calculation, the numbers a and B change.
Parameters:
A: input a large number and output the value of X that meets the value of aX-bY = 1.
B: Pass in another large number, and pass out the value of Y that satisfies the value of aX-bY = 1.
Return Value: 0-failed, 1-success.
R. Montgomery Algorithm
GChar gMon (gBigInt * a, gBigInt * B, gBigInt * c); // Montgomery Algorithm
Function: Execute the Montgomery Algorithm for large numbers a, large numbers B, and large numbers c, and put the result in.
Calculate the value of a ^ B MOD c using the exponential downgrading idea. For the principle of downgrading, see related books.
Parameters:
A: input a large number to output the operation result.
B: Input another large number.
C: Enter the third large number.
Return Value: 0-failed, 1-success.
S. maximum public approx.
GChar gGcd (gBigInt * a, gBigInt * B); // maximum approximate number
Function: calculate the maximum common divisor of a and B by moving phase division.
Parameters:
A: input a large number, and output the maximum common divisor of a and B.
B: Input another large number.
Return Value: 0-failed, 1-success.
Excerpted from Mai Ling Network