RSA C语言实现

完整代码上传至GitHub: https://github.com/XEric7/simpleRSA

由于目前gcc最大只支持128位整数(需使用64位gcc进行编译),故如果在不重写相关数学运算的前提下,无法实现较大密钥的RSA加密。

tool:实现一些基本的数学运算

tool.h

#ifndef _tool_h_
#define _tool_h_

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define ASSERT(condition)                                                \
    if (!condition)                                                      \
    {                                                                    \
        printf("Assertion failed: line %d file %s", __LINE__, __FILE__); \
        exit(1);                                                         \
    }

#define EXCHANGE(x, y, tmp) \
    tmp = x;                \
    x = y;                  \
    y = tmp;

typedef unsigned __int128 bignum;

bignum powMod(bignum base, bignum index, bignum mod);

// generate unsigned int64 random number
unsigned __int64 uint64Rand();

// generate unsigned int128 random number
unsigned __int128 uint128Rand();

// 判断一个大于3的数是否为素数
bool isprime(bignum n);

// 判断两数是否互质
bool coprime(bignum x, bignum y);


//将int128类型的整数保存到文件
void int128tofile(bignum num, FILE *fp);

//将hex的string转换成 int128
unsigned __int128 stringToInt128(char *str);

// Function to find modulo inverse of a
bignum modInverse(bignum a, bignum m);

// Returns (a * b) % mod
bignum moduloMultiplication(bignum a, bignum b, bignum mod);

#endif

tool.c

#include "tool.h"

// C program of finding modulo multiplication
#include <stdio.h>

// Returns (a * b) % mod
bignum moduloMultiplication(bignum a, bignum b, bignum mod)
{
    bignum res = 0; // Initialize result

    // Update a if it is more than
    // or equal to mod
    a %= mod;

    while (b)
    {
        // If b is odd, add a with result
        if (b & 1)
            res = (res + a) % mod;

        // Here we assume that doing 2*a
        // doesn't cause overflow
        a = (2 * a) % mod;

        b >>= 1; // b = b / 2
    }

    return res;
}

bignum powMod(bignum base, bignum index, bignum mod)
{
    bignum res = 1; // Initialize result

    while (index > 0)
    {
        // If index is odd, multiply base with result
        if (index & 1u)
            res = moduloMultiplication(res, base, mod);

        // index must be even now
        index = index >> 1;           // index = index/2
        base = moduloMultiplication(base, base, mod); // Change base to base^2%mod
    }
    return (res % mod);
}

// generate unsigned __int64 random number
unsigned __int64 uint64Rand()
{
    ASSERT((0x7FFF == RAND_MAX))
    unsigned __int64 r = 0;

    for (int i = 0; i < 5; ++i)
    {
        r = (r << 15) | (rand() & 0x7FFF);
    }

    return r & 0xFFFFFFFFFFFFFFFFULL;
}


unsigned __int128 uint128Rand()
{
    ASSERT((0x7FFF == RAND_MAX))
    bignum r = 0;

    for (int i = 0; i < 9; ++i)
    {
        r = (r << 15) | (rand() & 0x7FFF);
    }

    __int128 allone = 0;
    allone--;
    return r & allone;
}

// n为大于3的数
bool isprime(bignum n)
{
    ASSERT((n > 3))

    if (n % 2 == 0)
    {
        return false;
    }

    // n-1 = 2^k * m
    int k = 0;
    bignum m = n - 1;
    for (; m % 2 == 0; m /= 2)
    {
        k++;
    }
    // 使用 Miller-Rabin算法
    for (int i = 0; i < 100; i++)
    {
        bignum a = uint128Rand() % (n - 2) + 2;
        bignum b = powMod(a, m, n);
        if (b == 1)
        {
            continue;
        }
        for (int i = 0; i < k; i++)
        {
            if (b == n - 1)
            {
                goto ENDMillerRabin;
            }
            else
            {
                b = powMod(b, b, n);
            }
        }
        return false;
    ENDMillerRabin:;
    }
    return true;
}

//判断x, y是否互质
bool coprime(bignum x, bignum y)
{
    bignum tmp;

    if (y > x)
    {
        EXCHANGE(x, y, tmp);
    }
    if (x == y || x % y == 0)
    {
        return false;
    }

    while (true)
    {
        x %= y;
        if (y > x)
        {
            EXCHANGE(x, y, tmp);
        }
        if (y == 1)
        {
            return true;
        }
        if (x % y == 0)
        {
            return false;
        }
    }
}

// C program to find multiplicative modulo inverse using
// Extended Euclid algorithm.

