zoukankan      html  css  js  c++  java
  • C语言实现的RSA算法程序

    源程序来自Gethub的Simple implementation of the RSA algorithm

    程序中有关类型转换代码略做修改,并且已经能够编译运行。

    程序如下:

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <string.h>
    
    #define ACCURACY 5
    #define SINGLE_MAX 10000
    #define EXPONENT_MAX 1000
    #define BUF_SIZE 1024
    
    /**
     * Computes a^b mod c
     */
    int modpow(long long a, long long b, int c) {
        int res = 1;
        while(b > 0) {
            /* Need long multiplication else this will overflow... */
            if(b & 1) {
                res = (res * a) % c;
            }
            b = b >> 1;
            a = (a * a) % c; /* Same deal here */
        }
        return res;
    }
    
    /**
     * Computes the Jacobi symbol, (a, n)
     */
    int jacobi(int a, int n) {
        int twos, temp;
        int mult = 1;
        while(a > 1 && a != n) {
            a = a % n;
            if(a <= 1 || a == n) break;
            twos = 0;
            while(a % 2 == 0 && ++twos) a /= 2; /* Factor out multiples of 2 */
            if(twos > 0 && twos % 2 == 1) mult *= (n % 8 == 1 || n % 8 == 7) * 2 - 1;
            if(a <= 1 || a == n) break;
            if(n % 4 != 1 && a % 4 != 1) mult *= -1; /* Coefficient for flipping */
            temp = a;
            a = n;
            n = temp;
        }
        if(a == 0) return 0;
        else if(a == 1) return mult;
        else return 0; /* a == n => gcd(a, n) != 1 */
    }
    
    /**
     * Check whether a is a Euler witness for n
     */
    int solovayPrime(int a, int n) {
        int x = jacobi(a, n);
        if(x == -1) x = n - 1;
        return x != 0 && modpow(a, (n - 1)/2, n) == x;
    }
    
    /**
     * Test if n is probably prime, using accuracy of k (k solovay tests)
     */
    int probablePrime(int n, int k) {
        if(n == 2) return 1;
        else if(n % 2 == 0 || n == 1) return 0;
        while(k-- > 0) {
            if(!solovayPrime(rand() % (n - 2) + 2, n)) return 0;
        }
        return 1;
    }
    
    /**
     * Find a random (probable) prime between 3 and n - 1, this distribution is
     * nowhere near uniform, see prime gaps
     */
    int randPrime(int n) {
        int prime = rand() % n;
        n += n % 2; /* n needs to be even so modulo wrapping preserves oddness */
        prime += 1 - prime % 2;
        while(1) {
            if(probablePrime(prime, ACCURACY)) return prime;
            prime = (prime + 2) % n;
        }
    }
    
    /**
     * Compute gcd(a, b)
     */
    int gcd(int a, int b) {
        int temp;
        while(b != 0) {
            temp = b;
            b = a % b;
            a = temp;
        }
        return a;
    }
    
    /**
     * Find a random exponent x between 3 and n - 1 such that gcd(x, phi) = 1,
     * this distribution is similarly nowhere near uniform
     */
    int randExponent(int phi, int n) {
        int e = rand() % n;
        while(1) {
            if(gcd(e, phi) == 1) return e;
            e = (e + 1) % n;
            if(e <= 2) e = 3;
        }
    }
    
    /**
     * Compute n^-1 mod m by extended euclidian method
     */
    int inverse(int n, int modulus) {
        int a = n, b = modulus;
        int x = 0, y = 1, x0 = 1, y0 = 0, q, temp;
        while(b != 0) {
            q = a / b;
            temp = a % b;
            a = b;
            b = temp;
            temp = x; x = x0 - q * x; x0 = temp;
            temp = y; y = y0 - q * y; y0 = temp;
        }
        if(x0 < 0) x0 += modulus;
        return x0;
    }
    
    /**
     * Read the file fd into an array of bytes ready for encryption.
     * The array will be padded with zeros until it divides the number of
     * bytes encrypted per block. Returns the number of bytes read.
     */
    int readFile(FILE* fd, char** buffer, int bytes) {
        int len = 0, cap = BUF_SIZE, r;
        char buf[BUF_SIZE];
        *buffer = (char *)malloc(BUF_SIZE * sizeof(char));
        while((r = fread(buf, sizeof(char), BUF_SIZE, fd)) > 0) {
            if(len + r >= cap) {
                cap *= 2;
                *buffer = (char *)realloc(*buffer, cap);
            }
            memcpy(&(*buffer)[len], buf, r);
            len += r;
        }
        /* Pad the last block with zeros to signal end of cryptogram. An additional block is added if there is no room */
        if(len + bytes - len % bytes > cap) *buffer = (char *)realloc(*buffer, len + bytes - len % bytes);
        do {
            (*buffer)[len] = '';
            len++;
        }
        while(len % bytes != 0);
        return len;
    }
    
    /**
     * Encode the message m using public exponent and modulus, c = m^e mod n
     */
    int encode(int m, int e, int n) {
        return modpow(m, e, n);
    }
    
    /**
     * Decode cryptogram c using private exponent and public modulus, m = c^d mod n
     */
    int decode(int c, int d, int n) {
        return modpow(c, d, n);
    }
    
    /**
     * Encode the message of given length, using the public key (exponent, modulus)
     * The resulting array will be of size len/bytes, each index being the encryption
     * of "bytes" consecutive characters, given by m = (m1 + m2*128 + m3*128^2 + ..),
     * encoded = m^exponent mod modulus
     */
    int* encodeMessage(int len, int bytes, char* message, int exponent, int modulus) {
        int *encoded = (int *)malloc((len/bytes) * sizeof(int));
        int x, i, j;
        for(i = 0; i < len; i += bytes) {
            x = 0;
            for(j = 0; j < bytes; j++) x += message[i + j] * (1 << (7 * j));
            encoded[i/bytes] = encode(x, exponent, modulus);
    #ifndef MEASURE
            printf("%d ", encoded[i/bytes]);
    #endif
        }
        return encoded;
    }
    
    /**
     * Decode the cryptogram of given length, using the private key (exponent, modulus)
     * Each encrypted packet should represent "bytes" characters as per encodeMessage.
     * The returned message will be of size len * bytes.
     */
    int* decodeMessage(int len, int bytes, int* cryptogram, int exponent, int modulus) {
        int *decoded = (int *)malloc(len * bytes * sizeof(int));
        int x, i, j;
        for(i = 0; i < len; i++) {
            x = decode(cryptogram[i], exponent, modulus);
            for(j = 0; j < bytes; j++) {
                decoded[i*bytes + j] = (x >> (7 * j)) % 128;
    #ifndef MEASURE
                if(decoded[i*bytes + j] != '') printf("%c", decoded[i*bytes + j]);
    #endif
            }
        }
        return decoded;
    }
    
    /**
     * Main method to demostrate the system. Sets up primes p, q, and proceeds to encode and
     * decode the message given in "text.txt"
     */
    int main(void) {
        int p, q, n, phi, e, d, bytes, len;
        int *encoded, *decoded;
        char *buffer;
        FILE *f;
        srand(time(NULL));
        while(1) {
            p = randPrime(SINGLE_MAX);
            printf("Got first prime factor, p = %d ... ", p);
            getchar();
    
            q = randPrime(SINGLE_MAX);
            printf("Got second prime factor, q = %d ... ", q);
            getchar();
    
            n = p * q;
            printf("Got modulus, n = pq = %d ... ", n);
            if(n < 128) {
                printf("Modulus is less than 128, cannot encode single bytes. Trying again ... ");
                getchar();
            }
            else break;
        }
        if(n >> 21) bytes = 3;
        else if(n >> 14) bytes = 2;
        else bytes = 1;
        getchar();
    
        phi = (p - 1) * (q - 1);
        printf("Got totient, phi = %d ... ", phi);
        getchar();
    
        e = randExponent(phi, EXPONENT_MAX);
        printf("Chose public exponent, e = %d
    Public key is (%d, %d) ... ", e, e, n);
        getchar();
    
        d = inverse(e, phi);
        printf("Calculated private exponent, d = %d
    Private key is (%d, %d) ... ", d, d, n);
        getchar();
    
        printf("Opening file "text.txt" for reading
    ");
        f = fopen("text.txt", "r");
        if(f == NULL) {
            printf("Failed to open file "text.txt". Does it exist?
    ");
            return EXIT_FAILURE;
        }
        len = readFile(f, &buffer, bytes); /* len will be a multiple of bytes, to send whole chunks */
        fclose(f);
    
        printf("File "text.txt" read successfully, %d bytes read. Encoding byte stream in chunks of %d bytes ... ", len, bytes);
        getchar();
        encoded = encodeMessage(len, bytes, buffer, e, n);
        printf("
    Encoding finished successfully ... ");
        getchar();
    
    
        printf("Decoding encoded message ... ");
        getchar();
        decoded = decodeMessage(len/bytes, bytes, encoded, d, n);
    
    
        printf("
    Finished RSA demonstration!
    ");
    
        free(encoded);
        free(decoded);
        free(buffer);
        return EXIT_SUCCESS;
    }


  • 相关阅读:
    087 类的继承
    086 一切皆对象
    085 对象的绑定方法
    在菜鸟教程学 HTML(一)
    生成输出 URL(16.2)
    创建分部视图(7.6.3)
    显示页面链接(7.5.1)
    NuGet 控制台代码
    浏览器对应用程序的根URL发出请求时所发生的情况(结合 DI)
    第 6 章 —— 依赖项注入(DI)容器 —— Ninject
  • 原文地址:https://www.cnblogs.com/tigerisland/p/7564843.html
Copyright © 2011-2022 走看看