term_t bignum_to_term(bignum_t *a, xpool_t *xp) { if (bn_size(a) == 0) return intnum(0); if (bn_sign(a) == 0 && bn_size(a) == 1 && a->digits[0] <= MAX_INT_VALUE) return intnum(a->digits[0]); if (bn_sign(a) == 1 && bn_size(a) == 1 && a->digits[0] <= MAX_INT_VALUE+1) return intnum(-(int_value_t)a->digits[0]); if (bn_sign(a) == 0 && bn_size(a) == 2) { apr_uint64_t v = (apr_uint64_t)a->digits[0] << 32; v += a->digits[1]; // somehow it doesn't work if combined with previous line if (v <= MAX_INT_VALUE) return intnum(v); } if (bn_sign(a) == 1 && bn_size(a) == 2) { apr_uint64_t v = (apr_uint64_t)a->digits[0] << 32; v += a->digits[1]; if (v <= MAX_INT_VALUE+1) return intnum(-(int_value_t)v); } return bignum(a); }
static int check_modulus_params(const struct BIGNUM *N, uint32_t *out_len) { if (bn_size(N) > RSA_MAX_BYTES) return 0; /* Unsupported key size. */ if (!bn_check_topbit(N)) /* Check that top bit is set. */ return 0; if (out_len && *out_len < bn_size(N)) return 0; /* Output buffer too small. */ return 1; }
int DCRYPTO_rsa_decrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len, const uint8_t *in, const uint32_t in_len, enum padding_mode padding, enum hashing_mode hashing, const char *label) { uint32_t encrypted_buf[RSA_MAX_WORDS]; uint32_t padded_buf[RSA_MAX_WORDS]; struct BIGNUM encrypted; struct BIGNUM padded; int ret = 1; if (!check_modulus_params(&rsa->N, out_len)) return 0; if (in_len != bn_size(&rsa->N)) return 0; /* Invalid input length. */ /* TODO(ngm): this copy can be eliminated if input may be modified. */ bn_init(&encrypted, encrypted_buf, in_len); memcpy(encrypted_buf, in, in_len); bn_init(&padded, padded_buf, in_len); /* Reverse from big-endian to little-endian notation. */ reverse((uint8_t *) encrypted.d, encrypted.dmax * BN_BYTES); bn_mont_modexp(&padded, &encrypted, &rsa->d, &rsa->N); /* Back to big-endian notation. */ reverse((uint8_t *) padded.d, padded.dmax * BN_BYTES); switch (padding) { case PADDING_MODE_OAEP: if (!check_oaep_pad(out, out_len, (uint8_t *) padded.d, bn_size(&padded), hashing, label)) ret = 0; break; case PADDING_MODE_PKCS1: if (!check_pkcs1_type2_pad( out, out_len, (const uint8_t *) padded.d, bn_size(&padded))) ret = 0; break; default: /* Unsupported padding mode. */ ret = 0; break; } dcrypto_memset(encrypted_buf, 0, sizeof(encrypted_buf)); dcrypto_memset(padded_buf, 0, sizeof(padded_buf)); return ret; }
int DCRYPTO_rsa_verify(struct RSA *rsa, const uint8_t *digest, uint32_t digest_len, const uint8_t *sig, const uint32_t sig_len, enum padding_mode padding, enum hashing_mode hashing) { uint32_t padded_buf[RSA_MAX_WORDS]; uint32_t signature_buf[RSA_MAX_WORDS]; uint32_t e_buf[BN_BYTES / sizeof(uint32_t)]; struct BIGNUM padded; struct BIGNUM signature; struct BIGNUM e; int ret = 1; if (!check_modulus_params(&rsa->N, NULL)) return 0; if (sig_len != bn_size(&rsa->N)) return 0; /* Invalid input length. */ bn_init(&signature, signature_buf, bn_size(&rsa->N)); memcpy(signature_buf, sig, bn_size(&rsa->N)); bn_init(&padded, padded_buf, bn_size(&rsa->N)); bn_init(&e, e_buf, sizeof(e_buf)); *e.d = rsa->e; /* Reverse from big-endian to little-endian notation. */ reverse((uint8_t *) signature.d, signature.dmax * BN_BYTES); bn_mont_modexp(&padded, &signature, &e, &rsa->N); /* Back to big-endian notation. */ reverse((uint8_t *) padded.d, padded.dmax * BN_BYTES); switch (padding) { case PADDING_MODE_PKCS1: if (!check_pkcs1_type1_pad( digest, digest_len, (uint8_t *) padded.d, bn_size(&padded), hashing)) ret = 0; break; default: /* Unsupported padding mode. */ ret = 0; break; } dcrypto_memset(padded_buf, 0, sizeof(padded_buf)); dcrypto_memset(signature_buf, 0, sizeof(signature_buf)); return ret; }
int DCRYPTO_rsa_encrypt(struct RSA *rsa, uint8_t *out, uint32_t *out_len, const uint8_t *in, const uint32_t in_len, enum padding_mode padding, enum hashing_mode hashing, const char *label) { uint32_t padded_buf[RSA_MAX_WORDS]; uint32_t e_buf[BN_BYTES / sizeof(uint32_t)]; struct BIGNUM padded; struct BIGNUM e; struct BIGNUM encrypted; if (!check_modulus_params(&rsa->N, out_len)) return 0; bn_init(&padded, padded_buf, bn_size(&rsa->N)); bn_init(&encrypted, out, bn_size(&rsa->N)); bn_init(&e, e_buf, sizeof(e_buf)); *e.d = rsa->e; switch (padding) { case PADDING_MODE_OAEP: if (!oaep_pad((uint8_t *) padded.d, bn_size(&padded), (const uint8_t *) in, in_len, hashing, label)) return 0; break; case PADDING_MODE_PKCS1: if (!pkcs1_type2_pad((uint8_t *) padded.d, bn_size(&padded), (const uint8_t *) in, in_len)) return 0; break; default: return 0; /* Unsupported padding mode. */ } /* Reverse from big-endian to little-endian notation. */ reverse((uint8_t *) padded.d, bn_size(&padded)); bn_mont_modexp(&encrypted, &padded, &e, &rsa->N); /* Back to big-endian notation. */ reverse((uint8_t *) encrypted.d, bn_size(&encrypted)); *out_len = bn_size(&encrypted); dcrypto_memset(padded_buf, 0, sizeof(padded_buf)); dcrypto_memset(e_buf, 0, sizeof(e_buf)); return 1; }
int DCRYPTO_rsa_sign(struct RSA *rsa, uint8_t *out, uint32_t *out_len, const uint8_t *in, const uint32_t in_len, enum padding_mode padding, enum hashing_mode hashing) { uint32_t padded_buf[RSA_MAX_WORDS]; struct BIGNUM padded; struct BIGNUM signature; if (!check_modulus_params(&rsa->N, out_len)) return 0; bn_init(&padded, padded_buf, bn_size(&rsa->N)); bn_init(&signature, out, bn_size(&rsa->N)); /* TODO(ngm): add support for PSS. */ switch (padding) { case PADDING_MODE_PKCS1: if (!pkcs1_type1_pad((uint8_t *) padded.d, bn_size(&padded), (const uint8_t *) in, in_len, hashing)) return 0; break; default: return 0; } /* Reverse from big-endian to little-endian notation. */ reverse((uint8_t *) padded.d, bn_size(&padded)); bn_mont_modexp(&signature, &padded, &rsa->d, &rsa->N); /* Back to big-endian notation. */ reverse((uint8_t *) signature.d, bn_size(&signature)); *out_len = bn_size(&rsa->N); dcrypto_memset(padded_buf, 0, sizeof(padded_buf)); return 1; }