// C function for extended Euclidean Algorithm
bignum gcdExtended(bignum a, bignum b, bignum *x, bignum *y)
{
    // Base Case
    if (a == 0)
    {
        *x = 0, *y = 1;
        return b;
    }

    bignum x1, y1; // To store results of recursive call
    bignum gcd = gcdExtended(b % a, a, &x1, &y1);

    // Update x and y using results of recursive
    // call
    *x = y1 - (b / a) * x1;
    *y = x1;

    return gcd;
}

// Function to find modulo inverse of a
bignum modInverse(bignum a, bignum m)
{
    bignum x, y;
    if (gcdExtended(a, m, &x, &y) != 1)
    {
        printf("Inverse doesn't exist");
        exit(1);
    }

    // m is added to handle negative x
    bignum res = (x % m + m) % m;
    return res;
}


// 将int128类型的整数保存到文件
void int128tofile(unsigned __int128 num, FILE *fp)
{
    if (num == 0)
    {
        fputc('0', fp);
    }
    else
    {
        char c;
        char str[33];
        int i = 0;
        int remain;
        while (num != 0)
        {
            remain = num % 16;
            num /= 16;
            if (remain < 10)
            {
                c = '0' + remain;
            }
            else
            {
                c = 'A' + (remain - 10);
            }
            str[i++] = c;
        }
        while (i > 0)
        {
            fputc(str[--i], fp);
        }
    }
}

//将hex的string转换成 int128
unsigned __int128 stringToInt128(char *str)
{
    unsigned __int128 num = 0;
    for (int i = 0; str[i] != 0; i++)
    {
        if ('0' <= str[i] && str[i] <= '9')
        {
            num = num * 16 + (str[i] - '0');
        }
        else if ('A' <= str[i] && str[i] <= 'F')
        {
            num = num * 16 + (str[i] - 'A' + 10);
        }
        else if ('a' <= str[i] && str[i] <= 'f')
        {
            num = num * 16 + (str[i] - 'a' + 10);
        }
        else
        {
            printf("Invalid hex string");
            exit(1);
        }
    }
    return num;
}

keyGenerator:密钥生成

keyGenerator.c

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "tool.h"

#define MIN_PRIME 10000000000ull
#define MAX_PRIME 100000000000ull

// generate a prime bignum > min
bignum generatePrime(bignum min, bignum max)
{
    bignum result;
    while (true)
    {
        result = uint64Rand() % max;
        if (result > min && isprime(result))
        {
            return result;
        }
    }
}

void generateKey()
{
    bignum p = generatePrime(MIN_PRIME, MAX_PRIME);
    bignum q = generatePrime(MIN_PRIME, MAX_PRIME);
    ASSERT(coprime(p, q))

    bignum n = (bignum)p * q;
    bignum fain = (bignum)(p - 1) * (q - 1);

    // fain 与 e 互素
    bignum e = uint128Rand() % fain;
    while(!coprime(fain, e))
    {
        e = uint128Rand() % fain;
    }
    bignum d = modInverse(e, fain);

    // 写入文件
    FILE *p_txt = fopen("p.txt", "w");
    int128tofile(p, p_txt);
    fclose(p_txt);

    FILE *q_txt = fopen("q.txt", "w");
    int128tofile(q, q_txt);
    fclose(q_txt);

    FILE *n_txt = fopen("n.txt", "w");
    int128tofile(n, n_txt);
    fclose(n_txt);

    FILE *e_txt = fopen("e.txt", "w");
    int128tofile(e, e_txt);
    fclose(e_txt);

    FILE *d_txt = fopen("d.txt", "w");
    int128tofile(d, d_txt);
    fclose(d_txt);
}




int main()
{
    generateKey();
    return 0;
}

RSA

rsa.h

#ifndef _rsa_h_
#define _rsa_h_

#include "tool.h"
// rsa加密
bignum rsaEncrypt(bignum m, bignum e, bignum n);

// rsa解密与签名
bignum rsaSign(bignum m, bignum d, bignum n);

#endif

rsa.c

#include "tool.h"

bignum rsaEncrypt(bignum m, bignum e, bignum n)
{
    return powMod(m, e, n);
}

bignum rsaSign(bignum m, bignum d, bignum n)
{
    return powMod(m, d, n);
}

main.c

#include <stdio.h>
#include "rsa.h"
#include <string.h>

