// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifdef ESP_PLATFORM #include "esp_system.h" #include "mbedtls/bignum.h" #endif #include "utils/includes.h" #include "utils/common.h" #include "crypto.h" #include "random.h" #include "sha256.h" #include "mbedtls/pk.h" struct crypto_bignum *crypto_bignum_init(void) { mbedtls_mpi *bn = os_zalloc(sizeof(mbedtls_mpi)); if (bn == NULL) { return NULL; } mbedtls_mpi_init(bn); return (struct crypto_bignum *)bn; } struct crypto_bignum *crypto_bignum_init_set(const u8 *buf, size_t len) { int ret = 0; mbedtls_mpi *bn = os_zalloc(sizeof(mbedtls_mpi)); if (bn == NULL) { return NULL; } MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(bn, buf, len)); return (struct crypto_bignum *) bn; cleanup: os_free(bn); return NULL; } void crypto_bignum_deinit(struct crypto_bignum *n, int clear) { mbedtls_mpi_free((mbedtls_mpi *)n); os_free((mbedtls_mpi *)n); } int crypto_bignum_to_bin(const struct crypto_bignum *a, u8 *buf, size_t buflen, size_t padlen) { int num_bytes, offset; if (padlen > buflen) { return -1; } num_bytes = mbedtls_mpi_size((mbedtls_mpi *) a); if ((size_t) num_bytes > buflen) { return -1; } if (padlen > (size_t) num_bytes) { offset = padlen - num_bytes; } else { offset = 0; } os_memset(buf, 0, offset); mbedtls_mpi_write_binary((mbedtls_mpi *) a, buf + offset, mbedtls_mpi_size((mbedtls_mpi *)a) ); return num_bytes + offset; } int crypto_bignum_add(const struct crypto_bignum *a, const struct crypto_bignum *b, struct crypto_bignum *c) { return mbedtls_mpi_add_mpi((mbedtls_mpi *) c, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b) ? -1 : 0; } int crypto_bignum_mod(const struct crypto_bignum *a, const struct crypto_bignum *b, struct crypto_bignum *c) { return mbedtls_mpi_mod_mpi((mbedtls_mpi *) c, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b) ? -1 : 0; } int crypto_bignum_exptmod(const struct crypto_bignum *a, const struct crypto_bignum *b, const struct crypto_bignum *c, struct crypto_bignum *d) { return mbedtls_mpi_exp_mod((mbedtls_mpi *) d, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b, (const mbedtls_mpi *) c, NULL) ? -1 : 0; } int crypto_bignum_inverse(const struct crypto_bignum *a, const struct crypto_bignum *b, struct crypto_bignum *c) { return mbedtls_mpi_inv_mod((mbedtls_mpi *) c, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b) ? -1 : 0; } int crypto_bignum_sub(const struct crypto_bignum *a, const struct crypto_bignum *b, struct crypto_bignum *c) { return mbedtls_mpi_sub_mpi((mbedtls_mpi *) c, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b) ? -1 : 0; } int crypto_bignum_div(const struct crypto_bignum *a, const struct crypto_bignum *b, struct crypto_bignum *c) { return mbedtls_mpi_div_mpi((mbedtls_mpi *) c, NULL, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b) ? -1 : 0; } int crypto_bignum_mulmod(const struct crypto_bignum *a, const struct crypto_bignum *b, const struct crypto_bignum *c, struct crypto_bignum *d) { int res; #if ALLOW_EVEN_MOD || !CONFIG_MBEDTLS_HARDWARE_MPI // Must enable ALLOW_EVEN_MOD if c is even mbedtls_mpi temp; mbedtls_mpi_init(&temp); res = mbedtls_mpi_mul_mpi(&temp, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b); if (res) { return -1; } res = mbedtls_mpi_mod_mpi((mbedtls_mpi *) d, &temp, (mbedtls_mpi *) c); mbedtls_mpi_free(&temp); #else // Works with odd modulus only, but it is faster with HW acceleration res = esp_mpi_mul_mpi_mod((mbedtls_mpi *) d, (mbedtls_mpi *) a, (mbedtls_mpi *) b, (mbedtls_mpi *) c); #endif return res ? -1 : 0; } int crypto_bignum_cmp(const struct crypto_bignum *a, const struct crypto_bignum *b) { return mbedtls_mpi_cmp_mpi((const mbedtls_mpi *) a, (const mbedtls_mpi *) b); } int crypto_bignum_bits(const struct crypto_bignum *a) { return mbedtls_mpi_bitlen((const mbedtls_mpi *) a); } int crypto_bignum_is_zero(const struct crypto_bignum *a) { return (mbedtls_mpi_cmp_int((const mbedtls_mpi *) a, 0) == 0); } int crypto_bignum_is_one(const struct crypto_bignum *a) { return (mbedtls_mpi_cmp_int((const mbedtls_mpi *) a, 1) == 0); } int crypto_bignum_legendre(const struct crypto_bignum *a, const struct crypto_bignum *p) { mbedtls_mpi exp, tmp; int res = -2, ret; mbedtls_mpi_init(&exp); mbedtls_mpi_init(&tmp); /* exp = (p-1) / 2 */ MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&exp, (const mbedtls_mpi *) p, 1)); MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&exp, 1)); MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&tmp, (const mbedtls_mpi *) a, &exp, (const mbedtls_mpi *) p, NULL)); if (mbedtls_mpi_cmp_int(&tmp, 1) == 0) { res = 1; } else if (mbedtls_mpi_cmp_int(&tmp, 0) == 0 /* The below check is workaround for the case where HW * does not behave properly for X ^ A mod M when X is * power of M. Instead of returning value 0, value M is * returned.*/ || mbedtls_mpi_cmp_mpi(&tmp, (const mbedtls_mpi *)p) == 0) { res = 0; } else { res = -1; } cleanup: mbedtls_mpi_free(&tmp); mbedtls_mpi_free(&exp); return res; } int crypto_bignum_to_string(const struct crypto_bignum *a, u8 *buf, size_t buflen, size_t padlen) { int num_bytes, offset; size_t outlen; if (padlen > buflen) { return -1; } num_bytes = mbedtls_mpi_size((mbedtls_mpi *) a); if (padlen > (size_t) num_bytes) { offset = padlen - num_bytes; } else { offset = 0; } os_memset(buf, 0, offset); mbedtls_mpi_write_string((mbedtls_mpi *) a, 16, (char *)(buf + offset), mbedtls_mpi_size((mbedtls_mpi *)a), &outlen); return outlen; } int crypto_bignum_addmod(struct crypto_bignum *a, struct crypto_bignum *b, struct crypto_bignum *c, struct crypto_bignum *d) { struct crypto_bignum *tmp = crypto_bignum_init(); int ret = -1; if (mbedtls_mpi_add_mpi((mbedtls_mpi *) tmp, (const mbedtls_mpi *) b, (const mbedtls_mpi *) c) < 0) goto fail; if (mbedtls_mpi_mod_mpi( (mbedtls_mpi *) a, (const mbedtls_mpi *) tmp, (const mbedtls_mpi *) d) < 0) goto fail; ret = 0; fail: crypto_bignum_deinit(tmp, 0); return ret; } void crypto_free_buffer(unsigned char *buf) { os_free(buf); }