引用自:https://github.com/pantaloons/RSA
- 使用C語言實現RSA算法,網上找了一圈,不是這出問題,就是那里出問題,有些根本都運行不了,錯誤太多,白白浪費時間;
- 絕望之際,在GitHub上看到了這位大佬,真的是大佬,究極膜拜;
- 話不多說,送上代碼(我有做修改);
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <time.h> 4 #include <string.h> 5 6 #define ACCURACY 5 7 #define SINGLE_MAX 10000 8 #define EXPONENT_MAX 1000 9 #define BUF_SIZE 1024 10 11 /** 12 * Computes a^b mod c,計算a^b mod c 13 */ 14 int modpow(long long a, long long b, int c) { 15 int res = 1; 16 while(b > 0) { 17 /* Need long multiplication else this will overflow... 18 必須使用長乘法,否則這將溢出*/ 19 if(b & 1) { 20 res = (res * a) % c; 21 } 22 b = b >> 1; 23 a = (a * a) % c; /* Same deal here */ 24 } 25 return res; 26 } 27 28 /** 29 * Computes the Jacobi symbol, (a, n),計算Jacobi符號(a,n) 30 */ 31 int jacobi(int a, int n) { 32 int twos, temp; 33 int mult = 1; 34 while(a > 1 && a != n) { 35 a = a % n; 36 if(a <= 1 || a == n) break; 37 twos = 0; 38 while(a % 2 == 0 && ++twos) a /= 2; /* Factor out multiples of 2 ,減去2的倍數*/ 39 if(twos > 0 && twos % 2 == 1) mult *= (n % 8 == 1 || n % 8 == 7) * 2 - 1; 40 if(a <= 1 || a == n) break; 41 if(n % 4 != 1 && a % 4 != 1) mult *= -1; /* Coefficient for flipping,翻轉系數 */ 42 temp = a; 43 a = n; 44 n = temp; 45 } 46 if(a == 0) return 0; 47 else if(a == 1) return mult; 48 else return 0; /* a == n => gcd(a, n) != 1 */ 49 } 50 51 /** 52 * Check whether a is a Euler witness for n,檢查a是否為n的歐拉見證 */ 53 int solovayPrime(int a, int n) { 54 int x = jacobi(a, n); 55 if(x == -1) x = n - 1; 56 return x != 0 && modpow(a, (n - 1)/2, n) == x; 57 } 58 59 /** 60 * Test if n is probably prime, using accuracy of k (k solovay tests),用k的精度檢查n是否可能是素數 */ 61 int probablePrime(int n, int k) { 62 if(n == 2) return 1; 63 else if(n % 2 == 0 || n == 1) return 0; 64 while(k-- > 0) { 65 if(!solovayPrime(rand() % (n - 2) + 2, n)) return 0; 66 } 67 return 1; 68 } 69 70 /** 71 * Find a random (probable) prime between 3 and n - 1在3和(n-1)之間找一個隨機素數, this distribution is, 72 * nowhere near uniform, see prime gaps 73 */ 74 int randPrime(int n) { 75 int prime = rand() % n; 76 n += n % 2; /* n needs to be even so modulo wrapping preserves oddness */ 77 prime += 1 - prime % 2; 78 while(1) { 79 if(probablePrime(prime, ACCURACY)) return prime; 80 prime = (prime + 2) % n; 81 } 82 } 83 84 /** 85 * Compute gcd(a, b),計算gcd(a,b) 86 */ 87 int gcd(int a, int b) { 88 int temp; 89 while(b != 0) { 90 temp = b; 91 b = a % b; 92 a = temp; 93 } 94 return a; 95 } 96 97 /** 98 * Find a random exponent x between 3 and n - 1 such that gcd(x, phi) = 1,在3和n-1之間找到隨機指數x,使得gcd(x,phi)=1 99 * this distribution is similarly nowhere near uniform,這種分布同樣不接近制服 100 */ 101 int randExponent(int phi, int n) { 102 int e = rand() % n; 103 while(1) { 104 if(gcd(e, phi) == 1) return e; 105 e = (e + 1) % n; 106 if(e <= 2) e = 3; 107 } 108 } 109 110 /** 111 * Compute n^-1 mod m by extended euclidian method,用擴展歐幾里得法計算n^-1 mod m 112 */ 113 int inverse(int n, int modulus) { 114 int a = n, b = modulus; 115 int x = 0, y = 1, x0 = 1, y0 = 0, q, temp; 116 while(b != 0) { 117 q = a / b; 118 temp = a % b; 119 a = b; 120 b = temp; 121 temp = x; x = x0 - q * x; x0 = temp; 122 temp = y; y = y0 - q * y; y0 = temp; 123 } 124 if(x0 < 0) x0 += modulus; 125 return x0; 126 } 127 128 /** 129 * Read the file fd into an array of bytes ready for encryption.將文件fd讀入准備加密的字節數組 130 * The array will be padded with zeros until it divides the number of數組將填充零,知道它划分每個塊加密的字節數 131 * bytes encrypted per block. Returns the number of bytes read.返回讀取的字節數 132 */ 133 int readFile(FILE* fd, char** buffer, int bytes) { 134 int len = 0, cap = BUF_SIZE, r; 135 char buf[BUF_SIZE]; 136 *buffer = (char *)malloc(BUF_SIZE * sizeof(char)); 137 while((r = fread(buf, sizeof(char), BUF_SIZE, fd)) > 0) { 138 if(len + r >= cap) { 139 cap *= 2; 140 *buffer = (char *)realloc(*buffer, cap); 141 } 142 memcpy(&(*buffer)[len], buf, r); 143 len += r; 144 } 145 /* Pad the last block with zeros to signal end of cryptogram. An additional block is added if there is no room,將最后一個帶有零的塊插入密碼的信號端。 如果沒有房間,則增加一個額外的街區 */ 146 if(len + bytes - len % bytes > cap) *buffer = (char *)realloc(*buffer, len + bytes - len % bytes); 147 do { 148 (*buffer)[len] = '\0'; 149 len++; 150 } 151 while(len % bytes != 0); 152 return len; 153 } 154 155 /** 156 * Encode the message m using public exponent and modulus, c = m^e mod n使用公共指數和模量對消息m進行編碼,c = m^e Mod n 157 */ 158 int encode(int m, int e, int n) { 159 return modpow(m, e, n); 160 } 161 162 /** 163 * Decode cryptogram c using private exponent and public modulus, m = c^d mod n,用私有指數和公共模量解碼密碼c,m = c^d Mod n 164 */ 165 int decode(int c, int d, int n) { 166 return modpow(c, d, n); 167 } 168 169 /** 170 * Encode the message of given length, using the public key (exponent, modulus) 171 * The resulting array will be of size len/bytes, each index being the encryption 172 * of "bytes" consecutive characters, given by m = (m1 + m2*128 + m3*128^2 + ..), 173 * encoded = m^exponent mod modulus 174 * 使用公鑰(指數、模數)對給定長度的消息進行編碼) 175 得到的數組將是大小為len/字節,每個索引是由m=(m1m2*128m3*128^2.)給出的“字節”連續字符的加密,編碼=m^指數mod模量 176 */ 177 int* encodeMessage(int len, int bytes, char* message, int exponent, int modulus) { 178 int *encoded = (int *)malloc((len/bytes) * sizeof(int)); 179 int x, i, j; 180 for(i = 0; i < len; i += bytes) { 181 x = 0; 182 for(j = 0; j < bytes; j++) x += message[i + j] * (1 << (7 * j)); 183 encoded[i/bytes] = encode(x, exponent, modulus); 184 #ifndef MEASURE 185 printf("%d ", encoded[i/bytes]); 186 #endif 187 } 188 return encoded; 189 } 190 191 /** 192 * Decode the cryptogram of given length, using the private key (exponent, modulus) 193 * Each encrypted packet should represent "bytes" characters as per encodeMessage. 194 * The returned message will be of size len * bytes. 195 * 使用私鑰(指數、模數)解碼給定長度的密碼) 196 每個加密的數據包應該按照編碼消息表示“字節”字符。 197 返回的消息大小為len*字節。 198 */ 199 int* decodeMessage(int len, int bytes, int* cryptogram, int exponent, int modulus) { 200 int *decoded = (int *)malloc(len * bytes * sizeof(int)); 201 int x, i, j; 202 for(i = 0; i < len; i++) { 203 x = decode(cryptogram[i], exponent, modulus); 204 for(j = 0; j < bytes; j++) { 205 decoded[i*bytes + j] = (x >> (7 * j)) % 128; 206 #ifndef MEASURE 207 if(decoded[i*bytes + j] != '\0') printf("%c", decoded[i*bytes + j]); 208 #endif 209 } 210 } 211 return decoded; 212 } 213 214 /** 215 * Main method to demostrate the system. Sets up primes p, q, and proceeds to encode and 216 * decode the message given in "text.txt" 217 * 系統降級的主要方法。 設置素數p,q,並開始編碼和 218 *解碼“text.txt”中給出的消息; 219 */ 220 int main(void) { 221 int p, q, n, phi, e, d, bytes, len; 222 int *encoded, *decoded; 223 char *buffer; 224 FILE *f; 225 srand(time(NULL)); 226 while(1) { 227 p = randPrime(SINGLE_MAX); 228 printf("生成第一個隨機素數, p = %d ... ", p); 229 getchar(); 230 231 q = randPrime(SINGLE_MAX); 232 printf("生成第二個隨機素數, q = %d ... ", q); 233 getchar(); 234 235 n = p * q; 236 printf("計算p和q的乘積n, n = pq = %d ... ", n); 237 if(n < 128) { 238 printf("Modulus is less than 128, cannot encode single bytes. Trying again ... "); 239 getchar(); 240 } 241 else break; 242 } 243 if(n >> 21) bytes = 3; 244 else if(n >> 14) bytes = 2; 245 else bytes = 1; 246 getchar(); 247 248 phi = (p - 1) * (q - 1); 249 printf("計算歐拉函數的值phi, phi = %d ... ", phi); 250 getchar(); 251 252 e = randExponent(phi, EXPONENT_MAX); 253 printf("選取一個隨機素數e, e = %d...\n獲得公鑰 (%d, %d) ... ", e, e, n); 254 getchar(); 255 256 d = inverse(e, phi); 257 printf("計算模反元素d, d = %d...\n獲得密鑰 (%d, %d) ... ", d, d, n); 258 getchar(); 259 260 printf("打開文件 \"text.txt\" 用於讀取信息\n"); 261 f = fopen("text.txt", "r"); 262 if(f == NULL) { 263 printf("Failed to open file \"text.txt\". Does it exist?\n"); 264 return EXIT_FAILURE; 265 } 266 len = readFile(f, &buffer, bytes); /* len will be a multiple of bytes, to send whole chunks倫將是多個字節,以發送整個塊 */ 267 fclose(f); 268 269 printf("文件 \"text.txt\" 讀取成功, 讀取到%d字節. 以%d字節的字節流編碼 ... ", len, bytes); 270 getchar(); 271 printf("加密得密文為:"); 272 encoded = encodeMessage(len, bytes, buffer, e, n); 273 printf("\n編碼成功完成 ... "); 274 getchar(); 275 276 277 printf("正在解碼編碼的信息 ... "); 278 getchar(); 279 printf("解碼得明文為:"); 280 decoded = decodeMessage(len/bytes, bytes, encoded, d, n); 281 282 283 printf("\nRSA算法演示完成!\n"); 284 285 free(encoded); 286 free(decoded); 287 free(buffer); 288 return EXIT_SUCCESS; 289 }
代碼沒有半點問題,跑就是了;
需要注意的是,運行代碼需要新建一個.txt文檔,里面存放你的明文,目前我試過支持數字和英文,中文不支持,其他還沒試過。把這個.txt文檔和代碼放在一個路徑里,注意代碼里的文件名和你的文件名,現在是text.txt;
這是運行結果,可以參考下;
以上為所有內容,🏄沖浪🏄♀️碼字不容易!!!
您的贊就是最好的肯定🙆♂️
//還是那句話,有什么問題,歡迎指正!!!🙏