RSA加解密算法实现

本代码为大作业RSA加解密,q和p的选择使用了伪随机生成大数,并进行素性测试;明文中三个字符为一块,进行分块,块中字符不满三个的进行填充,采用的填充方案是PKCS#7填充。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <math.h>
using namespace std;
long long int N;
long long int D;
// 生成伪素数
const int MAX_ROW = 50;

size_t Pseudoprime()
{
    bool ifprime = false;
    size_t a = 0;
    int arr[MAX_ROW];   //数组arr为{3,4,5,6...52}
    for (int i = 0; i < MAX_ROW; ++i)
    {
        arr[i] = i + 3;
    }
    while (!ifprime)
    {
        srand((unsigned)time(0));
        ifprime = true;
        a = (rand() % 10000) * 3 + 10000; //生成一个范围在10000到40000里的奇数
        for (int j = 0; j < MAX_ROW; ++j)
        {
            if (a % arr[j] == 0)
            {
                ifprime = false;
                break;
            }
        }
    }
    return a;
}

size_t  repeatMod(size_t base, size_t n, size_t mod)//模重复平方算法求(b^n)%m
{
    size_t a = 1;
    while (n)
    {
        if (n & 1)
        {
            a = (a * base) % mod;
        }
        base = (base * base) % mod;
        n = n >> 1;
    }
    return a;
}

//Miller-Rabin素数检测
bool rabinmiller(size_t n, size_t k)
{

    int s = 0;
    int temp = n - 1;
    while ((temp & 0x1) == 0 && temp)
    {
        temp = temp >> 1;
        s++;
    }   //将n-1表示为(2^s)*t
    size_t t = temp;

    while (k--)  //判断k轮误判概率不大于(1/4)^k
    {
        srand((unsigned)time(0));
        size_t b = rand() % (n - 2) + 2; //生成一个b(2≤a ≤n-2)

        size_t y = repeatMod(b, t, n);
        if (y == 1 || y == (n - 1))
            return true;
        for (int j = 1; j <= (s - 1) && y != (n - 1); ++j)
        {
            y = repeatMod(y, 2, n);
            if (y == 1)
                return false;
        }
        if (y != (n - 1))
            return false;
    }
    return true;
}

/*
//简单的素数检测方法
bool isprime(size_t n)
{
    if (n == 2)
        return true;
    for (int i = 2; i <= (int)sqrt((float)n); ++i)
    {
        if (n % i == 0)
            return false;
    }
    return true;
}*/

// 计算最大公约数
unsigned long long gcd(unsigned long long a, unsigned long long b) {
    if (b == 0)
        return a;
    return gcd(b, a % b);
}

// 计算模反元素
unsigned long long modInverse(unsigned long long a, unsigned long long m) {
    long long m0 = m;
    long long y = 0, x = 1;

    if (m == 1)
        return 0;

    while (a > 1) {
        long long q = a / m;
        long long t = m;

        m = a % m;
        a = t;
        t = y;

        y = x - q * y;
        x = t;
    }

    if (x < 0)
        x += m0;

    return x;
}

// 快速模幂运算
unsigned long long modExp(unsigned long long base, unsigned long long exponent, unsigned long long modulus) {
    unsigned long long result = 1;
    base = base % modulus;

    while (exponent > 0) {
        if (exponent & 1) {
            result = (result * base) % modulus;
        }

        exponent = exponent >> 1;
        base = (base * base) % modulus;
    }

    return result;
}

// RSA分段加密函数(包括填充)
unsigned long long* encryptString(const char* plaintext, unsigned long long n, unsigned long long e, int blockSize, int* numBlocks) {
    int plaintextLength = strlen(plaintext);
    int paddingLength = blockSize - (plaintextLength % blockSize);
    *numBlocks = (int)ceil((double)(plaintextLength + paddingLength) / blockSize);

    unsigned long long* ciphertext = new unsigned long long[*numBlocks];

    for (int i = 0; i < *numBlocks; i++) {
        int startIndex = i * blockSize;
        int endIndex = (i + 1) * blockSize;
        if (endIndex > plaintextLength) {
            endIndex = plaintextLength;
        }

        unsigned long long blockValue = 0;
        for (int j = startIndex; j < endIndex; j++) {
            blockValue = blockValue * 256 + (unsigned long long)plaintext[j];
        }

        if (i == (*numBlocks - 1)) {
            // 最后一个块进行填充
            for (int j = 0; j < paddingLength; j++) {
                blockValue = blockValue * 256 + paddingLength;
            }
        }

        ciphertext[i] = modExp(blockValue, e, n);
    }

    return ciphertext;
}

