130 lines
		
	
	
		
			No EOL
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			130 lines
		
	
	
		
			No EOL
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # RSA
 | |
| 
 | |
| TODO
 | |
| 
 | |
| generating keys:
 | |
| 
 | |
| 1. *p := large random prime*
 | |
| 2. *q := large random prime*
 | |
| 3. *n := p * q*
 | |
| 4. *f := (p - 1) * (q - 1)* (this step may differ in other versions)
 | |
| 5. *e := 65537* (most common, other constants exist)
 | |
| 6. *d := solve for x: 1 = (x * e) mod f*
 | |
| 7. *public key := (n,e)*
 | |
| 8. *private key := d*
 | |
| 
 | |
| message encryption:
 | |
| 
 | |
| 1. *m := message encoded as a number < n*
 | |
| 2. *encrypted := m^e mod n*
 | |
| 
 | |
| message decryption:
 | |
| 
 | |
| 1. *m := encrypted^d mod n*
 | |
| 2. *decrypted := decode message from number m*
 | |
| 
 | |
| ## Code Example
 | |
| 
 | |
| Here is a stupidly simple [C](c.md) code demonstrating the algorithm, for simplicity we use laughably small primes, we only consider 4 character string as a message and make other simplifications.
 | |
| 
 | |
| ```
 | |
| #include <stdio.h>
 | |
| #define e 65537       // often used constant
 | |
| 
 | |
| typedef unsigned long long u64;
 | |
| 
 | |
| void generateKeys(u64 prime1, u64 prime2, u64 *privateKey, u64 *publicKey)
 | |
| {
 | |
|   u64 f = (prime1 - 1) * (prime2 - 1);
 | |
| 
 | |
|   *publicKey = prime1 * prime2;
 | |
|   *privateKey = 1;
 | |
| 
 | |
|   while (*privateKey) // brute force solve the equation
 | |
|   {
 | |
|     if (((*privateKey) * e) % f == 1)
 | |
|       break;
 | |
| 
 | |
|     (*privateKey)++;
 | |
|   }
 | |
| }
 | |
| 
 | |
| u64 powerMod(u64 n, u64 power, u64 mod) // helper func, returns n^power % mod
 | |
| {
 | |
|   u64 result = 1;
 | |
| 
 | |
|   for (int i = 0; i < power; ++i)
 | |
|     result = (result * n) % mod;
 | |
| 
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| u64 encryptNum(u64 n, u64 publicKey)
 | |
| {
 | |
|   return powerMod(n,e,publicKey);
 | |
| }
 | |
| 
 | |
| u64 decryptNum(u64 n, u64 publicKey, u64 privateKey)
 | |
| {
 | |
|   return powerMod(n,privateKey,publicKey);
 | |
| }
 | |
| 
 | |
| int main(void)
 | |
| {
 | |
|   u64 priv, pub,
 | |
|     prime1 = 33461,
 | |
|     prime2 = 17977;
 | |
| 
 | |
|   const char *str = "bich"; // we'll only consider 4 char string
 | |
| 
 | |
|   puts("generating keys, wait...");
 | |
| 
 | |
|   generateKeys(prime1,prime2,&priv,&pub);
 | |
| 
 | |
|   printf("prime1 = %llu\nprime2 = %llu\nprivate key = %llu\npublic key = %llu\n",
 | |
|     prime1,prime2,priv,pub);
 | |
| 
 | |
|   u64 data = str[0] | (str[1] << 7) | (str[2] << 14) | (str[3] << 21);
 | |
| 
 | |
|   printf("string to encode: \"%s\"\n",str);
 | |
|   printf("string as numeric data: %lld\n",data);
 | |
| 
 | |
|   if (data >= pub)
 | |
|   {
 | |
|     puts("Data is too big, choose bigger primes or smaller data.");
 | |
|     return 1;
 | |
|   }
 | |
| 
 | |
|   puts("encrypting...");
 | |
| 
 | |
|   u64 encrypted = encryptNum(data,pub);
 | |
|   printf("encrypted: %lld\n",encrypted);
 | |
| 
 | |
|   puts("decrypting...");
 | |
| 
 | |
|   data = decryptNum(encrypted,pub,priv);
 | |
|   printf("decrypted: %lld\n",data);
 | |
| 
 | |
|   printf("retrieved string: \"%c%c%c%c\"\n",data & 0x7f,(data >> 7) & 0x7f,
 | |
|     (data >> 14) & 0x7f,(data >> 21) & 0x7f);
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| ```
 | |
| 
 | |
| The program prints out:
 | |
| 
 | |
| ```
 | |
| generating keys, wait...
 | |
| prime1 = 33461
 | |
| prime2 = 17977
 | |
| private key = 323099873
 | |
| public key = 601528397
 | |
| string to encode: "bich"
 | |
| string as numeric data: 219739362
 | |
| encrypting...
 | |
| encrypted: 233361060
 | |
| decrypting...
 | |
| decrypted: 219739362
 | |
| retrieved string: "bich"
 | |
| ``` |