RSA暗号の仕組みを勉強してみた

C++を学び始めたので、C++の環境構築をやったついでにRSA暗号についてGPT先生に教えてもらおうと思い、勉強してみました。ほぼGPT先生に質問するだけという手法でやってます。

RSA暗号は公開鍵暗号システムの一つで、1977年にロナルド・リベスト、アディ・シャミア、レオナルド・エーデルマンによって提案されました。RSAの名称も彼らの頭文字から取られています。この暗号システムは、公開鍵と秘密鍵のペアを使用し、一方の鍵で暗号化した情報をもう一方の鍵でのみ復号することができるという特性があります。

RSA暗号は次のような数学的原理に基づいています。

![RSAキーペア生成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/f6badc60-a877-9295-e6c9-b19c5c6acf2a.png)

YouTubeに分かりやすい解説があったので置いておきます。

https://www.youtube.com/watch?v=CUhDu5praMQ

GPT先生にRSA暗号をまずC++で書いてもらい、わからないところをすべて質問してわかるまで続けました。
```C++
#include <iostream>
#include <cmath>
#include <random>
#include <utility>
#include <limits>
#include <string>  // Include for std::string and std::getline
#include <vector>

// Euclidean algorithm to find the greatest common divisor
int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}

// Function to find modular exponentiation
int modExp(int base, int exp, int mod) {
    int result = 1;
    while (exp > 0) {
        if (exp % 2 == 1) // If exp is odd, multiply base with result
            result = (result * base) % mod;
        base = (base * base) % mod;
        exp /= 2;
    }
    return result;
}

// Generate RSA keys
std::pair<std::pair<int, int>, std::pair<int, int>> generateKeys() {
    int p = 61; // First prime number
    int q = 53; // Second prime number
    int n = p * q;
    int phi = (p - 1) * (q - 1);
    int e;
    std::random_device rd;
    std::mt19937 gen(rd());

    do {
        std::uniform_int_distribution<> dis(2, phi - 1);
        e = dis(gen);
    } while (gcd(e, phi) != 1);

    int d = 1;
    while ((d * e) % phi != 1) {
        d++;
    }

    return { {e, n}, {d, n} };
}

// Encrypt using the public key
int encrypt(int plaintext, int e, int n) {
    return modExp(plaintext, e, n);
}

// Decrypt using the private key
int decrypt(int ciphertext, int d, int n) {
    return modExp(ciphertext, d, n);
}

int main() {
    auto keys = generateKeys();
    int e = keys.first.first, n = keys.first.second;
    int d = keys.second.first;

    std::string input;
    std::cout << "Enter a string to encrypt: ";
    std::getline(std::cin, input); // Use std::getline to read a line of text

    std::vector<int> encrypted;
    std::cout << "Encrypted data: ";
    for (char c : input) {
        int enc = encrypt(c, e, n);
        encrypted.push_back(enc);
        std::cout << enc << " ";
    }
    std::cout << std::endl;

    std::cout << "Do you want to decrypt the data? (y/n): ";
    char response;
    std::cin >> response;

    if (response == 'y' || response == 'Y') {
        std::string decrypted;
        for (int num : encrypted) {
            decrypted.push_back(static_cast<char>(decrypt(num, d, n)));
        }
        std::cout << "Decrypted string: " << decrypted << std::endl;
    }
    else {
        std::cout << "Decryption skipped." << std::endl;
    }

    return 0;
}
```
実行結果
```bash
Enter a string to encrypt: hello
Encrypted data: 1019 406 2426 2426 3039
Do you want to decrypt the data? (y/n): y
Decrypted string: hello
```

分からないところをGPT先生に聞いてみました。

![RSAキーペア生成 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/71b72554-0e78-6815-bad2-2904e826404f.png)

![RSAキーペア生成 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/41be4bdb-d23a-b813-9aba-5035d31d9bad.png)

![RSAキーペア生成 (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/09298b45-2ea6-9358-b663-a0d6f7997cd4.png)

![RSAキーペア生成 (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/42bb26fa-2a72-b5ff-b8cf-03add946b2ad.png)

![RSAキーペア生成 (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/6174e6c4-b207-ed30-c0bd-45a02a1cebc6.png)

![RSAキーペア生成 (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/21a05245-c307-89e2-551b-67a5ee65e4e7.png)

![RSAキーペア生成 (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/42fc4170-7bec-9a1a-7e89-2627225b8fbe.png)

![RSAキーペア生成 (8).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/c2359871-6c75-8f23-bc08-0d3fb5b09e70.png)

![RSAキーペア生成 (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/1996f9dc-521a-d16e-6b91-5dfb2c2bedb4.png)

![RSAキーペア生成 (10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/9450c527-d7eb-66fc-1f9d-e109d6fb6198.png)

![RSAキーペア生成 (11).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/80eec98d-6b12-b4fb-1165-a20e06c73329.png)

![RSAキーペア生成 (12).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/5bce7ac2-2c4d-240f-593e-2f739332aa5f.png)

![RSAキーペア生成 (13).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/5f1c8fd6-a546-1e1c-e2a0-170b63040850.png)
![RSAキーペア生成 (14).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/b709a4e2-0030-57f0-2271-e07fdee25dca.png)
![RSAキーペア生成 (15).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/86482f4a-2a64-1977-b3f4-06add2fbc674.png)

ここでASCII値に対してRSA暗号化を施しているのならEncrypted Dataは文字列の長さの分だけ増えていくと思ったのでテストしてみました。
```
Enter a string to encrypt: o
Encrypted data: 1048
Do you want to decrypt the data? (y/n): y
Decrypted string: o

Enter a string to encrypt: on
Encrypted data: 233 2001
Do you want to decrypt the data? (y/n): y
Decrypted string: on

Enter a string to encrypt: one
Encrypted data: 1453 2550 1992
Do you want to decrypt the data? (y/n): y
Decrypted string: one

Enter a string to encrypt: one
Encrypted data: 1048 1387 1920 1241
Do you want to decrypt the data? (y/n): y
Decrypted string: one

Enter a string to encrypt: one letter
Encrypted data: 3161 3191 284 2106 840 284 2325 2325 284 1131
Do you want to decrypt the data? (y/n): y
Decrypted string: one letter
```
予想通り、1文字につき4つの数字で表示されています。

ここまででざっくりですが、RSA暗号の仕組みを「体験」として理解できました。まだC++を習得してるといえる段階にいないので標準的な使い方すらもわからず、文法がわからないのか関数がわからないのかも曖昧なレベルなので、一旦RSA暗号の理解はここで止めて再度C++の学習に戻ります。

以下のかわいらしい本で学習しています。
![71clrOgY4VL._SL1500_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/8e5fdd37-b177-1c74-09a4-6fe993ed7c0e.jpeg)