// RSA分段解密函数(包括去填充)
char* decryptString(unsigned long long* ciphertext, unsigned long long n, unsigned long long d, int blockSize, int numBlocks) {
    char* plaintext = new char[numBlocks * blockSize + 1]; // 加1用于存储空终止符
    for (int i = 0; i < numBlocks; i++) {
        unsigned long long decryptedBlock = modExp(ciphertext[i], d, n);

        for (int j = blockSize - 1; j >= 0; j--) {
            plaintext[i * blockSize + j] = (char)(decryptedBlock % 256);
            decryptedBlock = decryptedBlock / 256;
        }
    }

    // 去除填充的字节
    int padding = (int)plaintext[numBlocks * blockSize - 1]; // 最后一个字节表示填充长度
    int plaintextLength = numBlocks * blockSize - padding;
    plaintext[plaintextLength] = '\0';

    return plaintext;
}

void encryptNumber(long M, unsigned long long n, unsigned long long e) {
    int r = 1;
    e = e + 1;
    while (e != 1)
    {
        r = r * M;
        r = r % n;
        e--;
    }
    printf("原始消息:%ld\n", M);
    printf("加密后的消息:");
    cout << r << endl;

}

// RSA加解密的各个参数
void rsa(int mode) {
    cout << "正在生成RSA加密的公钥与私钥,请稍后……" << endl;
    unsigned long long int p = 0;
    unsigned long long int q = 0;
    for (int i = 0; i <= 1; i++) {
        size_t ret = Pseudoprime();
        if (i == 0 && p == 0) {
            if (rabinmiller(ret, 10)) {
                cout << "生成的" << ret << "是素数" << endl;
                cout << "p为:" << ret << endl;
                p = ret;
                cout << "------------------------------------------" << endl;
            }
            else {
                i--;
            }
        }
        else if (i == 1 && q == 0 && p != 0) {
            if (rabinmiller(ret, 10) && ret != p) {
                cout << "生成的" << ret << "是素数" << endl;
                cout << "q为:" << ret << endl;
                q = ret;
                cout << "------------------------------------------" << endl;
            }
            else {
                i--;
            }
        }
    }
    unsigned long long int n = p * q; // 计算n
    unsigned long long int phi = (p - 1) * (q - 1); // 计算欧拉函数phi(n)
    unsigned long long int e = 0;
    while (1) {
        e = rand() % phi; // 随机选择一个加密指数e
        if (gcd(e, phi) == 1) // 确保e和phi互质
            break;
    }
    cout << "n为:" << n << endl;
    N = n;
    cout << "随机生成e:" << e << endl;
    cout << "phi值为:" << phi << endl;
    // 计算解密指数d
    unsigned long long d = modInverse(e, phi);
    printf("私钥 (d): %llu\n", d);
    D = d;
    cout << "------------------------------------------" << endl;
    if (mode == 10) {
        char filename[256];
        printf("请输入包含明文的本地文件名:");
        scanf("%255s", filename);

        FILE* file = fopen(filename, "r");
        if (file == NULL) {
            printf("无法打开文件 %s\n", filename);
            return;
        }
        fseek(file, 0, SEEK_END);
        long fileSize = ftell(file);
        fseek(file, 0, SEEK_SET);

        char* plaintext = (char*)malloc((fileSize + 1) * sizeof(char));
        fread(plaintext, sizeof(char), fileSize, file);
        plaintext[fileSize] = '\0';

        fclose(file);
        int blockSize = 3;
        int numBlocks;
        unsigned long long* encrypted = encryptString(plaintext, n, e, blockSize, &numBlocks);

        printf("原始消息:%s\n", plaintext);
        printf("加密后的消息:");
        for (int i = 0; i < numBlocks; i++) {
            printf("%llu ", encrypted[i]);
        }
        printf("\n");
        // 写入txt本地文件中
        printf("请输入要保存密文的文件名:");
        char filename1[256];
        scanf("%255s", filename1);

        FILE* file1 = fopen(filename1, "w");
        if (file == NULL) {
            printf("无法打开文件 %s\n", filename1);
            return;
        }
        for (int i = 0; i < numBlocks; i++) {
            fprintf(file1, "%llu ", encrypted[i]);
        }
        fclose(file1);
        printf("密文已保存到文件 %s\n", filename1);
        free(plaintext);
        free(encrypted);
    }
    if (mode == 21) {
        char plaintext[256];
        printf("请输入待加密的明文:");
        scanf("%255s", plaintext);

        int numBlocks;
        unsigned long long* encrypted = encryptString(plaintext, n, e, 3, &numBlocks);
        printf("原始消息:%s\n", plaintext);
        printf("加密后的消息:");
        for (int i = 0; i < numBlocks; i++) {
            printf("%llu ", encrypted[i]);
        }
        cout << endl;
        // 写入txt本地文件中
        printf("请输入要保存密文的文件名:");
        char filename[256];
        scanf("%255s", filename);
        FILE* file = fopen(filename, "w");
        if (file == NULL) {
            printf("无法打开文件 %s\n", filename);
            return;
        }
        for (int i = 0; i < numBlocks; i++) {
            fprintf(file, "%llu ", encrypted[i]);
        }
        fclose(file);
        printf("密文已保存到文件 %s\n", filename);
        free(encrypted);
    }
    if (mode == 22) {
        long M;
        cout << "请输入数字:";
        scanf("%ld", &M);
        encryptNumber(M, n, e);
    }
}