bool cipher(char *n_path, char *e_path, char *message_path, char *out_path)
{
    // rsa_cipher
    FILE *n_fp = fopen(n_path, "r");
    if (n_fp == NULL)
    {
        printf("Unable to open %s\n", n_path);
        return false;
    }

    FILE *e_fp = fopen(e_path, "r");
    if (e_fp == NULL)
    {
        printf("Unable to open %s\n", e_path);
        return false;
    }

    FILE *m_fp = fopen(message_path, "r");
    if (m_fp == NULL)
    {
        printf("Unable to open %s\n", message_path);
        return false;
    }

    FILE *out_fp = fopen(out_path, "w");
    if (out_fp == NULL)
    {
        printf("Unable to open %s\n", out_path);
        return false;
    }

    char n_str[50];
    fscanf(n_fp, "%s", n_str);
    fclose(n_fp);

    char e_str[50];
    fscanf(e_fp, "%s", e_str);
    fclose(e_fp);

    char m_str[50];
    fscanf(m_fp, "%s", m_str);
    fclose(m_fp);

    bignum n = stringToInt128(n_str);
    bignum e = stringToInt128(e_str);
    bignum m = stringToInt128(m_str);

    bignum c = rsaEncrypt(m, e, n);

    int128tofile(c, out_fp);
    fclose(out_fp);
    return true;
}

bool sign(char *hash_path, char *n_path, char *d_path, char *out_path)
{
    FILE *hash_fp = fopen(hash_path, "r");
    if (hash_fp == NULL)
    {
        printf("Unable to open %s\n", hash_path);
        return false;
    }

    FILE *n_fp = fopen(n_path, "r");
    if (n_fp == NULL)
    {
        printf("Unable to open %s\n", n_path);
        return false;
    }

    FILE *d_fp = fopen(d_path, "r");
    if (d_fp == NULL)
    {
        printf("Unable to open %s\n", d_path);
        return false;
    }

    FILE *out_fp = fopen(out_path, "w");
    if (out_fp == NULL)
    {
        printf("Unable to open %s\n", out_path);
        return false;
    }

    char n_str[50];
    fscanf(n_fp, "%s", n_str);
    fclose(n_fp);

    char d_str[50];
    fscanf(d_fp, "%s", d_str);
    fclose(d_fp);

    char hash_str[50];
    fscanf(hash_fp, "%s", hash_str);
    fclose(hash_fp);

    bignum n = stringToInt128(n_str);
    bignum d = stringToInt128(d_str);
    bignum hash = stringToInt128(hash_str);

    bignum c = rsaSign(hash, d, n);

    int128tofile(c, out_fp);
    fclose(out_fp);
    return true;
}
int main(int argc, char *argv[])
{
    char *plainfile = NULL;
    char *nfile = NULL;
    char *efile = NULL;
    char *dfile = NULL;
    char *cipherfile = NULL;
    for (int i = 1; i < argc; i++)
    {
        if (strcmp(argv[i], "-p") == 0)
        {
            plainfile = argv[++i];
        }
        else if (strcmp(argv[i], "-n") == 0)
        {
            nfile = argv[++i];
        }
        else if (strcmp(argv[i], "-e") == 0)
        {
            efile = argv[++i];
        }
        else if (strcmp(argv[i], "-d") == 0)
        {
            dfile = argv[++i];
        }
        else if (strcmp(argv[i], "-c") == 0)
        {
            cipherfile = argv[++i];
        }
        else
        {
            printf("-p plainfile\t指定明文文件的位置和名称\n");
            printf("-n nfile\t指定存放整数 n 的文件的位置和名称\n");
            printf("-e efile\t在数据加密时, 指定存放整数 e 的文件的位置和名称\n");
            printf("-d dfile\t在数字签名时, 指定存放整数 d 的文件的位置和名称\n");
            printf("-c cipherfile\t指定密文文件的位置和名称\n");
        }
    }
    
    if (efile != NULL && dfile == NULL)
    {
        if (cipher(nfile, efile, plainfile, cipherfile))
        {
            printf("RSA Encryption success!\n");
        }
    }
    else if (efile == NULL && dfile != NULL)
    {
        if (sign(plainfile, nfile, dfile, cipherfile))
        {
            printf("RSA Sign success!\n");
        }
    }
    else
    {
        printf("arguments error!\n");
    }
   
    return 0;
}
main.exe -p plainfile -n nfile [-e efile] [-d dfile] -c cipherfile 

参数:
-p plainfile 指定明文文件的位置和名称
-n nfile 指定存放整数 n 的文件的位置和名称
-e efile 在数据加密时,指定存放整数 e 的文件的位置和名称
-d dfile 在数字签名时,指定存放整数 d 的文件的位置和名称
-c cipherfile 指定密文文件的位置和名称

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值