/** * Perform an in place divide of source. source = source/div. */ void bignum_idivide(bignum *source, bignum *div) { bignum *q = bignum_init(), *r = bignum_init(); bignum_divide(q, r, source, div); bignum_copy(q, source); bignum_deinit(q); bignum_deinit(r); }
/** * Modulate the source by the modulus. source = source % modulus */ void bignum_imodulate(bignum* source, bignum* modulus) { bignum *q = bignum_init(), *r = bignum_init(); bignum_divide(q, r, source, modulus); bignum_copy(r, source); bignum_deinit(q); bignum_deinit(r); }
int crypto_mod_exp(const u8 *base, size_t base_len, const u8 *power, size_t power_len, const u8 *modulus, size_t modulus_len, u8 *result, size_t *result_len) { struct bignum *bn_base, *bn_exp, *bn_modulus, *bn_result; int ret = 0; bn_base = bignum_init(); bn_exp = bignum_init(); bn_modulus = bignum_init(); bn_result = bignum_init(); if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL || bn_result == NULL) goto error; if (bignum_set_unsigned_bin(bn_base, base, base_len) < 0 || bignum_set_unsigned_bin(bn_exp, power, power_len) < 0 || bignum_set_unsigned_bin(bn_modulus, modulus, modulus_len) < 0) goto error; if (bignum_exptmod(bn_base, bn_exp, bn_modulus, bn_result) < 0) goto error; ret = bignum_get_unsigned_bin(bn_result, result, result_len); error: bignum_deinit(bn_base); bignum_deinit(bn_exp); bignum_deinit(bn_modulus); bignum_deinit(bn_result); return ret; }
/** * Perform an in place divide of source, also producing a remainder. * source = source/div and remainder = source - source/div. */ void bignum_idivider(bignum* source, bignum* div, bignum* remainder) { bignum *q = bignum_init(), *r = bignum_init(); bignum_divide(q, r, source, div); bignum_copy(q, source); bignum_copy(r, remainder); bignum_deinit(q); bignum_deinit(r); }
/** * Compute the inverse of a mod m. Or, result = a^-1 mod m. */ void bignum_inverse(bignum* a, bignum* m, bignum* result) { bignum *remprev = bignum_init(), *rem = bignum_init(); bignum *auxprev = bignum_init(), *aux = bignum_init(); bignum *rcur = bignum_init(), *qcur = bignum_init(), *acur = bignum_init(); bignum_copy(m, remprev); bignum_copy(a, rem); bignum_fromint(auxprev, 0); bignum_fromint(aux, 1); while(bignum_greater(rem, &NUMS[1])) { bignum_divide(qcur, rcur, remprev, rem); /* Observe we are finding the inverse in a finite field so we can use * a modified algorithm that avoids negative numbers here */ bignum_subtract(acur, m, qcur); bignum_imultiply(acur, aux); bignum_iadd(acur, auxprev); bignum_imodulate(acur, m); bignum_copy(rem, remprev); bignum_copy(aux, auxprev); bignum_copy(rcur, rem); bignum_copy(acur, aux); } bignum_copy(acur, result); bignum_deinit(remprev); bignum_deinit(rem); bignum_deinit(auxprev); bignum_deinit(aux); bignum_deinit(rcur); bignum_deinit(qcur); bignum_deinit(acur); }
/** * Compute the gcd of two bignums. result = gcd(b1, b2) */ void bignum_gcd(bignum* b1, bignum* b2, bignum* result) { bignum *a = bignum_init(), *b = bignum_init(), *remainder = bignum_init(); bignum *temp = bignum_init(), *discard = bignum_init(); bignum_copy(b1, a); bignum_copy(b2, b); while(!bignum_equal(b, &NUMS[0])) { bignum_copy(b, temp); bignum_imodulate(a, b); bignum_copy(a, b); bignum_copy(temp, a); } bignum_copy(a, result); bignum_deinit(a); bignum_deinit(b); bignum_deinit(remainder); bignum_deinit(temp); bignum_deinit(discard); }
/** * Check whether a is a Euler witness for n. That is, if a^(n - 1)/2 != Ja(a, n) mod n */ int solovayPrime(int a, bignum* n) { bignum *ab = bignum_init(), *res = bignum_init(), *pow = bignum_init(); bignum *modpow = bignum_init(); int x, result; bignum_fromint(ab, a); x = bignum_jacobi(ab, n); if(x == -1) bignum_subtract(res, n, &NUMS[1]); else bignum_fromint(res, x); bignum_copy(n, pow); bignum_isubtract(pow, &NUMS[1]); bignum_idivide(pow, &NUMS[2]); bignum_modpow(ab, pow, n, modpow); result = !bignum_equal(res, &NUMS[0]) && bignum_equal(modpow, res); bignum_deinit(ab); bignum_deinit(res); bignum_deinit(pow); bignum_deinit(modpow); return result; }
/** * Print a bignum to stdout as base 10 integer. This is done by * repeated division by 10. We can make it more efficient by dividing by * 10^9 for example, then doing single precision arithmetic to retrieve the * 9 remainders */ void bignum_print(bignum* b) { int cap = 100, len = 0, i; char* buffer = malloc(cap * sizeof(char)); bignum *copy = bignum_init(), *remainder = bignum_init(); if(b->length == 0 || bignum_iszero(b)) printf("0"); else { bignum_copy(b, copy); while(bignum_isnonzero(copy)) { bignum_idivider(copy, &NUMS[10], remainder); buffer[len++] = remainder->data[0]; if(len >= cap) { cap *= 2; buffer = realloc(buffer, cap * sizeof(char)); } } for(i = len - 1; i >= 0; i--) printf("%d", buffer[i]); } bignum_deinit(copy); bignum_deinit(remainder); free(buffer); }
/** * crypto_rsa_free - Free RSA key * @key: RSA key to be freed * * This function frees an RSA key imported with either * crypto_rsa_import_public_key() or crypto_rsa_import_private_key(). */ void crypto_rsa_free(struct crypto_rsa_key *key) { if (key) { bignum_deinit(key->n); bignum_deinit(key->e); bignum_deinit(key->d); bignum_deinit(key->p); bignum_deinit(key->q); bignum_deinit(key->dmp1); bignum_deinit(key->dmq1); bignum_deinit(key->iqmp); os_free(key); } }
/** * Compute the jacobi symbol, J(ac, nc). */ int bignum_jacobi(bignum* ac, bignum* nc) { bignum *remainder = bignum_init(), *twos = bignum_init(); bignum *temp = bignum_init(), *a = bignum_init(), *n = bignum_init(); int mult = 1, result = 0; bignum_copy(ac, a); bignum_copy(nc, n); while(bignum_greater(a, &NUMS[1]) && !bignum_equal(a, n)) { bignum_imodulate(a, n); if(bignum_leq(a, &NUMS[1]) || bignum_equal(a, n)) break; bignum_fromint(twos, 0); /* Factor out multiples of two */ while(a->data[0] % 2 == 0) { bignum_iadd(twos, &NUMS[1]); bignum_idivide(a, &NUMS[2]); } /* Coefficient for flipping */ if(bignum_greater(twos, &NUMS[0]) && twos->data[0] % 2 == 1) { bignum_remainder(n, &NUMS[8], remainder); if(!bignum_equal(remainder, &NUMS[1]) && !bignum_equal(remainder, &NUMS[7])) { mult *= -1; } } if(bignum_leq(a, &NUMS[1]) || bignum_equal(a, n)) break; bignum_remainder(n, &NUMS[4], remainder); bignum_remainder(a, &NUMS[4], temp); if(!bignum_equal(remainder, &NUMS[1]) && !bignum_equal(temp, &NUMS[1])) mult *= -1; bignum_copy(a, temp); bignum_copy(n, a); bignum_copy(temp, n); } if(bignum_equal(a, &NUMS[1])) result = mult; else result = 0; bignum_deinit(remainder); bignum_deinit(twos); bignum_deinit(temp); bignum_deinit(a); bignum_deinit(n); return result; }
/** * Perform modular exponentiation by repeated squaring. This will compute * result = base^exponent mod modulus */ void bignum_modpow(bignum* base, bignum* exponent, bignum* modulus, bignum* result) { bignum *a = bignum_init(), *b = bignum_init(), *c = bignum_init(); bignum *discard = bignum_init(), *remainder = bignum_init(); bignum_copy(base, a); bignum_copy(exponent, b); bignum_copy(modulus, c); bignum_fromint(result, 1); while(bignum_greater(b, &NUMS[0])) { if(b->data[0] & 1) { bignum_imultiply(result, a); bignum_imodulate(result, c); } bignum_idivide(b, &NUMS[2]); bignum_copy(a, discard); bignum_imultiply(a, discard); bignum_imodulate(a, c); } bignum_deinit(a); bignum_deinit(b); bignum_deinit(c); bignum_deinit(discard); bignum_deinit(remainder); }
/** * Choose a random public key exponent for the RSA algorithm. The exponent will * be less than the modulus, n, and coprime to phi. */ void randExponent(bignum* phi, int n, bignum* result) { bignum* gcd = bignum_init(); int e = rand() % n; while(1) { bignum_fromint(result, e); bignum_gcd(result, phi, gcd); if(bignum_equal(gcd, &NUMS[1])) { bignum_deinit(gcd); return; } e = (e + 1) % n; if(e <= 2) e = 3; } }
/** * 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); }
/** * 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; }
/** * Perform an in place multiplication into the source bignum. That is source *= mult */ void bignum_imultiply(bignum* source, bignum* mult) { bignum* temp = bignum_init(); bignum_multiply(temp, source, mult); bignum_copy(temp, source); bignum_deinit(temp); }
/** * Perform an in place subtract from the source bignum. That is, source -= sub */ void bignum_isubtract(bignum* source, bignum* sub) { bignum* temp = bignum_init(); bignum_subtract(temp, source, sub); bignum_copy(temp, source); bignum_deinit(temp); }
/** * Perform an in place add into the source bignum. That is source += add */ void bignum_iadd(bignum* source, bignum* add) { bignum* temp = bignum_init(); bignum_add(temp, source, add); bignum_copy(temp, source); bignum_deinit(temp); }
/** * Calculate the remainder when source is divided by div. */ void bignum_remainder(bignum* source, bignum *div, bignum* remainder) { bignum *q = bignum_init(); bignum_divide(q, remainder, source, div); bignum_deinit(q); }
/** * crypto_rsa_exptmod - RSA modular exponentiation * @in: Input data * @inlen: Input data length * @out: Buffer for output data * @outlen: Maximum size of the output buffer and used size on success * @key: RSA key * @use_private: 1 = Use RSA private key, 0 = Use RSA public key * Returns: 0 on success, -1 on failure */ int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen, struct crypto_rsa_key *key, int use_private) { struct bignum *tmp, *a = NULL, *b = NULL; int ret = -1; size_t modlen; if (use_private && !key->private_key) return -1; tmp = bignum_init(); if (tmp == NULL) return -1; if (bignum_set_unsigned_bin(tmp, in, inlen) < 0) goto error; if (bignum_cmp(key->n, tmp) < 0) { /* Too large input value for the RSA key modulus */ goto error; } if (use_private) { /* * Decrypt (or sign) using Chinese remainer theorem to speed * up calculation. This is equivalent to tmp = tmp^d mod n * (which would require more CPU to calculate directly). * * dmp1 = (1/e) mod (p-1) * dmq1 = (1/e) mod (q-1) * iqmp = (1/q) mod p, where p > q * m1 = c^dmp1 mod p * m2 = c^dmq1 mod q * h = q^-1 (m1 - m2) mod p * m = m2 + hq */ a = bignum_init(); b = bignum_init(); if (a == NULL || b == NULL) goto error; /* a = tmp^dmp1 mod p */ if (bignum_exptmod(tmp, key->dmp1, key->p, a) < 0) goto error; /* b = tmp^dmq1 mod q */ if (bignum_exptmod(tmp, key->dmq1, key->q, b) < 0) goto error; /* tmp = (a - b) * (1/q mod p) (mod p) */ if (bignum_sub(a, b, tmp) < 0 || bignum_mulmod(tmp, key->iqmp, key->p, tmp) < 0) goto error; /* tmp = b + q * tmp */ if (bignum_mul(tmp, key->q, tmp) < 0 || bignum_add(tmp, b, tmp) < 0) goto error; } else { /* Encrypt (or verify signature) */ /* tmp = tmp^e mod N */ if (bignum_exptmod(tmp, key->e, key->n, tmp) < 0) goto error; } modlen = crypto_rsa_get_modulus_len(key); if (modlen > *outlen) { *outlen = modlen; goto error; } if (bignum_get_unsigned_bin_len(tmp) > modlen) goto error; /* should never happen */ *outlen = modlen; os_memset(out, 0, modlen); if (bignum_get_unsigned_bin( tmp, out + (modlen - bignum_get_unsigned_bin_len(tmp)), NULL) < 0) goto error; ret = 0; error: bignum_deinit(tmp); bignum_deinit(a); bignum_deinit(b); return ret; }