//主函数
int main(void)
{
    int choice = 0;
    while (choice != 3) {
        printf("                                                     欢迎来到RSA加解密系统\n");
        cout << "--------------------------------------------------------------------------------------------------------------------" << endl;
        printf("                                                        请选择功能:\n");
        printf("                                                        1. 加密\n");
        printf("                                                        2. 解密\n");
        printf("                                                        3. 退出\n");
        printf("                                                        选择:");
        scanf("%d", &choice);

        switch (choice) {
        case 1: {
            int option = 0;
            printf("请选择输入方式:\n");
            printf("1. 从本地文件读取明文\n");
            printf("2. 直接输出明文\n");
            printf("选择:");
            scanf("%d", &option);
            if (option == 1) {
                // 从文件读取明文
               // char* plainText = readPlainTextFromFile(filename);
               // if (plainText == NULL) {
               //     break;
              //  }
              //  free(plainText);
                rsa(10); break;
            }
            else if (option == 2) {
                int op = 0;
                bool flag = false;
                printf("                                                  请选择输入方式:\n");
                printf("                                                  1. 加密字符串\n");
                printf("                                                  2. 加密数字\n");
                printf("                                                  选择:");
                int modeNumber = 22; //加密数字
                int modeString = 21; //加密字符串
                while (op > -1 && flag == false) {
                    scanf("%d", &op);
                    if (op == 1) {
                        rsa(modeString); flag = 1; break;
                    }
                    else if (op == 2)
                        break;
                    else {
                        printf("无效的选择,请重新输入:\n");
                    }
                }
                while (op > -1 && flag == false) {
                    scanf("%d", &op);
                    if (op == 2) {
                        rsa(modeNumber); flag = 1; break;
                    }
                    else {
                        printf("无效的选择,请重新输入:\n");
                    }
                }
                break;
            }
        }
              //密文进行解密
        case 2: {
            printf("                                                  请选择输入方式:\n");
            printf("                                                  1. 从本地文件读取密文\n");
            printf("                                                  2. 直接输出密文\n");
            printf("                                                  选择:");
            int option = 0;
            scanf("%d", &option);
            if (option == 2) {
                unsigned long long ciphertext[256];
                int numBlocks = 0;

                printf("请输入待解密的密文(以空格分隔,换行符停止):");
                while (scanf("%llu", &ciphertext[numBlocks]) == 1) {
                    numBlocks++;
                    // 读取并丢弃换行符
                    if (getchar() == '\n') {
                        break;
                    }
                }
                getchar(); // 清除输入缓冲区中的换行符
                // 获取私钥d和n
                unsigned long long d, n;
                cout << "请输入私钥d和n" << endl;
                cout << "d为: ";
                cin >> d;
                cout << "n为: ";
                cin >> n;
                // 进行解密操作
                char* decrypted = decryptString(ciphertext, n, d, 3, numBlocks);
                printf("解密后的消息:%s\n", decrypted);

                free(decrypted);
                break;
            }
            else if (option == 1) {
                cout <<
                    "私钥PR={" << D << "," << N << "}" << endl;
                printf("请输入要读取的密文文件名:");
                char filename[256];
                scanf("%255s", filename);

                FILE* file = fopen(filename, "r");
                if (file == NULL) {
                    printf("无法打开文件 %s\n", filename);
                    return 1;
                }

                unsigned long long* ciphertext = NULL;
                int numBlocks = 0;
                int c;
                // 读取密文数据
                unsigned long long block;
                while ((c = fgetc(file)) != EOF) {
                    if (isdigit(c) || c == '-') {
                        ungetc(c, file);
                        if (fscanf(file, "%llu", &block) == 1) {
                            numBlocks++;
                            ciphertext = (unsigned long long*)realloc(ciphertext, numBlocks * sizeof(unsigned long long));
                            ciphertext[numBlocks - 1] = block;
                        }
                    }
                    else if (c == ' ') {
                        continue; // 忽略空格字符
                    }
                }
                fclose(file);
                char* decrypted = decryptString(ciphertext, N, D, 3, numBlocks);
                printf("解密后的明文:%s\n", decrypted);
                free(ciphertext);
                free(decrypted);
                break;
            }
        }
        case 3: {
            printf("退出程序。\n");
            break;
        }
        default: {
            printf("无效的选择。\n");
            break;
        }
        }
        cout << endl;
    }
    return 0;
}

如有雷同,纯数巧合。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值