/*
* Copyright (C) 2010-2012 Free Software Foundation, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
* This file is part of GNUTLS.
*
* The GNUTLS library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see
*
*/
/* Here lie everything that has to do with large numbers, gmp.
*/
#include "gnutls_int.h"
#include "errors.h"
#include
#include
#include
#include /* includes gmp.h */
#if ENABLE_GOST
#include "gost/bignum-le.h"
#endif
#include
#include
static int
wrap_nettle_mpi_print(const bigint_t a, void *buffer, size_t * nbytes,
gnutls_bigint_format_t format)
{
unsigned int size;
mpz_t *p = (void *) a;
if (format == GNUTLS_MPI_FORMAT_USG) {
size = nettle_mpz_sizeinbase_256_u(*p);
} else if (format == GNUTLS_MPI_FORMAT_STD) {
size = nettle_mpz_sizeinbase_256_s(*p);
#if ENABLE_GOST
} else if (format == GNUTLS_MPI_FORMAT_ULE) {
size = nettle_mpz_sizeinbase_256_u_le(*p);
#endif
} else {
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
}
if (buffer == NULL || size > *nbytes) {
*nbytes = size;
gnutls_assert();
return GNUTLS_E_SHORT_MEMORY_BUFFER;
}
#if ENABLE_GOST
if (format == GNUTLS_MPI_FORMAT_ULE)
nettle_mpz_get_str_256_u_le(size, buffer, *p);
else
#endif
nettle_mpz_get_str_256(size, buffer, *p);
*nbytes = size;
return 0;
}
static int wrap_nettle_mpi_init(bigint_t *w)
{
bigint_t r;
r = gnutls_malloc(SIZEOF_MPZT);
if (r == NULL) {
gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
}
mpz_init(TOMPZ(r));
*w = r;
return 0;
}
static int wrap_nettle_mpi_init_multi(bigint_t *w, ...)
{
va_list args;
bigint_t *next;
int ret;
bigint_t* last_failed = NULL;
ret = wrap_nettle_mpi_init(w);
if (ret < 0) {
gnutls_assert();
return ret;
}
va_start(args, w);
do {
next = va_arg(args, bigint_t*);
if (next != NULL) {
ret = wrap_nettle_mpi_init(next);
if (ret < 0) {
gnutls_assert();
va_end(args);
last_failed = next;
goto fail;
}
}
} while(next != 0);
va_end(args);
return 0;
fail:
mpz_clear(TOMPZ(*w));
gnutls_free(*w);
va_start(args, w);
do {
next = va_arg(args, bigint_t*);
if (next != last_failed) {
mpz_clear(TOMPZ(*next));
gnutls_free(*next);
}
} while(next != last_failed);
va_end(args);
return GNUTLS_E_MEMORY_ERROR;
}
static int
wrap_nettle_mpi_scan(bigint_t r, const void *buffer, size_t nbytes,
gnutls_bigint_format_t format)
{
if (format == GNUTLS_MPI_FORMAT_USG) {
nettle_mpz_set_str_256_u(TOMPZ(r), nbytes, buffer);
} else if (format == GNUTLS_MPI_FORMAT_STD) {
nettle_mpz_set_str_256_s(TOMPZ(r), nbytes, buffer);
#if ENABLE_GOST
} else if (format == GNUTLS_MPI_FORMAT_ULE) {
nettle_mpz_set_str_256_u_le(TOMPZ(r), nbytes, buffer);
#endif
} else {
gnutls_assert();
goto fail;
}
return 0;
fail:
return GNUTLS_E_MPI_SCAN_FAILED;
}
static int wrap_nettle_mpi_cmp(const bigint_t u, const bigint_t v)
{
mpz_t *i1 = u, *i2 = v;
return mpz_cmp(*i1, *i2);
}
static int wrap_nettle_mpi_cmp_ui(const bigint_t u, unsigned long v)
{
mpz_t *i1 = u;
return mpz_cmp_ui(*i1, v);
}
static int wrap_nettle_mpi_set(bigint_t w, const bigint_t u)
{
mpz_set(TOMPZ(w), TOMPZ(u));
return 0;
}
static bigint_t wrap_nettle_mpi_copy(const bigint_t u)
{
int ret;
bigint_t w;
ret = wrap_nettle_mpi_init(&w);
if (ret < 0)
return NULL;
mpz_set(TOMPZ(w), u);
return w;
}
static int wrap_nettle_mpi_set_ui(bigint_t w, unsigned long u)
{
mpz_set_ui(TOMPZ(w), u);
return 0;
}
static unsigned int wrap_nettle_mpi_get_nbits(bigint_t a)
{
return mpz_sizeinbase(TOMPZ(a), 2);
}
static void wrap_nettle_mpi_release(bigint_t a)
{
mpz_clear(TOMPZ(a));
gnutls_free(a);
}
static void wrap_nettle_mpi_clear(bigint_t a)
{
zeroize_key(TOMPZ(a)[0]._mp_d,
TOMPZ(a)[0]._mp_alloc * sizeof(mp_limb_t));
}
static int wrap_nettle_mpi_modm(bigint_t r, const bigint_t a, const bigint_t b)
{
if (mpz_cmp_ui(TOMPZ(b), 0) == 0)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
mpz_mod(TOMPZ(r), TOMPZ(a), TOMPZ(b));
return 0;
}
static int
wrap_nettle_mpi_powm(bigint_t w, const bigint_t b, const bigint_t e,
const bigint_t m)
{
mpz_powm(TOMPZ(w), TOMPZ(b), TOMPZ(e), TOMPZ(m));
return 0;
}
static int
wrap_nettle_mpi_addm(bigint_t w, const bigint_t a, const bigint_t b,
const bigint_t m)
{
mpz_add(TOMPZ(w), TOMPZ(b), TOMPZ(a));
mpz_fdiv_r(TOMPZ(w), TOMPZ(w), TOMPZ(m));
return 0;
}
static int
wrap_nettle_mpi_subm(bigint_t w, const bigint_t a, const bigint_t b,
const bigint_t m)
{
mpz_sub(TOMPZ(w), TOMPZ(a), TOMPZ(b));
mpz_fdiv_r(TOMPZ(w), TOMPZ(w), TOMPZ(m));
return 0;
}
static int
wrap_nettle_mpi_mulm(bigint_t w, const bigint_t a, const bigint_t b,
const bigint_t m)
{
mpz_mul(TOMPZ(w), TOMPZ(a), TOMPZ(b));
mpz_fdiv_r(TOMPZ(w), TOMPZ(w), TOMPZ(m));
return 0;
}
static int
wrap_nettle_mpi_add(bigint_t w, const bigint_t a, const bigint_t b)
{
mpz_add(TOMPZ(w), TOMPZ(a), TOMPZ(b));
return 0;
}
static int
wrap_nettle_mpi_sub(bigint_t w, const bigint_t a, const bigint_t b)
{
mpz_sub(TOMPZ(w), TOMPZ(a), TOMPZ(b));
return 0;
}
static int
wrap_nettle_mpi_mul(bigint_t w, const bigint_t a, const bigint_t b)
{
mpz_mul(TOMPZ(w), TOMPZ(a), TOMPZ(b));
return 0;
}
/* q = a / b */
static int
wrap_nettle_mpi_div(bigint_t q, const bigint_t a, const bigint_t b)
{
mpz_cdiv_q(TOMPZ(q), TOMPZ(a), TOMPZ(b));
return 0;
}
static int
wrap_nettle_mpi_add_ui(bigint_t w, const bigint_t a, unsigned long b)
{
mpz_add_ui(TOMPZ(w), TOMPZ(a), b);
return 0;
}
static int
wrap_nettle_mpi_sub_ui(bigint_t w, const bigint_t a, unsigned long b)
{
mpz_sub_ui(TOMPZ(w), TOMPZ(a), b);
return 0;
}
static int
wrap_nettle_mpi_mul_ui(bigint_t w, const bigint_t a, unsigned long b)
{
mpz_mul_ui(TOMPZ(w), TOMPZ(a), b);
return 0;
}
static int wrap_nettle_prime_check(bigint_t pp)
{
int ret;
ret = mpz_probab_prime_p(TOMPZ(pp), PRIME_CHECK_PARAM);
if (ret > 0) {
return 0;
}
return GNUTLS_E_INTERNAL_ERROR; /* ignored */
}
int crypto_bigint_prio = INT_MAX;
gnutls_crypto_bigint_st _gnutls_mpi_ops = {
.bigint_init = wrap_nettle_mpi_init,
.bigint_init_multi = wrap_nettle_mpi_init_multi,
.bigint_cmp = wrap_nettle_mpi_cmp,
.bigint_cmp_ui = wrap_nettle_mpi_cmp_ui,
.bigint_modm = wrap_nettle_mpi_modm,
.bigint_copy = wrap_nettle_mpi_copy,
.bigint_set = wrap_nettle_mpi_set,
.bigint_set_ui = wrap_nettle_mpi_set_ui,
.bigint_get_nbits = wrap_nettle_mpi_get_nbits,
.bigint_powm = wrap_nettle_mpi_powm,
.bigint_addm = wrap_nettle_mpi_addm,
.bigint_subm = wrap_nettle_mpi_subm,
.bigint_add = wrap_nettle_mpi_add,
.bigint_sub = wrap_nettle_mpi_sub,
.bigint_add_ui = wrap_nettle_mpi_add_ui,
.bigint_sub_ui = wrap_nettle_mpi_sub_ui,
.bigint_mul = wrap_nettle_mpi_mul,
.bigint_mulm = wrap_nettle_mpi_mulm,
.bigint_mul_ui = wrap_nettle_mpi_mul_ui,
.bigint_div = wrap_nettle_mpi_div,
.bigint_prime_check = wrap_nettle_prime_check,
.bigint_release = wrap_nettle_mpi_release,
.bigint_clear = wrap_nettle_mpi_clear,
.bigint_print = wrap_nettle_mpi_print,
.bigint_scan = wrap_nettle_mpi_scan,
};