/** * Divide two bignums by naive long division, producing both a quotient and remainder. * quotient = floor(b1/b2), remainder = b1 - quotient * b2. If b1 < b2 the quotient is * trivially 0 and remainder is b2. */ void bignum_divide(bignum* quotient, bignum* remainder, bignum* b1, bignum* b2) { bignum *b2copy = bignum_init(), *b1copy = bignum_init(); bignum *temp = bignum_init(), *temp2 = bignum_init(), *temp3 = bignum_init(); bignum* quottemp = bignum_init(); word carry = 0; int n, m, i, j, length = 0; unsigned long long factor = 1; unsigned long long gquot, gtemp, grem; if(bignum_less(b1, b2)) { /* Trivial case, b1/b2 = 0 iff b1 < b2. */ quotient->length = 0; bignum_copy(b1, remainder); } else if(bignum_iszero(b1)) { /* 0/x = 0.. assuming b2 is nonzero */ quotient->length = 0; bignum_fromint(remainder, 0); } else if(b2->length == 1) { /* Division by a single limb means we can do simple division */ if(quotient->capacity < b1->length) { quotient->capacity = b1->length; quotient->data = realloc(quotient->data, quotient->capacity * sizeof(word)); } for(i = b1->length - 1; i >= 0; i--) { gtemp = carry * RADIX + b1->data[i]; gquot = gtemp / b2->data[0]; quotient->data[i] = (unsigned)gquot; if(quotient->data[i] != 0 && length == 0) length = i + 1; carry = gtemp % b2->data[0]; } bignum_fromint(remainder, carry); quotient->length = length; } else { /* Long division is neccessary */ n = b1->length + 1; m = b2->length; if(quotient->capacity < n - m) { quotient->capacity = n - m; quotient->data = realloc(quotient->data, (n - m) * sizeof(word)); } bignum_copy(b1, b1copy); bignum_copy(b2, b2copy); /* Normalize.. multiply by the divisor by 2 until MSB >= HALFRADIX. This ensures fast * convergence when guessing the quotient below. We also multiply the dividend by the * same amount to ensure the result does not change. */ while(b2copy->data[b2copy->length - 1] < HALFRADIX) { factor *= 2; bignum_imultiply(b2copy, &NUMS[2]); } if(factor > 1) { bignum_fromint(temp, (unsigned)factor); bignum_imultiply(b1copy, temp); } /* Ensure the dividend is longer than the original (pre-normalized) divisor. If it is not * we introduce a dummy zero word to artificially inflate it. */ if(b1copy->length != n) { b1copy->length++; if(b1copy->length > b1copy->capacity) { b1copy->capacity = b1copy->length; b1copy->data = realloc(b1copy->data, b1copy->capacity * sizeof(word)); } b1copy->data[n - 1] = 0; } /* Process quotient by long division */ for(i = n - m - 1; i >= 0; i--) { gtemp = RADIX * b1copy->data[i + m] + b1copy->data[i + m - 1]; gquot = gtemp / b2copy->data[m - 1]; if(gquot >= RADIX) gquot = UINT_MAX; grem = gtemp % b2copy->data[m - 1]; while(grem < RADIX && gquot * b2copy->data[m - 2] > RADIX * grem + b1copy->data[i + m - 2]) { /* Should not overflow... ? */ gquot--; grem += b2copy->data[m - 1]; } quottemp->data[0] = (unsigned)gquot % RADIX; quottemp->data[1] = (gquot / RADIX); if(quottemp->data[1] != 0) quottemp->length = 2; else quottemp->length = 1; bignum_multiply(temp2, b2copy, quottemp); if(m + 1 > temp3->capacity) { temp3->capacity = m + 1; temp3->data = realloc(temp3->data, temp3->capacity * sizeof(word)); } temp3->length = 0; for(j = 0; j <= m; j++) { temp3->data[j] = b1copy->data[i + j]; if(temp3->data[j] != 0) temp3->length = j + 1; } if(bignum_less(temp3, temp2)) { bignum_iadd(temp3, b2copy); gquot--; } bignum_isubtract(temp3, temp2); for(j = 0; j < temp3->length; j++) b1copy->data[i + j] = temp3->data[j]; for(j = temp3->length; j <= m; j++) b1copy->data[i + j] = 0; quotient->data[i] = (unsigned)gquot; if(quotient->data[i] != 0) quotient->length = i; } if(quotient->data[b1->length - b2->length] == 0) quotient->length = b1->length - b2->length; else quotient->length = b1->length - b2->length + 1; /* Divide by factor now to find final remainder */ carry = 0; for(i = b1copy->length - 1; i >= 0; i--) { gtemp = carry * RADIX + b1copy->data[i]; b1copy->data[i] = (unsigned)gtemp/factor; if(b1copy->data[i] != 0 && length == 0) length = i + 1; carry = (unsigned)gtemp % factor; } b1copy->length = length; bignum_copy(b1copy, remainder); } bignum_deinit(temp); bignum_deinit(temp2); bignum_deinit(temp3); bignum_deinit(b1copy); bignum_deinit(b2copy); bignum_deinit(quottemp); }
int main(int argc, const char * argv[]) { char *p=(char*)malloc(BUF_SIZE*sizeof(char)); printf("\n请输入选择的大素数p:\n"); scanf("%s",p); bignum *p1 = bignum_init(); bignum_fromstring(p1, p); free(p); if(probablePrime(p1, ACCURACY)) { printf("p合理"); bignum *yz = bignum_init(); bignum_fromint(yz, 3); if (bignum_equal(yz,p1)) { printf("但p太小不适用!\n"); return 1; } }else{ printf("p不是素数!\n"); return 1; } bignum *p2 = bignum_init(); bignum *temp = bignum_init(); bignum_fromint(temp, 1); bignum_subtract(p2, p1, temp); printf("\n请输入选择的本原元α:\n"); char *a=(char*)malloc(BUF_SIZE*sizeof(char)); scanf("%s",a); bignum *a1 = bignum_init(); bignum_fromstring(a1, a); free(a); printf("\n请输入选择的随机整数d:(2<=d<=p-2)\n"); char *d=(char*)malloc(BUF_SIZE*sizeof(char)); scanf("%s",d); bignum *d1 = bignum_init(); bignum_fromstring(d1, d); free(d); bignum *yz0 = bignum_init(); bignum_fromint(yz0, 2); bignum *yz1 = bignum_init(); bignum_subtract(yz1, p1, yz0); if( (bignum_greater(d1, yz0)||bignum_equal(d1, yz0))&&(bignum_greater(yz1,d1)||bignum_equal(yz1,d1)) ) { printf("d合理"); }else{ printf("d不合要求!\n"); return 1; } printf("\n请输入您的消息x:\n"); char *x=(char*)malloc(BUF_SIZE*sizeof(char)); scanf("%s",x); bignum *x1 = bignum_init(); bignum_fromstring(x1, x); free(x); printf("\n请输入您选择的k:(2<=k<=p-2且k应与p-1互质)\n"); char *k=(char*)malloc(BUF_SIZE*sizeof(char)); scanf("%s",k); bignum *k1 = bignum_init(); bignum_fromstring(k1, k); free(k); if( (bignum_greater(k1, yz0)||bignum_equal(k1, yz0))&&(bignum_greater(yz1,k1)||bignum_equal(yz1,k1)) ) { bignum *yz2 = bignum_init(); bignum_gcd(k1, p2, yz2); if (!bignum_equal(yz2,temp)) { printf("k不合要求!\n"); return 1; } printf("k合理"); }else{ printf("k不合要求!\n"); return 1; } bignum *b1 = bignum_init(); bignum_modpow(a1,d1,p1,b1); printf("\n\n所以\n您生成的公钥(p,α,β)为:\t("); bignum_print(p1); printf(","); bignum_print(a1); printf(","); bignum_print(b1); printf(")\n"); printf("您的私钥为:"); bignum_print(d1); printf("\n"); printf("您发出的消息(x(r,s))为:\t("); bignum_print(x1); printf(",("); bignum *r1 = bignum_init(); bignum_modpow(a1,k1,p1,r1); bignum_print(r1); printf(","); bignum *s1=bignum_init(); bignum_multiply(temp, d1, r1); bignum *temp2 = bignum_init(); bignum *x2 = bignum_init(); bignum_copy(x1, x2); while (bignum_less(x2, temp)) { bignum *add = bignum_init(); bignum_copy(p2, add); bignum_iadd(x2, add) ; } bignum_subtract(temp2, x2, temp); // printf("\ntemp2:"); // bignum_print(temp2); // printf("\t"); // bignum_print(x2); // printf("\t"); // bignum_print(temp); // printf("\n"); bignum_inverse(k1, p2, temp);//计算a的逆元result = a^-1 mod m bignum_multiply(s1, temp, temp2); bignum_imodulate(s1, p2);//source = source % modulus bignum_print(s1); printf("))\n"); bignum *t0 = bignum_init(); bignum_modpow(a1,x1,p1,t0); bignum *t1 = bignum_init(); bignum_modpow(b1,r1,p1,t1); bignum *t2 = bignum_init(); bignum_modpow(r1,s1,p1,t2); bignum *t3 = bignum_init(); bignum_multiply(t3, t1, t2); bignum_imodulate(t3, p1); printf("按t=(α^x)mod p,结果为:"); bignum_print(t0); printf("\n按t=(β^r*r^s)mod p,结果为:"); bignum_print(t3); printf("\n"); if (bignum_equal(t0, t3)) { printf("此签名正确有效~\n\n"); }else{ printf("此签名错误无效!\n\n"); } }
/** * Check if bignum b1 is greater than or equal to b2 */ int bignum_geq(bignum* b1, bignum* b2) { return !bignum_less(b1, b2); }
/** * 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 i, bytes, len; bignum *p = bignum_init(), *q = bignum_init(), *n = bignum_init(); bignum *phi = bignum_init(), *e = bignum_init(), *d = bignum_init(); bignum *bbytes = bignum_init(), *shift = bignum_init(); bignum *temp1 = bignum_init(), *temp2 = bignum_init(); bignum *encoded; int *decoded; char *buffer; FILE* f; srand(time(NULL)); randPrime(FACTOR_DIGITS, p); printf("Got first prime factor, p = "); bignum_print(p); printf(" ... "); getchar(); randPrime(FACTOR_DIGITS, q); printf("Got second prime factor, q = "); bignum_print(q); printf(" ... "); getchar(); bignum_multiply(n, p, q); printf("Got modulus, n = pq = "); bignum_print(n); printf(" ... "); getchar(); bignum_subtract(temp1, p, &NUMS[1]); bignum_subtract(temp2, q, &NUMS[1]); bignum_multiply(phi, temp1, temp2); /* phi = (p - 1) * (q - 1) */ printf("Got totient, phi = "); bignum_print(phi); printf(" ... "); getchar(); randExponent(phi, EXPONENT_MAX, e); printf("Chose public exponent, e = "); bignum_print(e); printf("\nPublic key is ("); bignum_print(e); printf(", "); bignum_print(n); printf(") ... "); getchar(); bignum_inverse(e, phi, d); printf("Calculated private exponent, d = "); bignum_print(d); printf("\nPrivate key is ("); bignum_print(d); printf(", "); bignum_print(n); printf(") ... "); getchar(); /* Compute maximum number of bytes that can be encoded in one encryption */ bytes = -1; bignum_fromint(shift, 1 << 7); /* 7 bits per char */ bignum_fromint(bbytes, 1); while(bignum_less(bbytes, n)) { bignum_imultiply(bbytes, shift); /* Shift by one byte, NB: we use bitmask representative so this can actually be a shift... */ bytes++; } printf("Opening file \"text.txt\" for reading\n"); f = fopen("text.txt", "r"); if(f == NULL) { printf("Failed to open file \"text.txt\". Does it exist?\n"); return EXIT_FAILURE; } len = readFile(f, &buffer, bytes); /* len will be a multiple of bytes, to send whole chunks */ printf("File \"text.txt\" read successfully, %d bytes read. Encoding byte stream in chunks of %d bytes ... ", len, bytes); getchar(); printf("\n"); encoded = encodeMessage(len, bytes, buffer, e, n); printf("\n\nEncoding finished successfully ... "); getchar(); printf("Decoding encoded message ... "); getchar(); printf("\n"); decoded = decodeMessage(len/bytes, bytes, encoded, d, n); printf("\n\nFinished RSA demonstration!"); /* Eek! This is why we shouldn't of calloc'd those! */ for(i = 0; i < len/bytes; i++) free(encoded[i].data); free(encoded); free(decoded); free(buffer); bignum_deinit(p); bignum_deinit(q); bignum_deinit(n); bignum_deinit(phi); bignum_deinit(e); bignum_deinit(d); bignum_deinit(bbytes); bignum_deinit(shift); bignum_deinit(temp1); bignum_deinit(temp2); fclose(f); return EXIT_SUCCESS; }