2020-04-13 12:25:52 -04:00
|
|
|
// 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;
|
2020-05-19 22:06:07 -04:00
|
|
|
#if ALLOW_EVEN_MOD || !CONFIG_MBEDTLS_HARDWARE_MPI // Must enable ALLOW_EVEN_MOD if c is even
|
2020-04-13 12:25:52 -04:00
|
|
|
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);
|
|
|
|
}
|