Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F20064505
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
117 KB
Subscribers
None
View Options
diff --git a/mpi/Makefile.am b/mpi/Makefile.am
index 6fe63fce..a7268e2b 100644
--- a/mpi/Makefile.am
+++ b/mpi/Makefile.am
@@ -1,183 +1,183 @@
## Process this file with automake to produce Makefile.in
# Copyright (C) 1992, 1999, 2000, 2002 Free Software Foundation, Inc.
#
# This file is part of Libgcrypt.
#
# Libgcrypt 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.
#
# Libgcrypt 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 <https://www.gnu.org/licenses/>.
# SPDX-License-Identifier: LGPL-2.1-or-later
# 1.5 leads to a combinatorial explosion due to all the conditionals
# I was not able to build it with 64Megs - 1.6 fixes this.
# not anymore required: AUTOMAKE_OPTIONS = 1.6
# Need to include ../src in addition to top_srcdir because gcrypt.h is
# a built header.
AM_CPPFLAGS = -I../src -I$(top_srcdir)/src
AM_CFLAGS = $(GPG_ERROR_CFLAGS)
AM_ASFLAGS = $(MPI_SFLAGS)
AM_CCASFLAGS = $(NOEXECSTACK_FLAGS)
EXTRA_DIST = config.links
DISTCLEANFILES = mpi-asm-defs.h \
mpih-add1-asm.S mpih-mul1-asm.S mpih-mul2-asm.S mpih-mul3-asm.S \
mpih-lshift-asm.S mpih-rshift-asm.S mpih-sub1-asm.S asm-syntax.h \
mpih-add1.c mpih-mul1.c mpih-mul2.c mpih-mul3.c \
mpih-lshift.c mpih-rshift.c mpih-sub1.c \
sysdep.h mod-source-info.h
# Beware: The following list is not a comment but grepped by
# config.links to get the list of symlinked modules
# Optional modules are marked with an O in the second column.
#BEGIN_ASM_LIST
# mpih-add1 C
# mpih-sub1 C
# mpih-mul1 C
# mpih-mul2 C
# mpih-mul3 C
# mpih-lshift C
# mpih-rshift C
# udiv O
# udiv-qrnnd O
#END_ASM_LIST
# Note: This function has not yet been implemented. There is only a dummy in
# generic/
# udiv-w-sdiv O
# And we need to have conditionals for all modules because
# we don't know whether they are .c or .S. Very ugly; I know.
# Remember to define them all in configure.ac
if MPI_MOD_ASM_MPIH_ADD1
mpih_add1 = mpih-add1-asm.S
else
if MPI_MOD_C_MPIH_ADD1
mpih_add1 = mpih-add1.c
else
mpih_add1 =
endif
endif
if MPI_MOD_ASM_MPIH_SUB1
mpih_sub1 = mpih-sub1-asm.S
else
if MPI_MOD_C_MPIH_SUB1
mpih_sub1 = mpih-sub1.c
else
mpih_sub1 =
endif
endif
if MPI_MOD_ASM_MPIH_MUL1
mpih_mul1 = mpih-mul1-asm.S
else
if MPI_MOD_C_MPIH_MUL1
mpih_mul1 = mpih-mul1.c
else
mpih_mul1 =
endif
endif
if MPI_MOD_ASM_MPIH_MUL2
mpih_mul2 = mpih-mul2-asm.S
else
if MPI_MOD_C_MPIH_MUL2
mpih_mul2 = mpih-mul2.c
else
mpih_mul2 =
endif
endif
if MPI_MOD_ASM_MPIH_MUL3
mpih_mul3 = mpih-mul3-asm.S
else
if MPI_MOD_C_MPIH_MUL3
mpih_mul3 = mpih-mul3.c
else
mpih_mul3 =
endif
endif
if MPI_MOD_ASM_MPIH_LSHIFT
mpih_lshift = mpih-lshift-asm.S
else
if MPI_MOD_C_MPIH_LSHIFT
mpih_lshift = mpih-lshift.c
else
mpih_lshift =
endif
endif
if MPI_MOD_ASM_MPIH_RSHIFT
mpih_rshift = mpih-rshift-asm.S
else
if MPI_MOD_C_MPIH_RSHIFT
mpih_rshift = mpih-rshift.c
else
mpih_rshift =
endif
endif
if MPI_MOD_ASM_UDIV
udiv = udiv-asm.S
else
if MPI_MOD_C_UDIV
udiv = udiv.c
else
udiv =
endif
endif
if MPI_MOD_ASM_UDIV_QRNND
udiv_qrnnd = udiv-qrnnd-asm.S
else
if MPI_MOD_C_UDIV_QRNND
udiv_qrnnd = udiv-qrnnd.c
else
udiv_qrnnd =
endif
endif
noinst_LTLIBRARIES = libmpi.la
libmpi_la_LDFLAGS =
nodist_libmpi_la_SOURCES = $(mpih_add1) $(mpih_sub1) $(mpih_mul1) \
$(mpih_mul2) $(mpih_mul3) $(mpih_lshift) $(mpih_rshift) \
$(udiv) $(udiv_qrnnd)
libmpi_la_SOURCES = longlong.h \
mpi-add.c \
mpi-bit.c \
mpi-cmp.c \
mpi-div.c \
mpi-gcd.c \
mpi-internal.h \
mpi-inline.h \
mpi-inline.c \
mpi-inv.c \
mpi-mul.c \
mpi-mod.c \
mpi-pow.c \
mpi-mpow.c \
mpi-scan.c \
mpicoder.c \
mpih-div.c \
- mpih-mul.c \
+ mpih-mul.c mpih-pow.c \
mpih-const-time.c \
mpiutil.c \
ec.c ec-internal.h ec-ed25519.c ec-nist.c ec-inline.h \
ec-hw-s390x.c
EXTRA_libmpi_la_SOURCES = \
asm-common-aarch64.h \
asm-common-amd64.h \
asm-common-i386.h
diff --git a/mpi/mpi-internal.h b/mpi/mpi-internal.h
index 84392dc1..a6dc0651 100644
--- a/mpi/mpi-internal.h
+++ b/mpi/mpi-internal.h
@@ -1,335 +1,338 @@
/* mpi-internal.h - Internal to the Multi Precision Integers
* Copyright (C) 1994, 1996, 1998, 2000, 2002,
* 2003 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt 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.
*
* Libgcrypt 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 <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* Note: This code is heavily based on the GNU MP Library.
* Actually it's the same code with only minor changes in the
* way the data is stored; this is to support the abstraction
* of an optional secure memory allocation which may be used
* to avoid revealing of sensitive data due to paging etc.
*/
#ifndef G10_MPI_INTERNAL_H
#define G10_MPI_INTERNAL_H
#include "mpi-asm-defs.h"
#ifndef BITS_PER_MPI_LIMB
#if BYTES_PER_MPI_LIMB == SIZEOF_UNSIGNED_INT
typedef unsigned int mpi_limb_t;
typedef signed int mpi_limb_signed_t;
#elif BYTES_PER_MPI_LIMB == SIZEOF_UNSIGNED_LONG
typedef unsigned long int mpi_limb_t;
typedef signed long int mpi_limb_signed_t;
#elif BYTES_PER_MPI_LIMB == SIZEOF_UNSIGNED_LONG_LONG
typedef unsigned long long int mpi_limb_t;
typedef signed long long int mpi_limb_signed_t;
#elif BYTES_PER_MPI_LIMB == SIZEOF_UNSIGNED_SHORT
typedef unsigned short int mpi_limb_t;
typedef signed short int mpi_limb_signed_t;
#else
#error BYTES_PER_MPI_LIMB does not match any C type
#endif
#define BITS_PER_MPI_LIMB (8*BYTES_PER_MPI_LIMB)
#endif /*BITS_PER_MPI_LIMB*/
#include "mpi.h"
#include "const-time.h"
/* If KARATSUBA_THRESHOLD is not already defined, define it to a
* value which is good on most machines. */
/* tested 4, 16, 32 and 64, where 16 gave the best performance when
* checking a 768 and a 1024 bit ElGamal signature.
* (wk 22.12.97) */
#ifndef KARATSUBA_THRESHOLD
#define KARATSUBA_THRESHOLD 16
#endif
/* The code can't handle KARATSUBA_THRESHOLD smaller than 2. */
#if KARATSUBA_THRESHOLD < 2
#undef KARATSUBA_THRESHOLD
#define KARATSUBA_THRESHOLD 2
#endif
typedef mpi_limb_t *mpi_ptr_t; /* pointer to a limb */
typedef int mpi_size_t; /* (must be a signed type) */
#define ABS(x) (x >= 0 ? x : -x)
#define MIN(l,o) ((l) < (o) ? (l) : (o))
#define MAX(h,i) ((h) > (i) ? (h) : (i))
#define RESIZE_IF_NEEDED(a,b) \
do { \
if( (a)->alloced < (b) ) \
mpi_resize((a), (b)); \
} while(0)
#define RESIZE_AND_CLEAR_IF_NEEDED(a,b) \
do { \
if( (a)->nlimbs < (b) ) \
mpi_resize((a), (b)); \
} while(0)
/* Copy N limbs from S to D. */
#define MPN_COPY( d, s, n) \
do { \
mpi_size_t _i; \
for( _i = 0; _i < (n); _i++ ) \
(d)[_i] = (s)[_i]; \
} while(0)
#define MPN_COPY_INCR( d, s, n) \
do { \
mpi_size_t _i; \
for( _i = 0; _i < (n); _i++ ) \
(d)[_i] = (s)[_i]; \
} while (0)
#define MPN_COPY_DECR( d, s, n ) \
do { \
mpi_size_t _i; \
for( _i = (n)-1; _i >= 0; _i--) \
(d)[_i] = (s)[_i]; \
} while(0)
/* Zero N limbs at D */
#define MPN_ZERO(d, n) \
do { \
int _i; \
for( _i = 0; _i < (n); _i++ ) \
(d)[_i] = 0; \
} while (0)
#define MPN_NORMALIZE(d, n) \
do { \
while( (n) > 0 ) { \
if( (d)[(n)-1] ) \
break; \
(n)--; \
} \
} while(0)
#define MPN_NORMALIZE_NOT_ZERO(d, n) \
do { \
for(;;) { \
if( (d)[(n)-1] ) \
break; \
(n)--; \
} \
} while(0)
#define MPN_MUL_N_RECURSE(prodp, up, vp, size, tspace) \
do { \
if( (size) < KARATSUBA_THRESHOLD ) \
mul_n_basecase (prodp, up, vp, size); \
else \
mul_n (prodp, up, vp, size, tspace); \
} while (0)
/* Divide the two-limb number in (NH,,NL) by D, with DI being the largest
* limb not larger than (2**(2*BITS_PER_MP_LIMB))/D - (2**BITS_PER_MP_LIMB).
* If this would yield overflow, DI should be the largest possible number
* (i.e., only ones). For correct operation, the most significant bit of D
* has to be set. Put the quotient in Q and the remainder in R.
*/
#define UDIV_QRNND_PREINV(q, r, nh, nl, d, di) \
do { \
mpi_limb_t _ql GCC_ATTR_UNUSED; \
mpi_limb_t _q, _r; \
mpi_limb_t _xh, _xl; \
umul_ppmm (_q, _ql, (nh), (di)); \
_q += (nh); /* DI is 2**BITS_PER_MPI_LIMB too small */ \
umul_ppmm (_xh, _xl, _q, (d)); \
sub_ddmmss (_xh, _r, (nh), (nl), _xh, _xl); \
if( _xh ) { \
sub_ddmmss (_xh, _r, _xh, _r, 0, (d)); \
_q++; \
if( _xh) { \
sub_ddmmss (_xh, _r, _xh, _r, 0, (d)); \
_q++; \
} \
} \
if( _r >= (d) ) { \
_r -= (d); \
_q++; \
} \
(r) = _r; \
(q) = _q; \
} while (0)
/*-- mpiutil.c --*/
#define mpi_alloc_limb_space(n,f) _gcry_mpi_alloc_limb_space((n),(f))
mpi_ptr_t _gcry_mpi_alloc_limb_space( unsigned nlimbs, int sec );
void _gcry_mpi_free_limb_space( mpi_ptr_t a, unsigned int nlimbs );
void _gcry_mpi_assign_limb_space( gcry_mpi_t a, mpi_ptr_t ap, unsigned nlimbs );
/*-- mpi-bit.c --*/
#define mpi_rshift_limbs(a,n) _gcry_mpi_rshift_limbs ((a), (n))
#define mpi_lshift_limbs(a,n) _gcry_mpi_lshift_limbs ((a), (n))
void _gcry_mpi_rshift_limbs( gcry_mpi_t a, unsigned int count );
void _gcry_mpi_lshift_limbs( gcry_mpi_t a, unsigned int count );
/*-- mpih-add.c --*/
mpi_limb_t _gcry_mpih_add_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
mpi_size_t s1_size, mpi_limb_t s2_limb );
mpi_limb_t _gcry_mpih_add_n( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
mpi_ptr_t s2_ptr, mpi_size_t size);
mpi_limb_t _gcry_mpih_add(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size,
mpi_ptr_t s2_ptr, mpi_size_t s2_size);
/*-- mpih-sub.c --*/
mpi_limb_t _gcry_mpih_sub_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
mpi_size_t s1_size, mpi_limb_t s2_limb );
mpi_limb_t _gcry_mpih_sub_n( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
mpi_ptr_t s2_ptr, mpi_size_t size);
mpi_limb_t _gcry_mpih_sub(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size,
mpi_ptr_t s2_ptr, mpi_size_t s2_size);
/*-- mpih-cmp.c --*/
int _gcry_mpih_cmp( mpi_ptr_t op1_ptr, mpi_ptr_t op2_ptr, mpi_size_t size );
/*-- mpih-mul.c --*/
struct karatsuba_ctx {
struct karatsuba_ctx *next;
mpi_ptr_t tspace;
unsigned int tspace_nlimbs;
mpi_size_t tspace_size;
mpi_ptr_t tp;
unsigned int tp_nlimbs;
mpi_size_t tp_size;
};
void _gcry_mpih_release_karatsuba_ctx( struct karatsuba_ctx *ctx );
mpi_limb_t _gcry_mpih_addmul_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
mpi_size_t s1_size, mpi_limb_t s2_limb);
mpi_limb_t _gcry_mpih_submul_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
mpi_size_t s1_size, mpi_limb_t s2_limb);
void _gcry_mpih_mul_n( mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp,
mpi_size_t size);
mpi_limb_t _gcry_mpih_mul( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t usize,
mpi_ptr_t vp, mpi_size_t vsize);
mpi_limb_t _gcry_mpih_mul_lli(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t usize,
mpi_ptr_t vp, mpi_size_t vsize);
void _gcry_mpih_sqr_n_basecase( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size );
void _gcry_mpih_sqr_n( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size,
mpi_ptr_t tspace);
void _gcry_mpih_mul_karatsuba_case( mpi_ptr_t prodp,
mpi_ptr_t up, mpi_size_t usize,
mpi_ptr_t vp, mpi_size_t vsize,
struct karatsuba_ctx *ctx );
/*-- mpih-mul_1.c (or xxx/cpu/ *.S) --*/
mpi_limb_t _gcry_mpih_mul_1( mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
mpi_size_t s1_size, mpi_limb_t s2_limb);
/*-- mpih-div.c --*/
mpi_limb_t _gcry_mpih_mod_1(mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
mpi_limb_t divisor_limb);
mpi_limb_t _gcry_mpih_divrem( mpi_ptr_t qp, mpi_size_t qextra_limbs,
mpi_ptr_t np, mpi_size_t nsize,
mpi_ptr_t dp, mpi_size_t dsize);
mpi_limb_t _gcry_mpih_divmod_1( mpi_ptr_t quot_ptr,
mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
mpi_limb_t divisor_limb);
/*-- mpih-shift.c --*/
mpi_limb_t _gcry_mpih_lshift( mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize,
unsigned cnt);
mpi_limb_t _gcry_mpih_rshift( mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize,
unsigned cnt);
+/*-- mpih-pow.c --*/
+void _gcry_mpih_powm_lli (mpi_ptr_t rp, mpi_ptr_t bp, mpi_ptr_t mp,
+ mpi_size_t n, mpi_ptr_t ep, mpi_size_t en);
/*-- mpih-const-time.c --*/
#define mpih_set_cond(w,u,s,o) _gcry_mpih_set_cond ((w),(u),(s),(o))
#define mpih_add_n_cond(w,u,v,s,o) _gcry_mpih_add_n_cond ((w),(u),(v),(s),(o))
#define mpih_sub_n_cond(w,u,v,s,o) _gcry_mpih_sub_n_cond ((w),(u),(v),(s),(o))
#define mpih_swap_cond(u,v,s,o) _gcry_mpih_swap_cond ((u),(v),(s),(o))
#define mpih_abs_cond(w,u,s,o) _gcry_mpih_abs_cond ((w),(u),(s),(o))
#define mpih_mod_lli(v,vs,u,us) _gcry_mpih_mod_lli ((v),(vs),(u),(us))
DEFINE_CT_TYPE_GEN_MASK(limb, mpi_limb_t)
DEFINE_CT_TYPE_GEN_INV_MASK(limb, mpi_limb_t)
DEFINE_CT_TYPE_SELECT_FUNC(limb, mpi_limb_t)
static inline int
mpih_limb_is_zero (mpi_limb_t a)
{
/* Sign bit set if A == 0. */
a = ~a & ~(-a);
return a >> (BITS_PER_MPI_LIMB - 1);
}
static inline int
mpih_limb_is_not_zero (mpi_limb_t a)
{
/* Sign bit set if A != 0. */
a = a | (-a);
return a >> (BITS_PER_MPI_LIMB - 1);
}
void _gcry_mpih_set_cond (mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize,
unsigned long op_enable);
mpi_limb_t _gcry_mpih_add_n_cond (mpi_ptr_t wp, mpi_ptr_t up, mpi_ptr_t vp,
mpi_size_t usize, unsigned long op_enable);
mpi_limb_t _gcry_mpih_sub_n_cond (mpi_ptr_t wp, mpi_ptr_t up, mpi_ptr_t vp,
mpi_size_t usize, unsigned long op_enable);
void _gcry_mpih_swap_cond (mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t usize,
unsigned long op_enable);
void _gcry_mpih_abs_cond (mpi_ptr_t wp, mpi_ptr_t up,
mpi_size_t usize, unsigned long op_enable);
void _gcry_mpih_lookup_lli (mpi_ptr_t rp, const mpi_limb_t *table,
mpi_size_t n, mpi_size_t nents, mpi_size_t idx);
mpi_ptr_t _gcry_mpih_mod_lli (mpi_ptr_t vp, mpi_size_t vsize,
mpi_ptr_t up, mpi_size_t usize);
int _gcry_mpih_cmp_ui (mpi_ptr_t up, mpi_size_t usize, unsigned long v);
int _gcry_mpih_cmp_lli ( mpi_ptr_t op1_ptr, mpi_ptr_t op2_ptr, mpi_size_t size );
mpi_limb_t _gcry_mpih_add_lli (mpi_ptr_t wp, mpi_ptr_t up, mpi_ptr_t vp,
mpi_size_t usize);
/* Define stuff for longlong.h. */
#define W_TYPE_SIZE BITS_PER_MPI_LIMB
typedef mpi_limb_t UWtype;
typedef unsigned int UHWtype;
#if defined (__GNUC__)
typedef unsigned int UQItype __attribute__ ((mode (QI)));
typedef int SItype __attribute__ ((mode (SI)));
typedef unsigned int USItype __attribute__ ((mode (SI)));
typedef int DItype __attribute__ ((mode (DI)));
typedef unsigned int UDItype __attribute__ ((mode (DI)));
#else
typedef unsigned char UQItype;
typedef long SItype;
typedef unsigned long USItype;
#endif
#ifdef __GNUC__
#include "mpi-inline.h"
#endif
#endif /*G10_MPI_INTERNAL_H*/
diff --git a/mpi/mpi-pow.c b/mpi/mpi-pow.c
index defd675e..ef410a60 100644
--- a/mpi/mpi-pow.c
+++ b/mpi/mpi-pow.c
@@ -1,772 +1,824 @@
/* mpi-pow.c - MPI functions for exponentiation
* Copyright (C) 1994, 1996, 1998, 2000, 2002
* 2003 Free Software Foundation, Inc.
* 2013 g10 Code GmbH
*
* This file is part of Libgcrypt.
*
* Libgcrypt 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.
*
* Libgcrypt 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 <http://www.gnu.org/licenses/>.
*
* Note: This code is heavily based on the GNU MP Library.
* Actually it's the same code with only minor changes in the
* way the data is stored; this is to support the abstraction
* of an optional secure memory allocation which may be used
* to avoid revealing of sensitive data due to paging etc.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mpi-internal.h"
#include "longlong.h"
+#ifndef USE_ALGORITHM_LLI_EXPONENTIATION
+/*
+ * When you don't need least-leak implementation, please add compilation option
+ * -DUSE_ALGORITHM_LLI_EXPONENTIATION=0
+ *
+ * For performance (by tests/benchmark rsa), it's comparable to leaky
+ * sliding window implementation on 64-bit architecture. On 32-bit
+ * architecture, it's slower with 3072-bit and 4096-bit. In future,
+ * it's good to have non-leaky Karatsuba multiplication, then, it's an
+ * option to use it.
+ *
+ */
+#define USE_ALGORITHM_LLI_EXPONENTIATION 1
+#endif
+
/*
* When you need old implementation, please add compilation option
* -DUSE_ALGORITHM_SIMPLE_EXPONENTIATION
* or expose this line:
#define USE_ALGORITHM_SIMPLE_EXPONENTIATION 1
*/
+const char *
+_gcry_mpi_get_powm_config (void)
+{
+#if USE_ALGORITHM_LLI_EXPONENTIATION
+ return "fixed-window";
+#else
+ return "sliding-window";
+#endif
+}
+
#if defined(USE_ALGORITHM_SIMPLE_EXPONENTIATION)
/****************
* RES = BASE ^ EXPO mod MOD
*/
void
_gcry_mpi_powm (gcry_mpi_t res,
gcry_mpi_t base, gcry_mpi_t expo, gcry_mpi_t mod)
{
/* Pointer to the limbs of the arguments, their size and signs. */
mpi_ptr_t rp, ep, mp, bp;
mpi_size_t esize, msize, bsize, rsize;
int msign, bsign, rsign;
/* Flags telling the secure allocation status of the arguments. */
int esec, msec, bsec;
/* Size of the result including space for temporary values. */
mpi_size_t size;
/* Helper. */
int mod_shift_cnt;
int negative_result;
mpi_ptr_t mp_marker = NULL;
mpi_ptr_t bp_marker = NULL;
mpi_ptr_t ep_marker = NULL;
mpi_ptr_t xp_marker = NULL;
unsigned int mp_nlimbs = 0;
unsigned int bp_nlimbs = 0;
unsigned int ep_nlimbs = 0;
unsigned int xp_nlimbs = 0;
mpi_ptr_t tspace = NULL;
mpi_size_t tsize = 0;
esize = expo->nlimbs;
msize = mod->nlimbs;
size = 2 * msize;
msign = mod->sign;
esec = mpi_is_secure(expo);
msec = mpi_is_secure(mod);
bsec = mpi_is_secure(base);
rp = res->d;
ep = expo->d;
MPN_NORMALIZE(ep, esize);
if (!msize)
_gcry_divide_by_zero();
if (!esize)
{
/* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0 depending
on if MOD equals 1. */
res->nlimbs = (msize == 1 && mod->d[0] == 1) ? 0 : 1;
if (res->nlimbs)
{
RESIZE_IF_NEEDED (res, 1);
rp = res->d;
rp[0] = 1;
}
res->sign = 0;
goto leave;
}
/* Normalize MOD (i.e. make its most significant bit set) as
required by mpn_divrem. This will make the intermediate values
in the calculation slightly larger, but the correct result is
obtained after a final reduction using the original MOD value. */
mp_nlimbs = msec? msize:0;
mp = mp_marker = mpi_alloc_limb_space(msize, msec);
count_leading_zeros (mod_shift_cnt, mod->d[msize-1]);
if (mod_shift_cnt)
_gcry_mpih_lshift (mp, mod->d, msize, mod_shift_cnt);
else
MPN_COPY( mp, mod->d, msize );
bsize = base->nlimbs;
bsign = base->sign;
if (bsize > msize)
{
/* The base is larger than the module. Reduce it.
Allocate (BSIZE + 1) with space for remainder and quotient.
(The quotient is (bsize - msize + 1) limbs.) */
bp_nlimbs = bsec ? (bsize + 1):0;
bp = bp_marker = mpi_alloc_limb_space( bsize + 1, bsec );
MPN_COPY ( bp, base->d, bsize );
/* We don't care about the quotient, store it above the
* remainder, at BP + MSIZE. */
_gcry_mpih_divrem( bp + msize, 0, bp, bsize, mp, msize );
bsize = msize;
/* Canonicalize the base, since we are going to multiply with it
quite a few times. */
MPN_NORMALIZE( bp, bsize );
}
else
bp = base->d;
if (!bsize)
{
res->nlimbs = 0;
res->sign = 0;
goto leave;
}
/* Make BASE, EXPO and MOD not overlap with RES. */
if ( rp == bp )
{
/* RES and BASE are identical. Allocate temp. space for BASE. */
gcry_assert (!bp_marker);
bp_nlimbs = bsec? bsize:0;
bp = bp_marker = mpi_alloc_limb_space( bsize, bsec );
MPN_COPY(bp, rp, bsize);
}
if ( rp == ep )
{
/* RES and EXPO are identical. Allocate temp. space for EXPO. */
ep_nlimbs = esec? esize:0;
ep = ep_marker = mpi_alloc_limb_space( esize, esec );
MPN_COPY(ep, rp, esize);
}
if ( rp == mp )
{
/* RES and MOD are identical. Allocate temporary space for MOD.*/
gcry_assert (!mp_marker);
mp_nlimbs = msec?msize:0;
mp = mp_marker = mpi_alloc_limb_space( msize, msec );
MPN_COPY(mp, rp, msize);
}
/* Copy base to the result. */
if (res->alloced < size)
{
mpi_resize (res, size);
rp = res->d;
}
MPN_COPY ( rp, bp, bsize );
rsize = bsize;
rsign = 0;
/* Main processing. */
{
mpi_size_t i;
mpi_ptr_t xp;
int c;
mpi_limb_t e;
mpi_limb_t carry_limb;
struct karatsuba_ctx karactx;
struct gcry_mpi w, u;
xp_nlimbs = msec? size:0;
xp = xp_marker = mpi_alloc_limb_space( size, msec );
w.sign = u.sign = 0;
w.flags = u.flags = 0;
w.alloced = w.nlimbs = size; /* RES->alloc may be longer. */
u.alloced = u.nlimbs = size;
memset( &karactx, 0, sizeof karactx );
negative_result = (ep[0] & 1) && bsign;
i = esize - 1;
e = ep[i];
count_leading_zeros (c, e);
e = (e << c) << 1; /* Shift the expo bits to the left, lose msb. */
c = BITS_PER_MPI_LIMB - 1 - c;
/* Main loop.
Make the result be pointed to alternately by XP and RP. This
helps us avoid block copying, which would otherwise be
necessary with the overlap restrictions of
_gcry_mpih_divmod. With 50% probability the result after this
loop will be in the area originally pointed by RP (==RES->d),
and with 50% probability in the area originally pointed to by XP. */
for (;;)
{
while (c)
{
mpi_ptr_t tp;
mpi_size_t xsize;
/*mpih_mul_n(xp, rp, rp, rsize);*/
if ( rsize < KARATSUBA_THRESHOLD )
_gcry_mpih_sqr_n_basecase( xp, rp, rsize );
else
{
if ( !tspace )
{
tsize = 2 * rsize;
tspace = mpi_alloc_limb_space( tsize, 0 );
}
else if ( tsize < (2*rsize) )
{
_gcry_mpi_free_limb_space (tspace, 0);
tsize = 2 * rsize;
tspace = mpi_alloc_limb_space (tsize, 0 );
}
_gcry_mpih_sqr_n (xp, rp, rsize, tspace);
}
xsize = 2 * rsize;
if ( xsize > msize )
{
_gcry_mpih_divrem(xp + msize, 0, xp, xsize, mp, msize);
xsize = msize;
}
tp = rp; rp = xp; xp = tp;
rsize = xsize;
/* To mitigate the Yarom/Falkner flush+reload cache
* side-channel attack on the RSA secret exponent, we do
* the multiplication regardless of the value of the
* high-bit of E. But to avoid this performance penalty
* we do it only if the exponent has been stored in secure
* memory and we can thus assume it is a secret exponent. */
if (esec || (mpi_limb_signed_t)e < 0)
{
/*mpih_mul( xp, rp, rsize, bp, bsize );*/
if( bsize < KARATSUBA_THRESHOLD )
_gcry_mpih_mul ( xp, rp, rsize, bp, bsize );
else
_gcry_mpih_mul_karatsuba_case (xp, rp, rsize, bp, bsize,
&karactx);
xsize = rsize + bsize;
if ( xsize > msize )
{
_gcry_mpih_divrem(xp + msize, 0, xp, xsize, mp, msize);
xsize = msize;
}
}
w.d = rp;
u.d = xp;
mpi_set_cond (&w, &u, ((mpi_limb_signed_t)e < 0));
e <<= 1;
c--;
}
i--;
if ( i < 0 )
break;
e = ep[i];
c = BITS_PER_MPI_LIMB;
}
/* We shifted MOD, the modulo reduction argument, left
MOD_SHIFT_CNT steps. Adjust the result by reducing it with the
original MOD.
Also make sure the result is put in RES->d (where it already
might be, see above). */
if ( mod_shift_cnt )
{
carry_limb = _gcry_mpih_lshift( res->d, rp, rsize, mod_shift_cnt);
rp = res->d;
if ( carry_limb )
{
rp[rsize] = carry_limb;
rsize++;
}
}
else if (res->d != rp)
{
MPN_COPY (res->d, rp, rsize);
rp = res->d;
}
if ( rsize >= msize )
{
_gcry_mpih_divrem(rp + msize, 0, rp, rsize, mp, msize);
rsize = msize;
}
/* Remove any leading zero words from the result. */
if ( mod_shift_cnt )
_gcry_mpih_rshift( rp, rp, rsize, mod_shift_cnt);
MPN_NORMALIZE (rp, rsize);
_gcry_mpih_release_karatsuba_ctx (&karactx );
}
/* Fixup for negative results. */
if ( negative_result && rsize )
{
if ( mod_shift_cnt )
_gcry_mpih_rshift( mp, mp, msize, mod_shift_cnt);
_gcry_mpih_sub( rp, mp, msize, rp, rsize);
rsize = msize;
rsign = msign;
MPN_NORMALIZE(rp, rsize);
}
gcry_assert (res->d == rp);
res->nlimbs = rsize;
res->sign = rsign;
leave:
if (mp_marker)
_gcry_mpi_free_limb_space( mp_marker, mp_nlimbs );
if (bp_marker)
_gcry_mpi_free_limb_space( bp_marker, bp_nlimbs );
if (ep_marker)
_gcry_mpi_free_limb_space( ep_marker, ep_nlimbs );
if (xp_marker)
_gcry_mpi_free_limb_space( xp_marker, xp_nlimbs );
if (tspace)
_gcry_mpi_free_limb_space( tspace, 0 );
}
#else
/**
* Internal function to compute
*
* X = R * S mod M
*
* and set the size of X at the pointer XSIZE_P.
* Use karatsuba structure at KARACTX_P.
*
* Condition:
* RSIZE >= SSIZE
* Enough space for X is allocated beforehand.
*
* For generic cases, we can/should use gcry_mpi_mulm.
* This function is use for specific internal case.
*/
static void
mul_mod (mpi_ptr_t xp, mpi_size_t *xsize_p,
mpi_ptr_t rp, mpi_size_t rsize,
mpi_ptr_t sp, mpi_size_t ssize,
mpi_ptr_t mp, mpi_size_t msize,
struct karatsuba_ctx *karactx_p)
{
if( ssize < KARATSUBA_THRESHOLD )
_gcry_mpih_mul ( xp, rp, rsize, sp, ssize );
else
_gcry_mpih_mul_karatsuba_case (xp, rp, rsize, sp, ssize, karactx_p);
if (rsize + ssize > msize)
{
_gcry_mpih_divrem (xp + msize, 0, xp, rsize + ssize, mp, msize);
*xsize_p = msize;
}
else
*xsize_p = rsize + ssize;
}
#define SIZE_PRECOMP ((1 << (5 - 1)))
/****************
* RES = BASE ^ EXPO mod MOD
*
* To mitigate the Yarom/Falkner flush+reload cache side-channel
* attack on the RSA secret exponent, we don't use the square
* routine but multiplication.
*
* Reference:
* Handbook of Applied Cryptography
* Algorithm 14.83: Modified left-to-right k-ary exponentiation
*/
void
_gcry_mpi_powm (gcry_mpi_t res,
gcry_mpi_t base, gcry_mpi_t expo, gcry_mpi_t mod)
{
/* Pointer to the limbs of the arguments, their size and signs. */
mpi_ptr_t rp, ep, mp, bp;
mpi_size_t esize, msize, bsize, rsize;
int msign, bsign, rsign;
/* Flags telling the secure allocation status of the arguments. */
int esec, msec, bsec;
/* Size of the result including space for temporary values. */
mpi_size_t size;
/* Helper. */
int mod_shift_cnt;
int negative_result;
mpi_ptr_t mp_marker = NULL;
mpi_ptr_t bp_marker = NULL;
mpi_ptr_t ep_marker = NULL;
mpi_ptr_t xp_marker = NULL;
unsigned int mp_nlimbs = 0;
unsigned int bp_nlimbs = 0;
unsigned int ep_nlimbs = 0;
unsigned int xp_nlimbs = 0;
mpi_ptr_t precomp[SIZE_PRECOMP]; /* Pre-computed array: BASE^1, ^3, ^5, ... */
mpi_size_t precomp_size[SIZE_PRECOMP];
mpi_size_t W;
mpi_ptr_t base_u;
mpi_size_t base_u_size;
mpi_size_t max_u_size;
esize = expo->nlimbs;
msize = mod->nlimbs;
size = 2 * msize;
msign = mod->sign;
ep = expo->d;
MPN_NORMALIZE(ep, esize);
if (esize * BITS_PER_MPI_LIMB > 512)
W = 5;
else if (esize * BITS_PER_MPI_LIMB > 256)
W = 4;
else if (esize * BITS_PER_MPI_LIMB > 128)
W = 3;
else if (esize * BITS_PER_MPI_LIMB > 64)
W = 2;
else
W = 1;
esec = mpi_is_secure(expo);
msec = mpi_is_secure(mod);
bsec = mpi_is_secure(base);
rp = res->d;
if (!msize)
_gcry_divide_by_zero();
if (!esize)
{
/* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0 depending
on if MOD equals 1. */
res->nlimbs = (msize == 1 && mod->d[0] == 1) ? 0 : 1;
if (res->nlimbs)
{
RESIZE_IF_NEEDED (res, 1);
rp = res->d;
rp[0] = 1;
}
res->sign = 0;
goto leave;
}
/* Normalize MOD (i.e. make its most significant bit set) as
required by mpn_divrem. This will make the intermediate values
in the calculation slightly larger, but the correct result is
obtained after a final reduction using the original MOD value. */
mp_nlimbs = msec? msize:0;
mp = mp_marker = mpi_alloc_limb_space(msize, msec);
count_leading_zeros (mod_shift_cnt, mod->d[msize-1]);
if (mod_shift_cnt)
_gcry_mpih_lshift (mp, mod->d, msize, mod_shift_cnt);
else
MPN_COPY( mp, mod->d, msize );
bsize = base->nlimbs;
bsign = base->sign;
if (bsize > msize)
{
/* The base is larger than the module. Reduce it.
Allocate (BSIZE + 1) with space for remainder and quotient.
(The quotient is (bsize - msize + 1) limbs.) */
bp_nlimbs = bsec ? (bsize + 1):0;
bp = bp_marker = mpi_alloc_limb_space( bsize + 1, bsec );
MPN_COPY ( bp, base->d, bsize );
/* We don't care about the quotient, store it above the
* remainder, at BP + MSIZE. */
_gcry_mpih_divrem( bp + msize, 0, bp, bsize, mp, msize );
bsize = msize;
/* Canonicalize the base, since we are going to multiply with it
quite a few times. */
MPN_NORMALIZE( bp, bsize );
}
else
bp = base->d;
if (!bsize)
{
res->nlimbs = 0;
res->sign = 0;
goto leave;
}
/* Make BASE, EXPO not overlap with RES. We don't need to check MOD
because that has already been copied to the MP var. */
if ( rp == bp )
{
/* RES and BASE are identical. Allocate temp. space for BASE. */
gcry_assert (!bp_marker);
bp_nlimbs = bsec? bsize:0;
bp = bp_marker = mpi_alloc_limb_space( bsize, bsec );
MPN_COPY(bp, rp, bsize);
}
if ( rp == ep )
{
/* RES and EXPO are identical. Allocate temp. space for EXPO. */
ep_nlimbs = esec? esize:0;
ep = ep_marker = mpi_alloc_limb_space( esize, esec );
MPN_COPY(ep, rp, esize);
}
/* Copy base to the result. */
if (res->alloced < size)
{
mpi_resize (res, size);
rp = res->d;
}
+#if USE_ALGORITHM_LLI_EXPONENTIATION
+ if ((esec || bsec || msec) && (mod->d[0] & 1))
+ {
+ mpi_ptr_t bp1 = NULL;
+
+ if (bsize < msize)
+ {
+ bp1 = mpi_alloc_limb_space (msize, 1);
+ MPN_ZERO (bp1, msize);
+ MPN_COPY (bp1, bp, bsize);
+ }
+
+ _gcry_mpih_powm_lli (rp, bp1?bp1:bp, mod->d, msize, ep, esize);
+ if (bp1)
+ _gcry_mpi_free_limb_space (bp1, msize);
+
+ rsign = 0;
+ negative_result = (ep[0] & 1) && bsign;
+ if (negative_result)
+ rsign = msign;
+
+ res->nlimbs = msize;
+ res->sign = rsign;
+ goto leave;
+ }
+#endif
+
/* Main processing. */
{
mpi_size_t i, j, k;
mpi_ptr_t xp;
mpi_size_t xsize = 0;
int c;
mpi_limb_t e;
mpi_limb_t carry_limb;
struct karatsuba_ctx karactx;
mpi_ptr_t tp;
xp_nlimbs = msec? size:0;
xp = xp_marker = mpi_alloc_limb_space( size, msec );
memset( &karactx, 0, sizeof karactx );
negative_result = (ep[0] & 1) && bsign;
/* Precompute PRECOMP[], BASE^(2 * i + 1), BASE^1, ^3, ^5, ... */
if (W > 1) /* X := BASE^2 */
mul_mod (xp, &xsize, bp, bsize, bp, bsize, mp, msize, &karactx);
base_u = precomp[0] = mpi_alloc_limb_space (bsize, esec);
base_u_size = max_u_size = precomp_size[0] = bsize;
MPN_COPY (precomp[0], bp, bsize);
for (i = 1; i < (1 << (W - 1)); i++)
{ /* PRECOMP[i] = BASE^(2 * i + 1) */
if (xsize >= base_u_size)
mul_mod (rp, &rsize, xp, xsize, base_u, base_u_size,
mp, msize, &karactx);
else
mul_mod (rp, &rsize, base_u, base_u_size, xp, xsize,
mp, msize, &karactx);
base_u = precomp[i] = mpi_alloc_limb_space (rsize, esec);
base_u_size = precomp_size[i] = rsize;
if (max_u_size < base_u_size)
max_u_size = base_u_size;
MPN_COPY (precomp[i], rp, rsize);
}
if (msize > max_u_size)
max_u_size = msize;
base_u = mpi_alloc_limb_space (max_u_size, esec);
MPN_ZERO (base_u, max_u_size);
i = esize - 1;
/* Main loop.
Make the result be pointed to alternately by XP and RP. This
helps us avoid block copying, which would otherwise be
necessary with the overlap restrictions of
_gcry_mpih_divmod. With 50% probability the result after this
loop will be in the area originally pointed by RP (==RES->d),
and with 50% probability in the area originally pointed to by XP. */
rsign = 0;
if (W == 1)
{
rsize = bsize;
}
else
{
rsize = msize;
MPN_ZERO (rp, rsize);
}
MPN_COPY ( rp, bp, bsize );
e = ep[i];
count_leading_zeros (c, e);
e = (e << c) << 1;
c = BITS_PER_MPI_LIMB - 1 - c;
j = 0;
for (;;)
if (e == 0)
{
j += c;
if ( --i < 0 )
break;
e = ep[i];
c = BITS_PER_MPI_LIMB;
}
else
{
int c0;
mpi_limb_t e0;
struct gcry_mpi w, u;
w.sign = u.sign = 0;
w.flags = u.flags = 0;
w.d = base_u;
count_leading_zeros (c0, e);
e = (e << c0);
c -= c0;
j += c0;
e0 = (e >> (BITS_PER_MPI_LIMB - W));
if (c >= W)
c0 = 0;
else
{
if ( --i < 0 )
{
e0 = (e >> (BITS_PER_MPI_LIMB - c));
j += c - W;
goto last_step;
}
else
{
c0 = c;
e = ep[i];
c = BITS_PER_MPI_LIMB;
e0 |= (e >> (BITS_PER_MPI_LIMB - (W - c0)));
}
}
e = e << (W - c0);
c -= (W - c0);
last_step:
count_trailing_zeros (c0, e0);
e0 = (e0 >> c0) >> 1;
for (j += W - c0; j >= 0; j--)
{
/*
* base_u <= precomp[e0]
* base_u_size <= precomp_size[e0]
*/
base_u_size = 0;
for (k = 0; k < (1<< (W - 1)); k++)
{
w.alloced = w.nlimbs = precomp_size[k];
u.alloced = u.nlimbs = precomp_size[k];
u.d = precomp[k];
mpi_set_cond (&w, &u, k == e0);
base_u_size |= ( precomp_size[k] & (0UL - (k == e0)) );
}
w.alloced = w.nlimbs = rsize;
u.alloced = u.nlimbs = rsize;
u.d = rp;
mpi_set_cond (&w, &u, j != 0);
base_u_size ^= ((base_u_size ^ rsize) & (0UL - (j != 0)));
mul_mod (xp, &xsize, rp, rsize, base_u, base_u_size,
mp, msize, &karactx);
tp = rp; rp = xp; xp = tp;
rsize = xsize;
}
j = c0;
if ( i < 0 )
break;
}
while (j--)
{
mul_mod (xp, &xsize, rp, rsize, rp, rsize, mp, msize, &karactx);
tp = rp; rp = xp; xp = tp;
rsize = xsize;
}
/* We shifted MOD, the modulo reduction argument, left
MOD_SHIFT_CNT steps. Adjust the result by reducing it with the
original MOD.
Also make sure the result is put in RES->d (where it already
might be, see above). */
if ( mod_shift_cnt )
{
carry_limb = _gcry_mpih_lshift( res->d, rp, rsize, mod_shift_cnt);
rp = res->d;
if ( carry_limb )
{
rp[rsize] = carry_limb;
rsize++;
}
}
else if (res->d != rp)
{
MPN_COPY (res->d, rp, rsize);
rp = res->d;
}
if ( rsize >= msize )
{
_gcry_mpih_divrem(rp + msize, 0, rp, rsize, mp, msize);
rsize = msize;
}
/* Remove any leading zero words from the result. */
if ( mod_shift_cnt )
_gcry_mpih_rshift( rp, rp, rsize, mod_shift_cnt);
MPN_NORMALIZE (rp, rsize);
_gcry_mpih_release_karatsuba_ctx (&karactx );
for (i = 0; i < (1 << (W - 1)); i++)
_gcry_mpi_free_limb_space( precomp[i], esec ? precomp_size[i] : 0 );
_gcry_mpi_free_limb_space (base_u, esec ? max_u_size : 0);
}
/* Fixup for negative results. */
if ( negative_result && rsize )
{
if ( mod_shift_cnt )
_gcry_mpih_rshift( mp, mp, msize, mod_shift_cnt);
_gcry_mpih_sub( rp, mp, msize, rp, rsize);
rsize = msize;
rsign = msign;
MPN_NORMALIZE(rp, rsize);
}
gcry_assert (res->d == rp);
res->nlimbs = rsize;
res->sign = rsign;
leave:
if (mp_marker)
_gcry_mpi_free_limb_space( mp_marker, mp_nlimbs );
if (bp_marker)
_gcry_mpi_free_limb_space( bp_marker, bp_nlimbs );
if (ep_marker)
_gcry_mpi_free_limb_space( ep_marker, ep_nlimbs );
if (xp_marker)
_gcry_mpi_free_limb_space( xp_marker, xp_nlimbs );
}
#endif
diff --git a/mpi/mpih-pow.c b/mpi/mpih-pow.c
new file mode 100644
index 00000000..649052f6
--- /dev/null
+++ b/mpi/mpih-pow.c
@@ -0,0 +1,283 @@
+/* mpih-pow.c - MPI helper functions
+ * Copyright (C) 2025 g10 Code GmbH
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt 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.
+ *
+ * Libgcrypt 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 <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "mpi-internal.h"
+#include "longlong.h"
+
+#if BITS_PER_MPI_LIMB <= 32
+#define MAX_SCRATCH_SPACE 256*2
+#define MAX_WINDOW 8
+#else
+#define MAX_SCRATCH_SPACE 256
+#define MAX_WINDOW 4
+#endif
+
+/*
+ * Compute -N^(-1) mod 2^BITS_PER_MPI_LIMB
+ *
+ * (1) Compute N^(-1) mod 2^BITS_PER_MPI_LIMB
+ * (2) Then, negate the value of (1)
+ *
+ * For computing N^(-1) mod (power of two), see:
+ *
+ * Jeffrey Hurchalla
+ * An Improved Integer Modular Multiplicative Inverse (modulo 2^w)
+ * https://arxiv.org/abs/2204.04342
+ *
+ */
+static mpi_limb_t
+compute_minv (mpi_limb_t n)
+{
+ mpi_limb_t x, y;
+
+ gcry_assert (n%2 == 1);
+
+ x = (3*n)^2;
+ y = 1 - n*x;
+ x = x*(1 + y);
+ y *= y;
+ x = x*(1 + y);
+ y *= y;
+ x = x*(1 + y);
+#if BITS_PER_MPI_LIMB == 32
+ return -x;
+#elif BITS_PER_MPI_LIMB == 64
+ y *= y;
+ x = x*(1 + y);
+ return -x;
+#else
+# error "Please implement multiplicative inverse mod power of 2"
+#endif
+}
+
+
+/*
+ * Compute T * R^(-1) mod M (where R is represented by MINV)
+ *
+ * Reference:
+ * Handbook of Applied Cryptography
+ * Algorithm 14.82: Montgomery reduction
+ */
+static void
+mont_reduc (mpi_ptr_t rp, mpi_ptr_t tp,
+ mpi_ptr_t mp, mpi_size_t n, mpi_limb_t minv)
+{
+ mpi_size_t i;
+ mpi_limb_t cy0;
+ mpi_limb_t cy1 = 0;
+
+ for (i = 0; i < n; i++)
+ {
+ mpi_limb_t ui = tp[i] * minv;
+
+ cy0 = _gcry_mpih_addmul_1 (tp + i, mp, n, ui);
+ cy1 += _gcry_mpih_add_1_lli (tp + n + i, n - i, cy0);
+ }
+
+ cy0 = _gcry_mpih_sub_n (rp, tp + n, mp, n);
+ _gcry_mpih_set_cond (rp, tp + n, n,
+ mpih_limb_is_not_zero (cy0)
+ & mpih_limb_is_zero (cy1));
+}
+
+/*
+ * Compute X * Y * R^(-1) mod M (where R is represented by MINV)
+ *
+ * Reference:
+ * Handbook of Applied Cryptography
+ * Algorithm 14.86: Montgomery multiplication
+ *
+ * RP should have space of 2*N limbs.
+ *
+ */
+static void
+mont_mul (mpi_ptr_t rp, mpi_ptr_t xp, mpi_ptr_t yp, mpi_ptr_t mp,
+ mpi_size_t n, mpi_limb_t minv, mpi_ptr_t scratch_2n)
+{
+ _gcry_mpih_mul_lli (scratch_2n, xp, n, yp, n);
+ mont_reduc (rp, scratch_2n, mp, n, minv);
+}
+
+/* Determine the window size for computing exponentiation. */
+static int
+window_size (mpi_size_t esize)
+{
+ int W;
+
+#if BITS_PER_MPI_LIMB <= 32
+ if (esize > 24)
+ W = 5;
+ else if (esize > 16)
+ W = 4;
+ else if (esize > 12)
+ W = 3;
+ else if (esize > 8)
+ W = 2;
+ else
+ W = 1;
+ return W;
+#else
+ if (esize > 8)
+ W = 4;
+ else if (esize > 6)
+ W = 3;
+ else if (esize > 4)
+ W = 2;
+ else
+ W = 1;
+ return W;
+#endif
+ return W;
+}
+
+/*
+ * Compute X ^ E mod M
+ *
+ * where X is in BP, M is in MP.
+ * The size of limbs for BP and MP are N.
+ * E is in EP, size of limbs EN.
+ *
+ * Result will be in RP with size N.
+ *
+ * Reference:
+ * Handbook of Applied Cryptography
+ * Algorithm 14.82: Left-to-right k-ary exponentiation
+ * Algorithm 14.94: Montgomery exponentiation
+ *
+ */
+void
+_gcry_mpih_powm_lli (mpi_ptr_t rp, mpi_ptr_t bp, mpi_ptr_t mp, mpi_size_t n,
+ mpi_ptr_t ep, mpi_size_t en)
+{
+ mpi_size_t scratch_size;
+#define temp0 (scratch)
+#define temp2 (scratch+n*2)
+#define a (scratch+n*4)
+#define precomp (scratch+n*5)
+ mpi_ptr_t scratch;
+ mpi_limb_t minv;
+ mpi_size_t i;
+ int mod_shift_cnt;
+ int windowsize = window_size (en);
+ mpi_limb_t wmask = (((mpi_limb_t) 1 << windowsize) - 1);
+#define temp1 (precomp+n)
+#define x_tilde (precomp+n)
+
+ scratch_size = (5 + (1 << windowsize))*n;
+ scratch = _gcry_mpi_alloc_limb_space (scratch_size, 1);
+
+ minv = compute_minv (mp[0]);
+
+ gcry_assert (mp[0]*(-minv) == 1);
+
+ MPN_ZERO (temp0, n);
+
+ /* TEMP0 := R mod m */
+ count_leading_zeros (mod_shift_cnt, mp[n-1]);
+ if (mod_shift_cnt)
+ {
+ _gcry_mpih_lshift (temp2, mp, n, mod_shift_cnt);
+ temp0[n] = (mpi_limb_t)1 << mod_shift_cnt;
+ }
+ else
+ {
+ MPN_COPY (temp2, mp, n);
+ temp0[n] = 1;
+ }
+ _gcry_mpih_divrem (temp1, 0, temp0, n+1, temp2, n);
+ if (mod_shift_cnt)
+ _gcry_mpih_rshift (temp0, temp0, n, mod_shift_cnt);
+ /* PRECOMP[0] := R mod m */
+ MPN_COPY (precomp, temp0, n);
+
+ /* TEMP0 := (R mod m)^2 */
+ _gcry_mpih_sqr_n_basecase (temp0, precomp, n);
+
+ /* TEMP0 := R^2 mod m */
+ if (mod_shift_cnt)
+ _gcry_mpih_lshift (temp0, temp0, n*2, mod_shift_cnt);
+ _gcry_mpih_divrem (temp1, 0, temp0, n*2, temp2, n);
+ if (mod_shift_cnt)
+ _gcry_mpih_rshift (temp0, temp0, n, mod_shift_cnt);
+ /* x~ := Mont(x, R^2 mod m) */
+ mont_mul (x_tilde, bp, temp0, mp, n, minv, temp2);
+
+ /* PRECOMP[i] := x~ ^ i */
+ for (i = 0; i < (1 << windowsize) - 2; i += 2)
+ {
+ _gcry_mpih_sqr_n_basecase (temp0, precomp+n*(i/2+1), n);
+ mont_reduc (precomp+n*(i+2), temp0, mp, n, minv);
+ mont_mul (precomp+n*(i+3), x_tilde, precomp+n*(i+2), mp, n, minv, temp2);
+ }
+
+ MPN_COPY (a, precomp, n);
+ i = en * BITS_PER_MPI_LIMB;
+ do
+ {
+ mpi_limb_t e;
+ int w;
+
+ if (i < windowsize)
+ {
+ e = ep[0] & (((mpi_limb_t) 1 << i) - 1);
+ w = i;
+ i = 0;
+ }
+ else
+ {
+ mpi_limb_t v;
+ mpi_size_t shift;
+ mpi_size_t j;
+ int nbits_in_v;
+
+ i -= windowsize;
+ j = i / BITS_PER_MPI_LIMB;
+ shift = i % BITS_PER_MPI_LIMB;
+ v = ep[j] >> shift;
+ nbits_in_v = BITS_PER_MPI_LIMB - shift;
+ if (nbits_in_v < windowsize)
+ v += ep[j + 1] << nbits_in_v;
+ e = v & wmask;
+ w = windowsize;
+ }
+
+ do
+ {
+ _gcry_mpih_sqr_n_basecase (temp0, a, n);
+ mont_reduc (a, temp0, mp, n, minv);
+ }
+ while (--w);
+
+ _gcry_mpih_lookup_lli (temp0, precomp, n, (1 << windowsize), e);
+ mont_mul (a, a, temp0, mp, n, minv, temp2);
+ }
+ while (i);
+
+ MPN_ZERO (temp0, n);
+ temp0[0] = 1;
+ mont_mul (a, a, temp0, mp, n, minv, temp2);
+
+ MPN_COPY (rp, a, n);
+ _gcry_mpi_free_limb_space (scratch, scratch_size);
+}
diff --git a/src/gcrypt-int.h b/src/gcrypt-int.h
index d52a1b1b..1eb58cb9 100644
--- a/src/gcrypt-int.h
+++ b/src/gcrypt-int.h
@@ -1,612 +1,613 @@
/* gcrypt-int.h - Internal version of gcrypt.h
* Copyright (C) 2013 g10 Code GmbH
*
* This file is part of Libgcrypt.
*
* Libgcrypt 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.
*
* Libgcrypt 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 <http://www.gnu.org/licenses/>.
*/
#ifndef GCRY_GCRYPT_INT_H
#define GCRY_GCRYPT_INT_H
#ifdef _GCRYPT_H
#error gcrypt.h already included
#endif
#include "gcrypt.h"
#include "types.h"
/* These error codes are used but not defined in the required
* libgpg-error N.MM. Define them here. [None right now.] */
/* Context used with elliptic curve functions. */
struct mpi_ec_ctx_s;
typedef struct mpi_ec_ctx_s *mpi_ec_t;
/* Underscore prefixed internal versions of the public functions.
They return gpg_err_code_t and not gpg_error_t. Some macros also
need an underscore prefixed internal version.
Note that the memory allocation functions and macros (xmalloc etc.)
are not defined here but in g10lib.h because this file here is
included by some test programs which define theie own xmalloc
macros. */
gpg_err_code_t _gcry_cipher_open (gcry_cipher_hd_t *handle,
int algo, int mode, unsigned int flags);
void _gcry_cipher_close (gcry_cipher_hd_t h);
gpg_err_code_t _gcry_cipher_ctl (gcry_cipher_hd_t h, int cmd, void *buffer,
size_t buflen);
gpg_err_code_t _gcry_cipher_info (gcry_cipher_hd_t h, int what, void *buffer,
size_t *nbytes);
gpg_err_code_t _gcry_cipher_algo_info (int algo, int what, void *buffer,
size_t *nbytes);
const char *_gcry_cipher_algo_name (int algorithm) _GCRY_GCC_ATTR_PURE;
int _gcry_cipher_map_name (const char *name) _GCRY_GCC_ATTR_PURE;
int _gcry_cipher_mode_from_oid (const char *string) _GCRY_GCC_ATTR_PURE;
gpg_err_code_t _gcry_cipher_encrypt (gcry_cipher_hd_t h,
void *out, size_t outsize,
const void *in, size_t inlen);
gpg_err_code_t _gcry_cipher_decrypt (gcry_cipher_hd_t h,
void *out, size_t outsize,
const void *in, size_t inlen);
gcry_err_code_t _gcry_cipher_setkey (gcry_cipher_hd_t hd,
const void *key, size_t keylen);
gcry_err_code_t _gcry_cipher_setiv (gcry_cipher_hd_t hd,
const void *iv, size_t ivlen);
gcry_err_code_t _gcry_cipher_setup_geniv (gcry_cipher_hd_t hd, int method,
const void *fixed_iv,
size_t fixed_ivlen,
const void *dyn_iv, size_t dyn_ivlen);
gcry_err_code_t _gcry_cipher_geniv (gcry_cipher_hd_t hd,
void *iv, size_t ivlen);
gpg_err_code_t _gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf,
size_t abuflen);
gpg_err_code_t _gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag,
size_t taglen);
gpg_err_code_t _gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag,
size_t taglen);
gpg_err_code_t _gcry_cipher_setctr (gcry_cipher_hd_t hd,
const void *ctr, size_t ctrlen);
gpg_err_code_t _gcry_cipher_getctr (gcry_cipher_hd_t hd,
void *ctr, size_t ctrlen);
size_t _gcry_cipher_get_algo_keylen (int algo);
size_t _gcry_cipher_get_algo_blklen (int algo);
#define _gcry_cipher_reset(h) _gcry_cipher_ctl ((h), GCRYCTL_RESET, NULL, 0)
gpg_err_code_t _gcry_pk_encrypt (gcry_sexp_t *result,
gcry_sexp_t data, gcry_sexp_t pkey);
gpg_err_code_t _gcry_pk_decrypt (gcry_sexp_t *result,
gcry_sexp_t data, gcry_sexp_t skey);
gpg_err_code_t _gcry_pk_sign (gcry_sexp_t *result,
gcry_sexp_t data, gcry_sexp_t skey);
gpg_err_code_t _gcry_pk_verify (gcry_sexp_t sigval,
gcry_sexp_t data, gcry_sexp_t pkey);
gpg_err_code_t _gcry_pk_testkey (gcry_sexp_t key);
gpg_err_code_t _gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms);
gpg_err_code_t _gcry_pk_ctl (int cmd, void *buffer, size_t buflen);
gpg_err_code_t _gcry_pk_algo_info (int algo, int what,
void *buffer, size_t *nbytes);
const char *_gcry_pk_algo_name (int algorithm) _GCRY_GCC_ATTR_PURE;
int _gcry_pk_map_name (const char* name) _GCRY_GCC_ATTR_PURE;
unsigned int _gcry_pk_get_nbits (gcry_sexp_t key) _GCRY_GCC_ATTR_PURE;
unsigned char *_gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array);
const char *_gcry_pk_get_curve (gcry_sexp_t key, int iterator,
unsigned int *r_nbits);
gcry_sexp_t _gcry_pk_get_param (int algo, const char *name);
gpg_err_code_t _gcry_pubkey_get_sexp (gcry_sexp_t *r_sexp,
int mode, gcry_ctx_t ctx);
unsigned int _gcry_ecc_get_algo_keylen (int algo);
gpg_err_code_t _gcry_ecc_curve_keypair (const char *curve,
unsigned char *pubkey,
size_t pubkey_len,
unsigned char *seckey,
size_t seckey_len);
gpg_err_code_t _gcry_ecc_curve_mul_point (const char *curve,
unsigned char *result,
size_t result_len,
const unsigned char *scalar,
size_t scalar_len,
const unsigned char *point,
size_t point_len);
gpg_err_code_t _gcry_ecc_mul_point (int algo, unsigned char *result,
const unsigned char *scalar,
const unsigned char *point);
gcry_err_code_t _gcry_pk_sign_md (gcry_sexp_t *r_sig, const char *tmpl,
gcry_md_hd_t hd, gcry_sexp_t s_skey,
gcry_ctx_t ctx);
gcry_err_code_t _gcry_pk_verify_md (gcry_sexp_t s_sig, const char *tmpl,
gcry_md_hd_t hd, gcry_sexp_t s_pkey,
gcry_ctx_t ctx);
gpg_err_code_t _gcry_pk_single_data_push (gcry_ctx_t *r_ctx,
const unsigned char *p,
size_t len);
gpg_err_code_t _gcry_pk_get_single_data (gcry_ctx_t *r_ctx,
const unsigned char **r_p,
size_t *r_len);
gpg_err_code_t _gcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags);
void _gcry_md_close (gcry_md_hd_t hd);
gpg_err_code_t _gcry_md_enable (gcry_md_hd_t hd, int algo);
gpg_err_code_t _gcry_md_copy (gcry_md_hd_t *bhd, gcry_md_hd_t ahd);
void _gcry_md_reset (gcry_md_hd_t hd);
gpg_err_code_t _gcry_md_ctl (gcry_md_hd_t hd, int cmd,
void *buffer, size_t buflen);
void _gcry_md_write (gcry_md_hd_t hd, const void *buffer, size_t length);
unsigned char *_gcry_md_read (gcry_md_hd_t hd, int algo);
gpg_err_code_t _gcry_md_extract (gcry_md_hd_t hd, int algo, void *buffer,
size_t length);
void _gcry_md_hash_buffer (int algo, void *digest,
const void *buffer, size_t length);
gpg_err_code_t _gcry_md_hash_buffers_extract (int algo, unsigned int flags,
void *digest, int digestlen,
const gcry_buffer_t *iov,
int iovcnt);
gpg_err_code_t _gcry_md_hash_buffers (int algo, unsigned int flags,
void *digest,
const gcry_buffer_t *iov, int iovcnt);
int _gcry_md_get_algo (gcry_md_hd_t hd);
unsigned int _gcry_md_get_algo_dlen (int algo);
int _gcry_md_is_enabled (gcry_md_hd_t a, int algo);
int _gcry_md_is_secure (gcry_md_hd_t a);
gpg_err_code_t _gcry_md_info (gcry_md_hd_t h, int what, void *buffer,
size_t *nbytes);
gpg_err_code_t _gcry_md_algo_info (int algo, int what, void *buffer,
size_t *nbytes);
const char *_gcry_md_algo_name (int algo) _GCRY_GCC_ATTR_PURE;
int _gcry_md_map_name (const char* name) _GCRY_GCC_ATTR_PURE;
gpg_err_code_t _gcry_md_setkey (gcry_md_hd_t hd,
const void *key, size_t keylen);
void _gcry_md_debug (gcry_md_hd_t hd, const char *suffix);
#define _gcry_md_test_algo(a) \
_gcry_md_algo_info ((a), GCRYCTL_TEST_ALGO, NULL, NULL)
#define _gcry_md_final(a) \
_gcry_md_ctl ((a), GCRYCTL_FINALIZE, NULL, 0)
#define _gcry_md_putc(h,c) \
do { \
gcry_md_hd_t h__ = (h); \
if( (h__)->bufpos == (h__)->bufsize ) \
_gcry_md_write( (h__), NULL, 0 ); \
(h__)->buf[(h__)->bufpos++] = (c) & 0xff; \
} while(0)
gpg_err_code_t _gcry_mac_open (gcry_mac_hd_t *handle, int algo,
unsigned int flags, gcry_ctx_t ctx);
void _gcry_mac_close (gcry_mac_hd_t h);
gpg_err_code_t _gcry_mac_ctl (gcry_mac_hd_t h, int cmd, void *buffer,
size_t buflen);
gpg_err_code_t _gcry_mac_algo_info (int algo, int what, void *buffer,
size_t *nbytes);
gpg_err_code_t _gcry_mac_setkey (gcry_mac_hd_t hd, const void *key,
size_t keylen);
gpg_err_code_t _gcry_mac_setiv (gcry_mac_hd_t hd, const void *iv,
size_t ivlen);
gpg_err_code_t _gcry_mac_write (gcry_mac_hd_t hd, const void *buffer,
size_t length);
gpg_err_code_t _gcry_mac_read (gcry_mac_hd_t hd, void *buffer, size_t *buflen);
gpg_err_code_t _gcry_mac_verify (gcry_mac_hd_t hd, const void *buffer,
size_t buflen);
int _gcry_mac_get_algo (gcry_mac_hd_t hd);
unsigned int _gcry_mac_get_algo_maclen (int algo);
unsigned int _gcry_mac_get_algo_keylen (int algo);
const char *_gcry_mac_algo_name (int algorithm) _GCRY_GCC_ATTR_PURE;
int _gcry_mac_map_name (const char *name) _GCRY_GCC_ATTR_PURE;
#define _gcry_mac_reset(h) _gcry_mac_ctl ((h), GCRYCTL_RESET, NULL, 0)
gpg_err_code_t _gcry_kdf_derive (const void *passphrase, size_t passphraselen,
int algo, int subalgo,
const void *salt, size_t saltlen,
unsigned long iterations,
size_t keysize, void *keybuffer);
gpg_err_code_t _gcry_kdf_open (gcry_kdf_hd_t *hd, int algo, int subalgo,
const unsigned long *param,
unsigned int paramlen,
const void *passphrase, size_t passphraselen,
const void *salt, size_t saltlen,
const void *key, size_t keylen,
const void *ad, size_t adlen);
gcry_err_code_t _gcry_kdf_compute (gcry_kdf_hd_t h,
const struct gcry_kdf_thread_ops *ops);
gpg_err_code_t _gcry_kdf_final (gcry_kdf_hd_t h, size_t resultlen, void *result);
void _gcry_kdf_close (gcry_kdf_hd_t h);
gcry_err_code_t _gcry_kem_genkey (int algo,
void *pubkey, size_t pubkey_len,
void *seckey, size_t seckey_len,
const void *optional, size_t optional_len);
gcry_err_code_t _gcry_kem_encap (int algo,
const void *pubkey, size_t pubkey_len,
void *ciphertext, size_t ciphertext_len,
void *shared, size_t shared_len,
const void *optional, size_t optional_len);
gcry_err_code_t _gcry_kem_decap (int algo,
const void *seckey, size_t seckey_len,
const void *ciphertext, size_t ciphertext_len,
void *shared, size_t shared_len,
const void *optional, size_t optional_len);
gpg_err_code_t _gcry_prime_generate (gcry_mpi_t *prime,
unsigned int prime_bits,
unsigned int factor_bits,
gcry_mpi_t **factors,
gcry_prime_check_func_t cb_func,
void *cb_arg,
gcry_random_level_t random_level,
unsigned int flags);
gpg_err_code_t _gcry_prime_group_generator (gcry_mpi_t *r_g,
gcry_mpi_t prime,
gcry_mpi_t *factors,
gcry_mpi_t start_g);
void _gcry_prime_release_factors (gcry_mpi_t *factors);
gpg_err_code_t _gcry_prime_check (gcry_mpi_t x, unsigned int flags);
void _gcry_randomize (void *buffer, size_t length,
enum gcry_random_level level);
gpg_err_code_t _gcry_random_add_bytes (const void *buffer, size_t length,
int quality);
void *_gcry_random_bytes (size_t nbytes, enum gcry_random_level level)
_GCRY_GCC_ATTR_MALLOC;
void *_gcry_random_bytes_secure (size_t nbytes, enum gcry_random_level level)
_GCRY_GCC_ATTR_MALLOC;
void _gcry_mpi_randomize (gcry_mpi_t w,
unsigned int nbits, enum gcry_random_level level);
void _gcry_create_nonce (void *buffer, size_t length);
void _gcry_ctx_release (gcry_ctx_t ctx);
const char *_gcry_check_version (const char *req_version);
void _gcry_set_allocation_handler (gcry_handler_alloc_t func_alloc,
gcry_handler_alloc_t func_alloc_secure,
gcry_handler_secure_check_t func_secure_check,
gcry_handler_realloc_t func_realloc,
gcry_handler_free_t func_free);
void _gcry_set_outofcore_handler (gcry_handler_no_mem_t h, void *opaque);
void _gcry_set_fatalerror_handler (gcry_handler_error_t fnc, void *opaque);
void _gcry_set_log_handler (gcry_handler_log_t f, void *opaque);
void _gcry_set_gettext_handler (const char *(*f)(const char*));
void _gcry_set_progress_handler (gcry_handler_progress_t cb, void *cb_data);
void _gcry_thread_context_set_reject (unsigned int flags);
int _gcry_thread_context_check_rejection (unsigned int flag);
#define fips_check_rejection(flag) \
_gcry_thread_context_check_rejection (flag)
void _gcry_thread_context_set_fsi (unsigned long fsi);
unsigned long _gcry_thread_context_get_fsi (void);
#define fips_service_indicator_init() do \
{ \
if (fips_mode ()) \
_gcry_thread_context_set_fsi (0); \
} while (0)
/* Should be used only when fips_mode()==TRUE. */
#define fips_service_indicator_mark_non_compliant() \
_gcry_thread_context_set_fsi (1)
/* Return a pointer to a string containing a description of the error
code in the error value ERR. */
static inline const char *
_gcry_strerror (gcry_error_t err)
{
return gpg_strerror (err);
}
/* Return a pointer to a string containing a description of the error
source in the error value ERR. */
static inline const char *
_gcry_strsource (gcry_error_t err)
{
return gpg_strsource (err);
}
/* Retrieve the error code for the system error ERR. This returns
GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped (report
this). */
static inline gcry_err_code_t
_gcry_err_code_from_errno (int err)
{
return gpg_err_code_from_errno (err);
}
/* Retrieve the system error for the error code CODE. This returns 0
if CODE is not a system error code. */
static inline int
_gcry_err_code_to_errno (gcry_err_code_t code)
{
return gpg_err_code_to_errno (code);
}
/* Return an error value with the error source SOURCE and the system
error ERR. */
static inline gcry_error_t
_gcry_err_make_from_errno (gpg_err_source_t source, int err)
{
return gpg_err_make_from_errno (source, err);
}
/* Return an error value with the system error ERR. */
static inline gcry_error_t
_gcry_error_from_errno (int err)
{
return gpg_error (gpg_err_code_from_errno (err));
}
gpg_err_code_t _gcry_sexp_new (gcry_sexp_t *retsexp,
const void *buffer, size_t length,
int autodetect);
gpg_err_code_t _gcry_sexp_create (gcry_sexp_t *retsexp,
void *buffer, size_t length,
int autodetect, void (*freefnc) (void *));
gpg_err_code_t _gcry_sexp_sscan (gcry_sexp_t *retsexp, size_t *erroff,
const char *buffer, size_t length);
gpg_err_code_t _gcry_sexp_build (gcry_sexp_t *retsexp, size_t *erroff,
const char *format, ...);
gpg_err_code_t _gcry_sexp_build_array (gcry_sexp_t *retsexp, size_t *erroff,
const char *format, void **arg_list);
void _gcry_sexp_release (gcry_sexp_t sexp);
size_t _gcry_sexp_canon_len (const unsigned char *buffer, size_t length,
size_t *erroff, gcry_err_code_t *errcode);
size_t _gcry_sexp_sprint (gcry_sexp_t sexp, int mode, void *buffer,
size_t maxlength);
void _gcry_sexp_dump (const gcry_sexp_t a);
gcry_sexp_t _gcry_sexp_cons (const gcry_sexp_t a, const gcry_sexp_t b);
gcry_sexp_t _gcry_sexp_alist (const gcry_sexp_t *array);
gcry_sexp_t _gcry_sexp_vlist (const gcry_sexp_t a, ...);
gcry_sexp_t _gcry_sexp_append (const gcry_sexp_t a, const gcry_sexp_t n);
gcry_sexp_t _gcry_sexp_prepend (const gcry_sexp_t a, const gcry_sexp_t n);
gcry_sexp_t _gcry_sexp_find_token (gcry_sexp_t list,
const char *tok, size_t toklen);
int _gcry_sexp_length (const gcry_sexp_t list);
gcry_sexp_t _gcry_sexp_nth (const gcry_sexp_t list, int number);
gcry_sexp_t _gcry_sexp_car (const gcry_sexp_t list);
gcry_sexp_t _gcry_sexp_cdr (const gcry_sexp_t list);
gcry_sexp_t _gcry_sexp_cadr (const gcry_sexp_t list);
const char *_gcry_sexp_nth_data (const gcry_sexp_t list, int number,
size_t *datalen);
void *_gcry_sexp_nth_buffer (const gcry_sexp_t list, int number,
size_t *rlength);
char *_gcry_sexp_nth_string (gcry_sexp_t list, int number);
gcry_mpi_t _gcry_sexp_nth_mpi (gcry_sexp_t list, int number, int mpifmt);
gpg_err_code_t _gcry_sexp_extract_param (gcry_sexp_t sexp,
const char *path,
const char *list,
...) _GCRY_GCC_ATTR_SENTINEL(0);
#define sexp_new(a, b, c, d) _gcry_sexp_new ((a), (b), (c), (d))
#define sexp_create(a, b, c, d, e) _gcry_sexp_create ((a), (b), (c), (d), (e))
#define sexp_sscan(a, b, c, d) _gcry_sexp_sscan ((a), (b), (c), (d))
#define sexp_build _gcry_sexp_build
#define sexp_build_array(a, b, c, d) _gcry_sexp_build_array ((a), (b), (c), (d))
#define sexp_release(a) _gcry_sexp_release ((a))
#define sexp_canon_len(a, b, c, d) _gcry_sexp_canon_len ((a), (b), (c), (d))
#define sexp_sprint(a, b, c, d) _gcry_sexp_sprint ((a), (b), (c), (d))
#define sexp_dump(a) _gcry_sexp_dump ((a))
#define sexp_cons(a, b) _gcry_sexp_cons ((a), (b))
#define sexp_alist(a) _gcry_sexp_alist ((a))
#define sexp_vlist _gcry_sexp_vlist
#define sexp_append(a, b) _gcry_sexp_append ((a), (b))
#define sexp_prepend(a, b) _gcry_sexp_prepend ((a), (b))
#define sexp_find_token(a, b, c) _gcry_sexp_find_token ((a), (b), (c))
#define sexp_length(a) _gcry_sexp_length ((a))
#define sexp_nth(a, b) _gcry_sexp_nth ((a), (b))
#define sexp_car(a) _gcry_sexp_car ((a))
#define sexp_cdr(a) _gcry_sexp_cdr ((a))
#define sexp_cadr(a) _gcry_sexp_cadr ((a))
#define sexp_nth_data(a, b, c) _gcry_sexp_nth_data ((a), (b), (c))
#define sexp_nth_buffer(a, b, c) _gcry_sexp_nth_buffer ((a), (b), (c))
#define sexp_nth_string(a, b) _gcry_sexp_nth_string ((a), (b))
#define sexp_nth_mpi(a, b, c) _gcry_sexp_nth_mpi ((a), (b), (c))
#define sexp_extract_param _gcry_sexp_extract_param
gcry_mpi_t _gcry_mpi_new (unsigned int nbits);
gcry_mpi_t _gcry_mpi_snew (unsigned int nbits);
void _gcry_mpi_release (gcry_mpi_t a);
gcry_mpi_t _gcry_mpi_copy (const gcry_mpi_t a);
void _gcry_mpi_snatch (gcry_mpi_t w, gcry_mpi_t u);
gcry_mpi_t _gcry_mpi_set (gcry_mpi_t w, const gcry_mpi_t u);
gcry_mpi_t _gcry_mpi_set_ui (gcry_mpi_t w, unsigned long u);
gcry_err_code_t _gcry_mpi_get_ui (unsigned int *w, gcry_mpi_t u);
void _gcry_mpi_swap (gcry_mpi_t a, gcry_mpi_t b);
int _gcry_mpi_is_neg (gcry_mpi_t a);
void _gcry_mpi_neg (gcry_mpi_t w, gcry_mpi_t u);
void _gcry_mpi_abs (gcry_mpi_t w);
int _gcry_mpi_cmp (const gcry_mpi_t u, const gcry_mpi_t v);
int _gcry_mpi_cmpabs (const gcry_mpi_t u, const gcry_mpi_t v);
int _gcry_mpi_cmp_ui (const gcry_mpi_t u, unsigned long v);
gpg_err_code_t _gcry_mpi_scan (gcry_mpi_t *ret_mpi, enum gcry_mpi_format format,
const void *buffer, size_t buflen,
size_t *nscanned);
gpg_err_code_t _gcry_mpi_print (enum gcry_mpi_format format,
unsigned char *buffer, size_t buflen,
size_t *nwritten,
const gcry_mpi_t a);
gpg_err_code_t _gcry_mpi_aprint (enum gcry_mpi_format format,
unsigned char **buffer, size_t *nwritten,
const gcry_mpi_t a);
void _gcry_mpi_dump (const gcry_mpi_t a);
void _gcry_mpi_add (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v);
void _gcry_mpi_add_ui (gcry_mpi_t w, gcry_mpi_t u, unsigned long v);
void _gcry_mpi_addm (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, gcry_mpi_t m);
void _gcry_mpi_sub (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v);
void _gcry_mpi_sub_ui (gcry_mpi_t w, gcry_mpi_t u, unsigned long v );
void _gcry_mpi_subm (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, gcry_mpi_t m);
void _gcry_mpi_mul (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v);
void _gcry_mpi_mul_ui (gcry_mpi_t w, gcry_mpi_t u, unsigned long v );
void _gcry_mpi_mulm (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, gcry_mpi_t m);
void _gcry_mpi_mul_2exp (gcry_mpi_t w, gcry_mpi_t u, unsigned long cnt);
void _gcry_mpi_div (gcry_mpi_t q, gcry_mpi_t r,
gcry_mpi_t dividend, gcry_mpi_t divisor, int round);
void _gcry_mpi_mod (gcry_mpi_t r, gcry_mpi_t dividend, gcry_mpi_t divisor);
+const char *_gcry_mpi_get_powm_config (void);
void _gcry_mpi_powm (gcry_mpi_t w,
const gcry_mpi_t b, const gcry_mpi_t e,
const gcry_mpi_t m);
int _gcry_mpi_gcd (gcry_mpi_t g, gcry_mpi_t a, gcry_mpi_t b);
int _gcry_mpi_invm (gcry_mpi_t x, gcry_mpi_t a, gcry_mpi_t m);
gcry_mpi_point_t _gcry_mpi_point_new (unsigned int nbits);
void _gcry_mpi_point_release (gcry_mpi_point_t point);
gcry_mpi_point_t _gcry_mpi_point_copy (gcry_mpi_point_t point);
void _gcry_mpi_point_get (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t z,
gcry_mpi_point_t point);
void _gcry_mpi_point_snatch_get (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t z,
gcry_mpi_point_t point);
gcry_mpi_point_t _gcry_mpi_point_set (gcry_mpi_point_t point,
gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t z);
gcry_mpi_point_t _gcry_mpi_point_snatch_set (gcry_mpi_point_t point,
gcry_mpi_t x, gcry_mpi_t y,
gcry_mpi_t z);
gcry_mpi_t _gcry_mpi_ec_get_mpi (const char *name, gcry_ctx_t ctx, int copy);
gcry_mpi_point_t _gcry_mpi_ec_get_point (const char *name,
gcry_ctx_t ctx, int copy);
int _gcry_mpi_ec_get_affine (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_point_t point,
mpi_ec_t ctx);
void _gcry_mpi_ec_point_resize (gcry_mpi_point_t p, mpi_ec_t ctx);
void _gcry_mpi_ec_dup (gcry_mpi_point_t w, gcry_mpi_point_t u, gcry_ctx_t ctx);
void _gcry_mpi_ec_add (gcry_mpi_point_t w,
gcry_mpi_point_t u, gcry_mpi_point_t v, mpi_ec_t ctx);
void _gcry_mpi_ec_sub (gcry_mpi_point_t w,
gcry_mpi_point_t u, gcry_mpi_point_t v, mpi_ec_t ctx);
void _gcry_mpi_ec_mul (gcry_mpi_point_t w, gcry_mpi_t n, gcry_mpi_point_t u,
mpi_ec_t ctx);
int _gcry_mpi_ec_curve_point (gcry_mpi_point_t w, mpi_ec_t ctx);
unsigned int _gcry_mpi_get_nbits (gcry_mpi_t a);
int _gcry_mpi_test_bit (gcry_mpi_t a, unsigned int n);
void _gcry_mpi_set_bit (gcry_mpi_t a, unsigned int n);
void _gcry_mpi_clear_bit (gcry_mpi_t a, unsigned int n);
void _gcry_mpi_set_highbit (gcry_mpi_t a, unsigned int n);
void _gcry_mpi_clear_highbit (gcry_mpi_t a, unsigned int n);
void _gcry_mpi_rshift (gcry_mpi_t x, gcry_mpi_t a, unsigned int n);
void _gcry_mpi_lshift (gcry_mpi_t x, gcry_mpi_t a, unsigned int n);
gcry_mpi_t _gcry_mpi_set_opaque (gcry_mpi_t a, void *p, unsigned int nbits);
gcry_mpi_t _gcry_mpi_set_opaque_copy (gcry_mpi_t a,
const void *p, unsigned int nbits);
void *_gcry_mpi_get_opaque (gcry_mpi_t a, unsigned int *nbits);
void _gcry_mpi_set_flag (gcry_mpi_t a, enum gcry_mpi_flag flag);
void _gcry_mpi_clear_flag (gcry_mpi_t a, enum gcry_mpi_flag flag);
int _gcry_mpi_get_flag (gcry_mpi_t a, enum gcry_mpi_flag flag);
/* Private function - do not use. */
/* gcry_mpi_t _gcry_mpi_get_const (int no); */
/* We need our internal versions of the macros. */
#ifndef GCRYPT_NO_MPI_MACROS
# error GCRYPT_NO_MPI_MACROS is not defined
#endif
#define mpi_new(n) _gcry_mpi_new ((n))
#define mpi_secure_new( n ) _gcry_mpi_snew ((n))
#define mpi_snew(n) _gcry_mpi_snew ((n))
#define mpi_release(a) \
do \
{ \
_gcry_mpi_release ((a));\
(a) = NULL; \
} \
while (0)
#define mpi_snatch( w, u) _gcry_mpi_snatch( (w), (u) )
#define mpi_set( w, u) _gcry_mpi_set( (w), (u) )
#define mpi_set_ui( w, u) _gcry_mpi_set_ui( (w), (u) )
#define mpi_get_ui(w,u) _gcry_mpi_get_ui( (w), (u) )
#define mpi_swap(a,b) _gcry_mpi_swap ((a),(b))
#define mpi_abs( w ) _gcry_mpi_abs( (w) )
#define mpi_neg( w, u) _gcry_mpi_neg( (w), (u) )
#define mpi_cmp( u, v ) _gcry_mpi_cmp( (u), (v) )
#define mpi_cmpabs( u, v ) _gcry_mpi_cmpabs( (u), (v) )
#define mpi_cmp_ui( u, v ) _gcry_mpi_cmp_ui( (u), (v) )
#define mpi_is_neg( a ) _gcry_mpi_is_neg ((a))
#define mpi_add_ui(w,u,v) _gcry_mpi_add_ui((w),(u),(v))
#define mpi_add(w,u,v) _gcry_mpi_add ((w),(u),(v))
#define mpi_addm(w,u,v,m) _gcry_mpi_addm ((w),(u),(v),(m))
#define mpi_sub_ui(w,u,v) _gcry_mpi_sub_ui ((w),(u),(v))
#define mpi_sub(w,u,v) _gcry_mpi_sub ((w),(u),(v))
#define mpi_subm(w,u,v,m) _gcry_mpi_subm ((w),(u),(v),(m))
#define mpi_mul_ui(w,u,v) _gcry_mpi_mul_ui ((w),(u),(v))
#define mpi_mul_2exp(w,u,v) _gcry_mpi_mul_2exp ((w),(u),(v))
#define mpi_mul(w,u,v) _gcry_mpi_mul ((w),(u),(v))
#define mpi_mulm(w,u,v,m) _gcry_mpi_mulm ((w),(u),(v),(m))
#define mpi_powm(w,b,e,m) _gcry_mpi_powm ( (w), (b), (e), (m) )
#define mpi_tdiv(q,r,a,m) _gcry_mpi_div ( (q), (r), (a), (m), 0)
#define mpi_fdiv(q,r,a,m) _gcry_mpi_div ( (q), (r), (a), (m), -1)
#define mpi_mod(r,a,m) _gcry_mpi_mod ((r), (a), (m))
#define mpi_gcd(g,a,b) _gcry_mpi_gcd ( (g), (a), (b) )
#define mpi_invm(g,a,b) _gcry_mpi_invm ( (g), (a), (b) )
#define mpi_point_new(n) _gcry_mpi_point_new((n))
#define mpi_point_release(p) \
do \
{ \
_gcry_mpi_point_release ((p)); \
(p) = NULL; \
} \
while (0)
#define mpi_point_copy(p) _gcry_mpi_point_copy((p))
#define mpi_point_get(x,y,z,p) _gcry_mpi_point_get((x),(y),(z),(p))
#define mpi_point_snatch_get(x,y,z,p) _gcry_mpi_point_snatch_get((x),(y), \
(z),(p))
#define mpi_point_set(p,x,y,z) _gcry_mpi_point_set((p),(x),(y),(z))
#define mpi_point_snatch_set(p,x,y,z) _gcry_mpi_point_snatch_set((p),(x), \
(y),(z))
#define mpi_point_resize(p,ctx) _gcry_mpi_ec_point_resize (p, ctx)
#define mpi_get_nbits(a) _gcry_mpi_get_nbits ((a))
#define mpi_test_bit(a,b) _gcry_mpi_test_bit ((a),(b))
#define mpi_set_bit(a,b) _gcry_mpi_set_bit ((a),(b))
#define mpi_set_highbit(a,b) _gcry_mpi_set_highbit ((a),(b))
#define mpi_clear_bit(a,b) _gcry_mpi_clear_bit ((a),(b))
#define mpi_clear_highbit(a,b) _gcry_mpi_clear_highbit ((a),(b))
#define mpi_rshift(a,b,c) _gcry_mpi_rshift ((a),(b),(c))
#define mpi_lshift(a,b,c) _gcry_mpi_lshift ((a),(b),(c))
#define mpi_set_opaque(a,b,c) _gcry_mpi_set_opaque ((a), (b), (c))
#define mpi_get_opaque(a,b) _gcry_mpi_get_opaque ((a), (b))
#define mpi_set_flag(a,f) _gcry_mpi_set_flag ((a), (f))
#define mpi_set_flag(a,f) _gcry_mpi_set_flag ((a), (f))
#define mpi_clear_flag(a,f) _gcry_mpi_clear_flag ((a), (f))
#define mpi_get_flag(a,f) _gcry_mpi_get_flag ((a), (f))
#endif /*GCRY_GCRYPT_INT_H*/
diff --git a/src/global.c b/src/global.c
index a5a48cb5..74cf16d3 100644
--- a/src/global.c
+++ b/src/global.c
@@ -1,1433 +1,1436 @@
/* global.c - global control functions
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
* 2004, 2005, 2006, 2008, 2011,
* 2012 Free Software Foundation, Inc.
* Copyright (C) 2013, 2014, 2017 g10 Code GmbH
*
* This file is part of Libgcrypt.
*
* Libgcrypt 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.
*
* Libgcrypt 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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
#include <unistd.h>
#ifdef HAVE_SYSLOG
# include <syslog.h>
#endif /*HAVE_SYSLOG*/
#include "g10lib.h"
#include "gcrypt-testapi.h"
#include "cipher.h"
#include "stdmem.h" /* our own memory allocator */
#include "secmem.h" /* our own secmem allocator */
/****************
* flag bits: 0 : general cipher debug
* 1 : general MPI debug
*/
static unsigned int debug_flags;
/* gcry_control (GCRYCTL_SET_FIPS_MODE), sets this flag so that the
initialization code switched fips mode on. */
static int force_fips_mode;
/* Controlled by global_init(). */
int _gcry_global_any_init_done;
/*
* Functions called before and after blocking syscalls.
* Initialized by global_init and used via
* _gcry_pre_syscall and _gcry_post_syscall.
*/
static void (*pre_syscall_func)(void);
static void (*post_syscall_func)(void);
/* Memory management. */
static gcry_handler_alloc_t alloc_func;
static gcry_handler_alloc_t alloc_secure_func;
static gcry_handler_secure_check_t is_secure_func;
static gcry_handler_realloc_t realloc_func;
static gcry_handler_free_t free_func;
static gcry_handler_no_mem_t outofcore_handler;
static void *outofcore_handler_value;
static int no_secure_memory;
/* Prototypes. */
static gpg_err_code_t external_lock_test (int cmd);
/* This is our handmade constructor. It gets called by any function
likely to be called at startup. The suggested way for an
application to make sure that this has been called is by using
gcry_check_version. */
static void
global_init (void)
{
gcry_error_t err = 0;
if (_gcry_global_any_init_done)
return;
_gcry_global_any_init_done = 1;
/* Tell the random module that we have seen an init call. */
_gcry_set_preferred_rng_type (0);
/* Get the system call clamp functions. */
if (!pre_syscall_func)
gpgrt_get_syscall_clamp (&pre_syscall_func, &post_syscall_func);
/* Add a handler to be called after log_fatal and log_debug. */
_gcry_set_gpgrt_post_log_handler ();
/* See whether the system is in FIPS mode. This needs to come as
early as possible but after ATH has been initialized. */
_gcry_initialize_fips_mode (force_fips_mode);
/* Before we do any other initialization we need to test available
hardware features. */
_gcry_detect_hw_features ();
/* Initialize the modules - this is mainly allocating some memory and
creating mutexes. */
err = _gcry_cipher_init ();
if (err)
goto fail;
err = _gcry_md_init ();
if (err)
goto fail;
err = _gcry_mac_init ();
if (err)
goto fail;
err = _gcry_pk_init ();
if (err)
goto fail;
err = _gcry_primegen_init ();
if (err)
goto fail;
err = _gcry_secmem_module_init ();
if (err)
goto fail;
err = _gcry_mpi_init ();
if (err)
goto fail;
return;
fail:
BUG ();
}
#ifdef ENABLE_HMAC_BINARY_CHECK
# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7 )
# define GCC_ATTR_CONSTRUCTOR __attribute__ ((__constructor__))
static void GCC_ATTR_CONSTRUCTOR
_gcry_global_constructor (void)
{
force_fips_mode = _gcry_fips_to_activate ();
if (force_fips_mode)
{
no_secure_memory = 1;
global_init ();
_gcry_fips_run_selftests (0);
_gcry_random_close_fds ();
no_secure_memory = 0;
}
}
# endif
#endif /* ENABLE_HMAC_BINARY_CHECK */
/* This function is called by the macro fips_is_operational and makes
sure that the minimal initialization has been done. This is far
from a perfect solution and hides problems with an improper
initialization but at least in single-threaded mode it should work
reliable.
The reason we need this is that a lot of applications don't use
Libgcrypt properly by not running any initialization code at all.
They just call a Libgcrypt function and that is all what they want.
Now with the FIPS mode, that has the side effect of entering FIPS
mode (for security reasons, FIPS mode is the default if no
initialization has been done) and bailing out immediately because
the FSM is in the wrong state. If we always run the init code,
Libgcrypt can test for FIPS mode and at least if not in FIPS mode,
it will behave as before. Note that this on-the-fly initialization
is only done for the cryptographic functions subject to FIPS mode
and thus not all API calls will do such an initialization. */
int
_gcry_global_is_operational (void)
{
if (!_gcry_global_any_init_done)
{
#ifdef HAVE_SYSLOG
syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
"missing initialization - please fix the application");
#endif /*HAVE_SYSLOG*/
global_init ();
}
return _gcry_fips_is_operational ();
}
/* Version number parsing. */
/* This function parses the first portion of the version number S and
stores it in *NUMBER. On success, this function returns a pointer
into S starting with the first character, which is not part of the
initial number portion; on failure, NULL is returned. */
static const char*
parse_version_number( const char *s, int *number )
{
int val = 0;
if( *s == '0' && isdigit(s[1]) )
return NULL; /* leading zeros are not allowed */
for ( ; isdigit(*s); s++ ) {
val *= 10;
val += *s - '0';
}
*number = val;
return val < 0? NULL : s;
}
/* This function breaks up the complete string-representation of the
version number S, which is of the following struture: <major
number>.<minor number>.<micro number><patch level>. The major,
minor and micro number components will be stored in *MAJOR, *MINOR
and *MICRO.
On success, the last component, the patch level, will be returned;
in failure, NULL will be returned. */
static const char *
parse_version_string( const char *s, int *major, int *minor, int *micro )
{
s = parse_version_number( s, major );
if( !s || *s != '.' )
return NULL;
s++;
s = parse_version_number( s, minor );
if( !s || *s != '.' )
return NULL;
s++;
s = parse_version_number( s, micro );
if( !s )
return NULL;
return s; /* patchlevel */
}
/* If REQ_VERSION is non-NULL, check that the version of the library
is at minimum the requested one. Returns the string representation
of the library version if the condition is satisfied; return NULL
if the requested version is newer than that of the library.
If a NULL is passed to this function, no check is done, but the
string representation of the library is simply returned. */
const char *
_gcry_check_version (const char *req_version)
{
const char *ver = VERSION;
int my_major, my_minor, my_micro;
int rq_major, rq_minor, rq_micro;
const char *my_plvl;
if (req_version && req_version[0] == 1 && req_version[1] == 1)
return _gcry_compat_identification ();
/* Initialize library. */
global_init ();
if ( !req_version )
/* Caller wants our version number. */
return ver;
/* Parse own version number. */
my_plvl = parse_version_string( ver, &my_major, &my_minor, &my_micro );
if ( !my_plvl )
/* very strange our own version is bogus. Shouldn't we use
assert() here and bail out in case this happens? -mo. */
return NULL;
/* Parse requested version number. */
if (!parse_version_string (req_version, &rq_major, &rq_minor, &rq_micro))
return NULL; /* req version string is invalid, this can happen. */
/* Compare version numbers. */
if ( my_major > rq_major
|| (my_major == rq_major && my_minor > rq_minor)
|| (my_major == rq_major && my_minor == rq_minor
&& my_micro > rq_micro)
|| (my_major == rq_major && my_minor == rq_minor
&& my_micro == rq_micro))
{
return ver;
}
return NULL;
}
static void
print_config (const char *what, gpgrt_stream_t fp)
{
int i;
const char *s;
if (!what || !strcmp (what, "version"))
{
gpgrt_fprintf (fp, "version:%s:%x:%s:%x:\n",
VERSION, GCRYPT_VERSION_NUMBER,
GPGRT_VERSION, GPGRT_VERSION_NUMBER);
}
if (!what || !strcmp (what, "cc"))
{
gpgrt_fprintf (fp, "cc:%d:%s:\n",
GPGRT_GCC_VERSION,
#ifdef __clang__
"clang:" __VERSION__
#elif __GNUC__
"gcc:" __VERSION__
#else
":"
#endif
);
}
if (!what || !strcmp (what, "ciphers"))
gpgrt_fprintf (fp, "ciphers:%s:\n", LIBGCRYPT_CIPHERS);
if (!what || !strcmp (what, "pubkeys"))
gpgrt_fprintf (fp, "pubkeys:%s:\n", LIBGCRYPT_PUBKEY_CIPHERS);
if (!what || !strcmp (what, "digests"))
gpgrt_fprintf (fp, "digests:%s:\n", LIBGCRYPT_DIGESTS);
if (!what || !strcmp (what, "rnd-mod"))
{
gpgrt_fprintf (fp, "rnd-mod:"
#if USE_RNDEGD
"egd:"
#endif
#if USE_RNDGETENTROPY
"getentropy:"
#endif
#if USE_RNDOLDLINUX
"oldlinux:"
#endif
#if USE_RNDUNIX
"unix:"
#endif
#if USE_RNDW32
"w32:"
#endif
"\n");
}
if (!what || !strcmp (what, "cpu-arch"))
{
gpgrt_fprintf (fp, "cpu-arch:"
#if defined(HAVE_CPU_ARCH_X86)
"x86"
# ifdef __x86_64__
":amd64"
# else
":i386"
# endif
#elif defined(HAVE_CPU_ARCH_ALPHA)
"alpha"
#elif defined(HAVE_CPU_ARCH_SPARC)
"sparc"
#elif defined(HAVE_CPU_ARCH_MIPS)
"mips"
#elif defined(HAVE_CPU_ARCH_M68K)
"m68k"
#elif defined(HAVE_CPU_ARCH_PPC)
"ppc"
#elif defined(HAVE_CPU_ARCH_ARM)
"arm"
#endif
":\n");
}
if (!what || !strcmp (what, "mpi-asm"))
gpgrt_fprintf (fp, "mpi-asm:%s:\n", _gcry_mpi_get_hw_config ());
+ if (!what || !strcmp (what, "mpi-pow"))
+ gpgrt_fprintf (fp, "mpi-pow:%s\n", _gcry_mpi_get_powm_config ());
+
if (!what || !strcmp (what, "hwflist"))
{
unsigned int hwfeatures, afeature;
hwfeatures = _gcry_get_hw_features ();
gpgrt_fprintf (fp, "hwflist:");
for (i=0; (s = _gcry_enum_hw_features (i, &afeature)); i++)
if ((hwfeatures & afeature))
gpgrt_fprintf (fp, "%s:", s);
gpgrt_fprintf (fp, "\n");
}
if (!what || !strcmp (what, "fips-mode"))
{
/* We use y/n instead of 1/0 for the stupid reason that
* Emacsen's compile error parser would accidentally flag that
* line when printed during "make check" as an error. The
* second field is obsolete and thus empty (used to be used for
* a so-called enforced-fips-mode). The third field has an
* option static string describing the module versions; this is
* an optional configure option. */
gpgrt_fprintf (fp, "fips-mode:%c::%s:\n",
fips_mode ()? 'y':'n',
#ifdef FIPS_MODULE_VERSION
fips_mode () ? FIPS_MODULE_VERSION : ""
#else
""
#endif /* FIPS_MODULE_VERSION */
);
}
if (!what || !strcmp (what, "rng-type"))
{
/* The currently used RNG type. */
unsigned int jver;
int active;
i = _gcry_get_rng_type (0);
switch (i)
{
case GCRY_RNG_TYPE_STANDARD: s = "standard"; break;
case GCRY_RNG_TYPE_FIPS: s = "fips"; break;
case GCRY_RNG_TYPE_SYSTEM: s = "system"; break;
default: BUG ();
}
jver = _gcry_rndjent_get_version (&active);
gpgrt_fprintf (fp, "rng-type:%s:%d:%u:%d:\n", s, i, jver, active);
}
if (!what || !strcmp (what, "compliance"))
{
/* Right now we have no certification for 1.9 so we return an
* empty string. As soon as this version has been approved for
* VS-Nfd we will put the string "de-vs" into the second
* field. If further specifications are required they are added
* as parameters to that field. Other certifications will go
* into field 3 and so on.
* field 1: keyword "compliance"
* field 2: German VS-Nfd is marked with "de-vs"
* field 3: reserved for FIPS.
*/
gpgrt_fprintf (fp, "compliance:%s::\n", "");
}
}
/* With a MODE of 0 return a malloced string with configured features.
* In that case a WHAT of NULL returns everything in the same way
* GCRYCTL_PRINT_CONFIG would do. With a specific WHAT string only
* the requested feature is returned (w/o the trailing LF. On error
* NULL is returned. */
char *
_gcry_get_config (int mode, const char *what)
{
gpgrt_stream_t fp;
int save_errno;
void *data;
char *p;
if (mode)
{
gpg_err_set_errno (EINVAL);
return NULL;
}
fp = gpgrt_fopenmem (0, "w+b,samethread");
if (!fp)
return NULL;
print_config (what, fp);
if (!what)
{
/* Null-terminate bulk output. */
gpgrt_fwrite ("\0", 1, 1, fp);
}
if (gpgrt_ferror (fp))
{
save_errno = errno;
gpgrt_fclose (fp);
gpg_err_set_errno (save_errno);
return NULL;
}
gpgrt_rewind (fp);
if (gpgrt_fclose_snatch (fp, &data, NULL))
{
save_errno = errno;
gpgrt_fclose (fp);
gpg_err_set_errno (save_errno);
return NULL;
}
if (!data)
{
/* Nothing was printed (unknown value for WHAT). This is okay,
* so clear ERRNO to indicate this. */
gpg_err_set_errno (0);
return NULL;
}
/* Strip trailing LF. */
if (what && (p = strchr (data, '\n')))
*p = 0;
return data;
}
#if _GCRY_GCC_VERSION >= 40200
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wswitch"
#endif
/* Command dispatcher function, acting as general control
function. */
gcry_err_code_t
_gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
{
static int init_finished = 0;
gcry_err_code_t rc = 0;
switch (cmd)
{
case GCRYCTL_ENABLE_M_GUARD:
rc = GPG_ERR_NOT_SUPPORTED;
break;
case GCRYCTL_ENABLE_QUICK_RANDOM:
_gcry_set_preferred_rng_type (0);
_gcry_enable_quick_random_gen ();
break;
case GCRYCTL_FAKED_RANDOM_P:
/* Return an error if the RNG is faked one (e.g. enabled by
ENABLE_QUICK_RANDOM. */
if (_gcry_random_is_faked ())
rc = GPG_ERR_GENERAL; /* Use as TRUE value. */
break;
case GCRYCTL_DUMP_RANDOM_STATS:
_gcry_random_dump_stats ();
break;
case GCRYCTL_DUMP_MEMORY_STATS:
/*m_print_stats("[fixme: prefix]");*/
break;
case GCRYCTL_DUMP_SECMEM_STATS:
_gcry_secmem_dump_stats (0);
break;
case GCRYCTL_DROP_PRIVS:
global_init ();
_gcry_secmem_init (0);
break;
case GCRYCTL_DISABLE_SECMEM:
global_init ();
/* When FIPS enabled, no effect at all. */
if (!fips_mode ())
no_secure_memory = 1;
break;
case GCRYCTL_INIT_SECMEM:
global_init ();
_gcry_secmem_init (va_arg (arg_ptr, unsigned int));
if ((_gcry_secmem_get_flags () & GCRY_SECMEM_FLAG_NOT_LOCKED))
rc = GPG_ERR_GENERAL;
break;
case GCRYCTL_TERM_SECMEM:
global_init ();
_gcry_secmem_term ();
break;
case GCRYCTL_DISABLE_SECMEM_WARN:
_gcry_set_preferred_rng_type (0);
_gcry_secmem_set_flags ((_gcry_secmem_get_flags ()
| GCRY_SECMEM_FLAG_NO_WARNING));
break;
case GCRYCTL_SUSPEND_SECMEM_WARN:
_gcry_set_preferred_rng_type (0);
_gcry_secmem_set_flags ((_gcry_secmem_get_flags ()
| GCRY_SECMEM_FLAG_SUSPEND_WARNING));
break;
case GCRYCTL_RESUME_SECMEM_WARN:
_gcry_set_preferred_rng_type (0);
_gcry_secmem_set_flags ((_gcry_secmem_get_flags ()
& ~GCRY_SECMEM_FLAG_SUSPEND_WARNING));
break;
case GCRYCTL_AUTO_EXPAND_SECMEM:
_gcry_secmem_set_auto_expand (va_arg (arg_ptr, unsigned int));
break;
case GCRYCTL_USE_SECURE_RNDPOOL:
global_init ();
_gcry_secure_random_alloc (); /* Put random number into secure memory. */
break;
case GCRYCTL_SET_RANDOM_SEED_FILE:
_gcry_set_preferred_rng_type (0);
_gcry_set_random_seed_file (va_arg (arg_ptr, const char *));
break;
case GCRYCTL_UPDATE_RANDOM_SEED_FILE:
_gcry_set_preferred_rng_type (0);
if ( fips_is_operational () )
_gcry_update_random_seed_file ();
break;
case GCRYCTL_SET_VERBOSITY:
_gcry_set_preferred_rng_type (0);
_gcry_set_log_verbosity (va_arg (arg_ptr, int));
break;
case GCRYCTL_SET_DEBUG_FLAGS:
debug_flags |= va_arg (arg_ptr, unsigned int);
break;
case GCRYCTL_CLEAR_DEBUG_FLAGS:
debug_flags &= ~va_arg (arg_ptr, unsigned int);
break;
case GCRYCTL_DISABLE_INTERNAL_LOCKING:
/* Not used anymore. */
global_init ();
break;
case GCRYCTL_ANY_INITIALIZATION_P:
if (_gcry_global_any_init_done)
rc = GPG_ERR_GENERAL;
break;
case GCRYCTL_INITIALIZATION_FINISHED_P:
if (init_finished)
rc = GPG_ERR_GENERAL; /* Yes. */
break;
case GCRYCTL_INITIALIZATION_FINISHED:
/* This is a hook which should be used by an application after
all initialization has been done and right before any threads
are started. It is not really needed but the only way to be
really sure that all initialization for thread-safety has
been done. */
if (! init_finished)
{
global_init ();
/* Do only a basic random initialization, i.e. init the
mutexes. */
_gcry_random_initialize (0);
init_finished = 1;
/* Force us into operational state if in FIPS mode. */
(void)fips_is_operational ();
}
break;
case GCRYCTL_SET_THREAD_CBS:
/* This is now a dummy call. We used to install our own thread
library here. */
_gcry_set_preferred_rng_type (0);
global_init ();
break;
case GCRYCTL_FAST_POLL:
_gcry_set_preferred_rng_type (0);
/* We need to do make sure that the random pool is really
initialized so that the poll function is not a NOP. */
_gcry_random_initialize (1);
if ( fips_is_operational () )
_gcry_fast_random_poll ();
break;
case GCRYCTL_SET_RNDEGD_SOCKET:
#if USE_RNDEGD
_gcry_set_preferred_rng_type (0);
rc = _gcry_rndegd_set_socket_name (va_arg (arg_ptr, const char *));
#else
rc = GPG_ERR_NOT_SUPPORTED;
#endif
break;
case GCRYCTL_SET_RANDOM_DAEMON_SOCKET:
rc = GPG_ERR_NOT_SUPPORTED;
break;
case GCRYCTL_USE_RANDOM_DAEMON:
rc = GPG_ERR_NOT_SUPPORTED;
break;
case GCRYCTL_CLOSE_RANDOM_DEVICE:
_gcry_random_close_fds ();
break;
/* This command dumps information pertaining to the
configuration of libgcrypt to the given stream. It may be
used before the initialization has been finished but not
before a gcry_version_check. See also gcry_get_config. */
case GCRYCTL_PRINT_CONFIG:
{
FILE *fp = va_arg (arg_ptr, FILE *);
char *tmpstr;
_gcry_set_preferred_rng_type (0);
tmpstr = _gcry_get_config (0, NULL);
if (tmpstr)
{
if (fp)
fputs (tmpstr, fp);
else
log_info ("%s", tmpstr);
xfree (tmpstr);
}
}
break;
case GCRYCTL_OPERATIONAL_P:
/* Returns true if the library is in an operational state. This
is always true for non-fips mode. */
_gcry_set_preferred_rng_type (0);
if (_gcry_fips_test_operational ())
rc = GPG_ERR_GENERAL; /* Used as TRUE value */
break;
case GCRYCTL_FIPS_MODE_P:
if (fips_mode ())
rc = GPG_ERR_GENERAL; /* Used as TRUE value */
break;
case GCRYCTL_FORCE_FIPS_MODE:
/* Performing this command puts the library into fips mode. If
the library has already been initialized into fips mode, a
selftest is triggered. It is not possible to put the libraty
into fips mode after having passed the initialization. */
_gcry_set_preferred_rng_type (0);
if (!_gcry_global_any_init_done)
{
/* Not yet initialized at all. Set a flag so that we are put
into fips mode during initialization. */
force_fips_mode = 1;
}
else
{
/* Already initialized. If we are already operational we
run a selftest. If not we use the is_operational call to
force us into operational state if possible. */
if (_gcry_fips_test_error_or_operational ())
_gcry_fips_run_selftests (1);
if (_gcry_fips_is_operational ())
rc = GPG_ERR_GENERAL; /* Used as TRUE value */
}
break;
case GCRYCTL_NO_FIPS_MODE:
/* Performing this command puts the library into non-fips mode,
even if system has fips setting. It is not possible to put
the libraty into non-fips mode after having passed the
initialization. */
_gcry_set_preferred_rng_type (0);
if (!_gcry_global_any_init_done)
{
/* Not yet initialized at all. Set a flag so that we are put
into non-fips mode during initialization. */
force_fips_mode = 0;
}
else if (!init_finished)
{
/* Already initialized. */
_gcry_no_fips_mode_required = 1;
}
else
rc = GPG_ERR_GENERAL;
break;
case GCRYCTL_SELFTEST:
/* Run a selftest. This works in fips mode as well as in
standard mode. In contrast to the power-up tests, we use an
extended version of the selftests. Returns 0 on success or an
error code. */
global_init ();
rc = _gcry_fips_run_selftests (1);
break;
case GCRYCTL_FIPS_SERVICE_INDICATOR:
rc = _gcry_fips_indicator ();
break;
case GCRYCTL_FIPS_REJECT_NON_FIPS:
{
unsigned int flags = va_arg (arg_ptr, unsigned int);
_gcry_thread_context_set_reject (flags);
}
break;
case GCRYCTL_FIPS_SERVICE_INDICATOR_CIPHER:
/* Get FIPS Service Indicator for a given symmetric algorithm and
* optional mode. Returns GPG_ERR_NO_ERROR if algorithm is allowed or
* GPG_ERR_NOT_SUPPORTED otherwise */
rc = _gcry_fips_indicator_cipher (arg_ptr);
break;
case GCRYCTL_FIPS_SERVICE_INDICATOR_MAC:
/* Get FIPS Service Indicator for a given message authentication code.
* Returns GPG_ERR_NO_ERROR if algorithm is allowed or
* GPG_ERR_NOT_SUPPORTED otherwise */
rc = _gcry_fips_indicator_mac (arg_ptr);
break;
case GCRYCTL_FIPS_SERVICE_INDICATOR_MD:
/* Get FIPS Service Indicator for a given message digest. Returns
* GPG_ERR_NO_ERROR if algorithm is allowed or GPG_ERR_NOT_SUPPORTED
* otherwise */
rc = _gcry_fips_indicator_md (arg_ptr);
break;
case GCRYCTL_FIPS_SERVICE_INDICATOR_KDF:
/* Get FIPS Service Indicator for a given KDF. Returns GPG_ERR_NO_ERROR
* if algorithm is allowed or GPG_ERR_NOT_SUPPORTED otherwise */
rc = _gcry_fips_indicator_kdf (arg_ptr);
break;
case GCRYCTL_FIPS_SERVICE_INDICATOR_FUNCTION:
/* Get FIPS Service Indicator for a given function from the API.
* Returns GPG_ERR_NO_ERROR if the function is allowed or
* GPG_ERR_NOT_SUPPORTED otherwise */
rc = _gcry_fips_indicator_function (arg_ptr);
break;
case GCRYCTL_FIPS_SERVICE_INDICATOR_PK_FLAGS:
/* Get FIPS Service Indicator for a public key operation flags.
* Returns GPG_ERR_NO_ERROR if the flag is allowed to be used or
* GPG_ERR_NOT_SUPPORTED otherwise */
rc = _gcry_fips_indicator_pk_flags (arg_ptr);
break;
case PRIV_CTL_INIT_EXTRNG_TEST: /* Init external random test. */
rc = GPG_ERR_NOT_SUPPORTED;
break;
case PRIV_CTL_RUN_EXTRNG_TEST: /* Run external DRBG test. */
{
struct gcry_drbg_test_vector *test =
va_arg (arg_ptr, struct gcry_drbg_test_vector *);
unsigned char *buf = va_arg (arg_ptr, unsigned char *);
if (buf)
rc = _gcry_rngdrbg_cavs_test (test, buf);
else
rc = _gcry_rngdrbg_healthcheck_one (test);
}
break;
case PRIV_CTL_DEINIT_EXTRNG_TEST: /* Deinit external random test. */
rc = GPG_ERR_NOT_SUPPORTED;
break;
case PRIV_CTL_EXTERNAL_LOCK_TEST: /* Run external lock test */
rc = external_lock_test (va_arg (arg_ptr, int));
break;
case PRIV_CTL_DUMP_SECMEM_STATS:
_gcry_secmem_dump_stats (1);
break;
case GCRYCTL_DISABLE_HWF:
{
const char *name = va_arg (arg_ptr, const char *);
rc = _gcry_disable_hw_feature (name);
}
break;
case GCRYCTL_SET_ENFORCED_FIPS_FLAG:
/* Obsolete - ignore */
break;
case GCRYCTL_SET_PREFERRED_RNG_TYPE:
/* This may be called before gcry_check_version. */
{
int i = va_arg (arg_ptr, int);
/* Note that we may not pass 0 to _gcry_set_preferred_rng_type. */
if (i > 0)
_gcry_set_preferred_rng_type (i);
}
break;
case GCRYCTL_GET_CURRENT_RNG_TYPE:
{
int *ip = va_arg (arg_ptr, int*);
if (ip)
*ip = _gcry_get_rng_type (!_gcry_global_any_init_done);
}
break;
case GCRYCTL_DISABLE_LOCKED_SECMEM:
_gcry_set_preferred_rng_type (0);
_gcry_secmem_set_flags ((_gcry_secmem_get_flags ()
| GCRY_SECMEM_FLAG_NO_MLOCK));
break;
case GCRYCTL_DISABLE_PRIV_DROP:
_gcry_set_preferred_rng_type (0);
_gcry_secmem_set_flags ((_gcry_secmem_get_flags ()
| GCRY_SECMEM_FLAG_NO_PRIV_DROP));
break;
case GCRYCTL_INACTIVATE_FIPS_FLAG:
case GCRYCTL_REACTIVATE_FIPS_FLAG:
rc = GPG_ERR_NOT_IMPLEMENTED;
break;
case GCRYCTL_DRBG_REINIT:
{
const char *flagstr = va_arg (arg_ptr, const char *);
gcry_buffer_t *pers = va_arg (arg_ptr, gcry_buffer_t *);
int npers = va_arg (arg_ptr, int);
if (va_arg (arg_ptr, void *) || npers < 0)
rc = GPG_ERR_INV_ARG;
else if (_gcry_get_rng_type (!_gcry_global_any_init_done)
!= GCRY_RNG_TYPE_FIPS)
rc = GPG_ERR_NOT_SUPPORTED;
else
rc = _gcry_rngdrbg_reinit (flagstr, pers, npers);
}
break;
case GCRYCTL_REINIT_SYSCALL_CLAMP:
if (!pre_syscall_func)
gpgrt_get_syscall_clamp (&pre_syscall_func, &post_syscall_func);
break;
default:
_gcry_set_preferred_rng_type (0);
rc = GPG_ERR_INV_OP;
}
return rc;
}
#if _GCRY_GCC_VERSION >= 40200
# pragma GCC diagnostic pop
#endif
/* Set custom allocation handlers. This is in general not useful
* because the libgcrypt allocation functions are guaranteed to
* provide proper allocation handlers which zeroize memory if needed.
* NOTE: All 5 functions should be set. */
void
_gcry_set_allocation_handler (gcry_handler_alloc_t new_alloc_func,
gcry_handler_alloc_t new_alloc_secure_func,
gcry_handler_secure_check_t new_is_secure_func,
gcry_handler_realloc_t new_realloc_func,
gcry_handler_free_t new_free_func)
{
global_init ();
if (fips_mode ())
{
/* In FIPS mode, we can not use custom allocation handlers because
* fips requires explicit zeroization and we can not guarantee that
* with custom free functions (and we can not do it transparently as
* in free we do not know the zize). */
return;
}
alloc_func = new_alloc_func;
alloc_secure_func = new_alloc_secure_func;
is_secure_func = new_is_secure_func;
realloc_func = new_realloc_func;
free_func = new_free_func;
}
/****************
* Set an optional handler which is called in case the xmalloc functions
* ran out of memory. This handler may do one of these things:
* o free some memory and return true, so that the xmalloc function
* tries again.
* o Do whatever it like and return false, so that the xmalloc functions
* use the default fatal error handler.
* o Terminate the program and don't return.
*
* The handler function is called with 3 arguments: The opaque value set with
* this function, the requested memory size, and a flag with these bits
* currently defined:
* bit 0 set = secure memory has been requested.
*/
void
_gcry_set_outofcore_handler (int (*f)(void*, size_t, unsigned int), void *value)
{
global_init ();
if (fips_mode ())
return;
outofcore_handler = f;
outofcore_handler_value = value;
}
static gcry_err_code_t
do_malloc (size_t n, unsigned int flags, void **mem)
{
gcry_err_code_t err = 0;
void *m;
if ((flags & GCRY_ALLOC_FLAG_SECURE) && !no_secure_memory)
{
if (alloc_secure_func)
m = (*alloc_secure_func) (n);
else
m = _gcry_private_malloc_secure (n, !!(flags & GCRY_ALLOC_FLAG_XHINT));
}
else
{
if (alloc_func)
m = (*alloc_func) (n);
else
m = _gcry_private_malloc (n);
}
if (!m)
{
/* Make sure that ERRNO has been set in case a user supplied
memory handler didn't it correctly. */
if (!errno)
gpg_err_set_errno (ENOMEM);
err = gpg_err_code_from_errno (errno);
}
else
*mem = m;
return err;
}
void *
_gcry_malloc (size_t n)
{
void *mem = NULL;
do_malloc (n, 0, &mem);
return mem;
}
static void *
_gcry_malloc_secure_core (size_t n, int xhint)
{
void *mem = NULL;
do_malloc (n, (GCRY_ALLOC_FLAG_SECURE | (xhint? GCRY_ALLOC_FLAG_XHINT:0)),
&mem);
return mem;
}
void *
_gcry_malloc_secure (size_t n)
{
return _gcry_malloc_secure_core (n, 0);
}
int
_gcry_is_secure (const void *a)
{
if (no_secure_memory)
return 0;
if (is_secure_func)
return is_secure_func (a) ;
return _gcry_private_is_secure (a);
}
static void *
_gcry_realloc_core (void *a, size_t n, int xhint)
{
void *p;
/* To avoid problems with non-standard realloc implementations and
our own secmem_realloc, we divert to malloc and free here. */
if (!a)
return _gcry_malloc (n);
if (!n)
{
xfree (a);
return NULL;
}
if (realloc_func)
p = realloc_func (a, n);
else
p = _gcry_private_realloc (a, n, xhint);
if (!p && !errno)
gpg_err_set_errno (ENOMEM);
return p;
}
void *
_gcry_realloc (void *a, size_t n)
{
return _gcry_realloc_core (a, n, 0);
}
void
_gcry_free (void *p)
{
int save_errno;
if (!p)
return;
/* In case ERRNO is set we better save it so that the free machinery
may not accidentally change ERRNO. We restore it only if it was
already set to comply with the usual C semantic for ERRNO. */
save_errno = errno;
if (free_func)
free_func (p);
else
_gcry_private_free (p);
if (save_errno && save_errno != errno)
gpg_err_set_errno (save_errno);
}
void *
_gcry_calloc (size_t n, size_t m)
{
size_t bytes;
void *p;
bytes = n * m; /* size_t is unsigned so the behavior on overflow is
defined. */
if (m && bytes / m != n)
{
gpg_err_set_errno (ENOMEM);
return NULL;
}
p = _gcry_malloc (bytes);
if (p)
memset (p, 0, bytes);
return p;
}
void *
_gcry_calloc_secure (size_t n, size_t m)
{
size_t bytes;
void *p;
bytes = n * m; /* size_t is unsigned so the behavior on overflow is
defined. */
if (m && bytes / m != n)
{
gpg_err_set_errno (ENOMEM);
return NULL;
}
p = _gcry_malloc_secure (bytes);
if (p)
memset (p, 0, bytes);
return p;
}
static char *
_gcry_strdup_core (const char *string, int xhint)
{
char *string_cp = NULL;
size_t string_n = 0;
string_n = strlen (string);
if (_gcry_is_secure (string))
string_cp = _gcry_malloc_secure_core (string_n + 1, xhint);
else
string_cp = _gcry_malloc (string_n + 1);
if (string_cp)
strcpy (string_cp, string);
return string_cp;
}
/* Create and return a copy of the null-terminated string STRING. If
* it is contained in secure memory, the copy will be contained in
* secure memory as well. In an out-of-memory condition, NULL is
* returned. */
char *
_gcry_strdup (const char *string)
{
return _gcry_strdup_core (string, 0);
}
void *
_gcry_xmalloc( size_t n )
{
void *p;
while ( !(p = _gcry_malloc( n )) )
{
if ( fips_mode ()
|| !outofcore_handler
|| !outofcore_handler (outofcore_handler_value, n, 0) )
{
_gcry_fatal_error (gpg_err_code_from_errno (errno), NULL);
}
}
return p;
}
void *
_gcry_xrealloc( void *a, size_t n )
{
void *p;
while (!(p = _gcry_realloc_core (a, n, 1)))
{
if ( fips_mode ()
|| !outofcore_handler
|| !outofcore_handler (outofcore_handler_value, n,
_gcry_is_secure(a)? 3:2))
{
_gcry_fatal_error (gpg_err_code_from_errno (errno), NULL );
}
}
return p;
}
void *
_gcry_xmalloc_secure( size_t n )
{
void *p;
while (!(p = _gcry_malloc_secure_core (n, 1)))
{
if ( fips_mode ()
|| !outofcore_handler
|| !outofcore_handler (outofcore_handler_value, n, 1) )
{
_gcry_fatal_error (gpg_err_code_from_errno (errno),
_("out of core in secure memory"));
}
}
return p;
}
void *
_gcry_xcalloc( size_t n, size_t m )
{
size_t nbytes;
void *p;
nbytes = n * m;
if (m && nbytes / m != n)
{
gpg_err_set_errno (ENOMEM);
_gcry_fatal_error(gpg_err_code_from_errno (errno), NULL );
}
p = _gcry_xmalloc ( nbytes );
memset ( p, 0, nbytes );
return p;
}
void *
_gcry_xcalloc_secure( size_t n, size_t m )
{
size_t nbytes;
void *p;
nbytes = n * m;
if (m && nbytes / m != n)
{
gpg_err_set_errno (ENOMEM);
_gcry_fatal_error(gpg_err_code_from_errno (errno), NULL );
}
p = _gcry_xmalloc_secure ( nbytes );
memset ( p, 0, nbytes );
return p;
}
char *
_gcry_xstrdup (const char *string)
{
char *p;
while ( !(p = _gcry_strdup_core (string, 1)) )
{
size_t n = strlen (string);
int is_sec = !!_gcry_is_secure (string);
if (fips_mode ()
|| !outofcore_handler
|| !outofcore_handler (outofcore_handler_value, n, is_sec) )
{
_gcry_fatal_error (gpg_err_code_from_errno (errno),
is_sec? _("out of core in secure memory"):NULL);
}
}
return p;
}
/* Used before blocking system calls. */
void
_gcry_pre_syscall (void)
{
if (pre_syscall_func)
pre_syscall_func ();
}
/* Used after blocking system calls. */
void
_gcry_post_syscall (void)
{
if (post_syscall_func)
post_syscall_func ();
}
int
_gcry_get_debug_flag (unsigned int mask)
{
if ( fips_mode () )
return 0;
return (debug_flags & mask);
}
/* It is often useful to get some feedback of long running operations.
This function may be used to register a handler for this.
The callback function CB is used as:
void cb (void *opaque, const char *what, int printchar,
int current, int total);
Where WHAT is a string identifying the the type of the progress
output, PRINTCHAR the character usually printed, CURRENT the amount
of progress currently done and TOTAL the expected amount of
progress. A value of 0 for TOTAL indicates that there is no
estimation available.
Defined values for WHAT:
"need_entropy" X 0 number-of-bytes-required
When running low on entropy
"primegen" '\n' 0 0
Prime generated
'!'
Need to refresh the prime pool
'<','>'
Number of bits adjusted
'^'
Looking for a generator
'.'
Fermat tests on 10 candidates failed
':'
Restart with a new random value
'+'
Rabin Miller test passed
"pk_elg" '+','-','.','\n' 0 0
Only used in debugging mode.
"pk_dsa"
Only used in debugging mode.
*/
void
_gcry_set_progress_handler (void (*cb)(void *,const char*,int, int, int),
void *cb_data)
{
#if USE_DSA
_gcry_register_pk_dsa_progress (cb, cb_data);
#endif
#if USE_ELGAMAL
_gcry_register_pk_elg_progress (cb, cb_data);
#endif
_gcry_register_primegen_progress (cb, cb_data);
_gcry_register_random_progress (cb, cb_data);
}
/* This is a helper for the regression test suite to test Libgcrypt's locks.
It works using a one test lock with CMD controlling what to do:
30111 - Allocate and init lock
30112 - Take lock
30113 - Release lock
30114 - Destroy lock.
This function is used by tests/t-lock.c - it is not part of the
public API!
*/
static gpg_err_code_t
external_lock_test (int cmd)
{
GPGRT_LOCK_DEFINE (testlock);
gpg_err_code_t rc = 0;
switch (cmd)
{
case 30111: /* Init Lock. */
rc = gpgrt_lock_init (&testlock);
break;
case 30112: /* Take Lock. */
rc = gpgrt_lock_lock (&testlock);
break;
case 30113: /* Release Lock. */
rc = gpgrt_lock_unlock (&testlock);
break;
case 30114: /* Destroy Lock. */
rc = gpgrt_lock_destroy (&testlock);
break;
default:
rc = GPG_ERR_INV_OP;
break;
}
return rc;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Feb 23, 7:16 PM (1 h, 37 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
9d/f6/68795164783314f8cc80dbe5d4cf
Attached To
rC libgcrypt
Event Timeline
Log In to Comment