Commit 4e2c5b28 authored by James Morris's avatar James Morris

Merge branch 'next-evm-digsig' of...

Merge branch 'next-evm-digsig' of git://git.kernel.org/pub/scm/linux/kernel/git/kasatkin/linux-digsig into next
parents 8077e8b0 15647eb3
Digital Signature Verification API
CONTENTS
1. Introduction
2. API
3. User-space utilities
1. Introduction
Digital signature verification API provides a method to verify digital signature.
Currently digital signatures are used by the IMA/EVM integrity protection subsystem.
Digital signature verification is implemented using cut-down kernel port of
GnuPG multi-precision integers (MPI) library. The kernel port provides
memory allocation errors handling, has been refactored according to kernel
coding style, and checkpatch.pl reported errors and warnings have been fixed.
Public key and signature consist of header and MPIs.
struct pubkey_hdr {
uint8_t version; /* key format version */
time_t timestamp; /* key made, always 0 for now */
uint8_t algo;
uint8_t nmpi;
char mpi[0];
} __packed;
struct signature_hdr {
uint8_t version; /* signature format version */
time_t timestamp; /* signature made */
uint8_t algo;
uint8_t hash;
uint8_t keyid[8];
uint8_t nmpi;
char mpi[0];
} __packed;
keyid equals to SHA1[12-19] over the total key content.
Signature header is used as an input to generate a signature.
Such approach insures that key or signature header could not be changed.
It protects timestamp from been changed and can be used for rollback
protection.
2. API
API currently includes only 1 function:
digsig_verify() - digital signature verification with public key
/**
* digsig_verify() - digital signature verification with public key
* @keyring: keyring to search key in
* @sig: digital signature
* @sigen: length of the signature
* @data: data
* @datalen: length of the data
* @return: 0 on success, -EINVAL otherwise
*
* Verifies data integrity against digital signature.
* Currently only RSA is supported.
* Normally hash of the content is used as a data for this function.
*
*/
int digsig_verify(struct key *keyring, const char *sig, int siglen,
const char *data, int datalen);
3. User-space utilities
The signing and key management utilities evm-utils provide functionality
to generate signatures, to load keys into the kernel keyring.
Keys can be in PEM or converted to the kernel format.
When the key is added to the kernel keyring, the keyid defines the name
of the key: 5D2B05FC633EE3E8 in the example bellow.
Here is example output of the keyctl utility.
$ keyctl show
Session Keyring
-3 --alswrv 0 0 keyring: _ses
603976250 --alswrv 0 -1 \_ keyring: _uid.0
817777377 --alswrv 0 0 \_ user: kmk
891974900 --alswrv 0 0 \_ encrypted: evm-key
170323636 --alswrv 0 0 \_ keyring: _module
548221616 --alswrv 0 0 \_ keyring: _ima
128198054 --alswrv 0 0 \_ keyring: _evm
$ keyctl list 128198054
1 key in keyring:
620789745: --alswrv 0 0 user: 5D2B05FC633EE3E8
Dmitry Kasatkin
06.10.2011
/*
* Copyright (C) 2011 Nokia Corporation
* Copyright (C) 2011 Intel Corporation
*
* Author:
* Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
* <dmitry.kasatkin@intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 of the License.
*
*/
#ifndef _DIGSIG_H
#define _DIGSIG_H
#include <linux/key.h>
enum pubkey_algo {
PUBKEY_ALGO_RSA,
PUBKEY_ALGO_MAX,
};
enum digest_algo {
DIGEST_ALGO_SHA1,
DIGEST_ALGO_SHA256,
DIGEST_ALGO_MAX
};
struct pubkey_hdr {
uint8_t version; /* key format version */
time_t timestamp; /* key made, always 0 for now */
uint8_t algo;
uint8_t nmpi;
char mpi[0];
} __packed;
struct signature_hdr {
uint8_t version; /* signature format version */
time_t timestamp; /* signature made */
uint8_t algo;
uint8_t hash;
uint8_t keyid[8];
uint8_t nmpi;
char mpi[0];
} __packed;
#if defined(CONFIG_DIGSIG) || defined(CONFIG_DIGSIG_MODULE)
int digsig_verify(struct key *keyring, const char *sig, int siglen,
const char *digest, int digestlen);
#else
static inline int digsig_verify(struct key *keyring, const char *sig,
int siglen, const char *digest, int digestlen)
{
return -EOPNOTSUPP;
}
#endif /* CONFIG_DIGSIG */
#endif /* _DIGSIG_H */
/* mpi.h - Multi Precision Integers
* Copyright (C) 1994, 1996, 1998, 1999,
* 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GNUPG.
*
* GNUPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GNUPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* 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.
* The GNU MP Library itself is published under the LGPL;
* however I decided to publish this code under the plain GPL.
*/
#ifndef G10_MPI_H
#define G10_MPI_H
#include <linux/types.h>
/* DSI defines */
#define SHA1_DIGEST_LENGTH 20
/*end of DSI defines */
#define BYTES_PER_MPI_LIMB (BITS_PER_LONG / 8)
#define BITS_PER_MPI_LIMB BITS_PER_LONG
typedef unsigned long int mpi_limb_t;
typedef signed long int mpi_limb_signed_t;
struct gcry_mpi {
int alloced; /* array size (# of allocated limbs) */
int nlimbs; /* number of valid limbs */
int nbits; /* the real number of valid bits (info only) */
int sign; /* indicates a negative number */
unsigned flags; /* bit 0: array must be allocated in secure memory space */
/* bit 1: not used */
/* bit 2: the limb is a pointer to some m_alloced data */
mpi_limb_t *d; /* array with the limbs */
};
typedef struct gcry_mpi *MPI;
#define MPI_NULL NULL
#define mpi_get_nlimbs(a) ((a)->nlimbs)
#define mpi_is_neg(a) ((a)->sign)
/*-- mpiutil.c --*/
MPI mpi_alloc(unsigned nlimbs);
MPI mpi_alloc_secure(unsigned nlimbs);
MPI mpi_alloc_like(MPI a);
void mpi_free(MPI a);
int mpi_resize(MPI a, unsigned nlimbs);
int mpi_copy(MPI *copy, const MPI a);
void mpi_clear(MPI a);
int mpi_set(MPI w, MPI u);
int mpi_set_ui(MPI w, ulong u);
MPI mpi_alloc_set_ui(unsigned long u);
void mpi_m_check(MPI a);
void mpi_swap(MPI a, MPI b);
/*-- mpicoder.c --*/
MPI do_encode_md(const void *sha_buffer, unsigned nbits);
MPI mpi_read_from_buffer(const void *buffer, unsigned *ret_nread);
int mpi_fromstr(MPI val, const char *str);
u32 mpi_get_keyid(MPI a, u32 *keyid);
void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign);
void *mpi_get_secure_buffer(MPI a, unsigned *nbytes, int *sign);
int mpi_set_buffer(MPI a, const void *buffer, unsigned nbytes, int sign);
#define log_mpidump g10_log_mpidump
/*-- mpi-add.c --*/
int mpi_add_ui(MPI w, MPI u, ulong v);
int mpi_add(MPI w, MPI u, MPI v);
int mpi_addm(MPI w, MPI u, MPI v, MPI m);
int mpi_sub_ui(MPI w, MPI u, ulong v);
int mpi_sub(MPI w, MPI u, MPI v);
int mpi_subm(MPI w, MPI u, MPI v, MPI m);
/*-- mpi-mul.c --*/
int mpi_mul_ui(MPI w, MPI u, ulong v);
int mpi_mul_2exp(MPI w, MPI u, ulong cnt);
int mpi_mul(MPI w, MPI u, MPI v);
int mpi_mulm(MPI w, MPI u, MPI v, MPI m);
/*-- mpi-div.c --*/
ulong mpi_fdiv_r_ui(MPI rem, MPI dividend, ulong divisor);
int mpi_fdiv_r(MPI rem, MPI dividend, MPI divisor);
int mpi_fdiv_q(MPI quot, MPI dividend, MPI divisor);
int mpi_fdiv_qr(MPI quot, MPI rem, MPI dividend, MPI divisor);
int mpi_tdiv_r(MPI rem, MPI num, MPI den);
int mpi_tdiv_qr(MPI quot, MPI rem, MPI num, MPI den);
int mpi_tdiv_q_2exp(MPI w, MPI u, unsigned count);
int mpi_divisible_ui(const MPI dividend, ulong divisor);
/*-- mpi-gcd.c --*/
int mpi_gcd(MPI g, const MPI a, const MPI b);
/*-- mpi-pow.c --*/
int mpi_pow(MPI w, MPI u, MPI v);
int mpi_powm(MPI res, MPI base, MPI exp, MPI mod);
/*-- mpi-mpow.c --*/
int mpi_mulpowm(MPI res, MPI *basearray, MPI *exparray, MPI mod);
/*-- mpi-cmp.c --*/
int mpi_cmp_ui(MPI u, ulong v);
int mpi_cmp(MPI u, MPI v);
/*-- mpi-scan.c --*/
int mpi_getbyte(MPI a, unsigned idx);
void mpi_putbyte(MPI a, unsigned idx, int value);
unsigned mpi_trailing_zeros(MPI a);
/*-- mpi-bit.c --*/
void mpi_normalize(MPI a);
unsigned mpi_get_nbits(MPI a);
int mpi_test_bit(MPI a, unsigned n);
int mpi_set_bit(MPI a, unsigned n);
int mpi_set_highbit(MPI a, unsigned n);
void mpi_clear_highbit(MPI a, unsigned n);
void mpi_clear_bit(MPI a, unsigned n);
int mpi_rshift(MPI x, MPI a, unsigned n);
/*-- mpi-inv.c --*/
int mpi_invm(MPI x, MPI u, MPI v);
#endif /*G10_MPI_H */
......@@ -276,4 +276,29 @@ config CORDIC
so its calculations are in fixed point. Modules can select this
when they require this function. Module will be called cordic.
config MPILIB
tristate "Multiprecision maths library"
help
Multiprecision maths library from GnuPG.
It is used to implement RSA digital signature verification,
which is used by IMA/EVM digital signature extension.
config MPILIB_EXTRA
bool "Multiprecision maths library - additional sources"
depends on MPILIB
help
Multiprecision maths library from GnuPG.
It is used to implement RSA digital signature verification,
which is used by IMA/EVM digital signature extension.
This code in unnecessary for RSA digital signature verification,
and can be compiled if needed.
config DIGSIG
tristate "In-kernel signature checker"
depends on CRYPTO
select MPILIB
help
Digital signature verification. Currently only RSA is supported.
Implementation is done using GnuPG MPI library
endmenu
......@@ -115,6 +115,9 @@ obj-$(CONFIG_CPU_RMAP) += cpu_rmap.o
obj-$(CONFIG_CORDIC) += cordic.o
obj-$(CONFIG_MPILIB) += mpi/
obj-$(CONFIG_DIGSIG) += digsig.o
hostprogs-y := gen_crc32table
clean-files := crc32table.h
......
/*
* Copyright (C) 2011 Nokia Corporation
* Copyright (C) 2011 Intel Corporation
*
* Author:
* Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
* <dmitry.kasatkin@intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 of the License.
*
* File: sign.c
* implements signature (RSA) verification
* pkcs decoding is based on LibTomCrypt code
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/err.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/key.h>
#include <linux/crypto.h>
#include <crypto/hash.h>
#include <crypto/sha.h>
#include <keys/user-type.h>
#include <linux/mpi.h>
#include <linux/digsig.h>
static struct crypto_shash *shash;
static int pkcs_1_v1_5_decode_emsa(const unsigned char *msg,
unsigned long msglen,
unsigned long modulus_bitlen,
unsigned char *out,
unsigned long *outlen,
int *is_valid)
{
unsigned long modulus_len, ps_len, i;
int result;
/* default to invalid packet */
*is_valid = 0;
modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
/* test message size */
if ((msglen > modulus_len) || (modulus_len < 11))
return -EINVAL;
/* separate encoded message */
if ((msg[0] != 0x00) || (msg[1] != (unsigned char)1)) {
result = -EINVAL;
goto bail;
}
for (i = 2; i < modulus_len - 1; i++)
if (msg[i] != 0xFF)
break;
/* separator check */
if (msg[i] != 0) {
/* There was no octet with hexadecimal value 0x00
to separate ps from m. */
result = -EINVAL;
goto bail;
}
ps_len = i - 2;
if (*outlen < (msglen - (2 + ps_len + 1))) {
*outlen = msglen - (2 + ps_len + 1);
result = -EOVERFLOW;
goto bail;
}
*outlen = (msglen - (2 + ps_len + 1));
memcpy(out, &msg[2 + ps_len + 1], *outlen);
/* valid packet */
*is_valid = 1;
result = 0;
bail:
return result;
}
/*
* RSA Signature verification with public key
*/
static int digsig_verify_rsa(struct key *key,
const char *sig, int siglen,
const char *h, int hlen)
{
int err = -EINVAL;
unsigned long len;
unsigned long mlen, mblen;
unsigned nret, l;
int valid, head, i;
unsigned char *out1 = NULL, *out2 = NULL;
MPI in = NULL, res = NULL, pkey[2];
uint8_t *p, *datap, *endp;
struct user_key_payload *ukp;
struct pubkey_hdr *pkh;
down_read(&key->sem);
ukp = key->payload.data;
pkh = (struct pubkey_hdr *)ukp->data;
if (pkh->version != 1)
goto err1;
if (pkh->algo != PUBKEY_ALGO_RSA)
goto err1;
if (pkh->nmpi != 2)
goto err1;
datap = pkh->mpi;
endp = datap + ukp->datalen;
for (i = 0; i < pkh->nmpi; i++) {
unsigned int remaining = endp - datap;
pkey[i] = mpi_read_from_buffer(datap, &remaining);
datap += remaining;
}
mblen = mpi_get_nbits(pkey[0]);
mlen = (mblen + 7)/8;
err = -ENOMEM;
out1 = kzalloc(mlen, GFP_KERNEL);
if (!out1)
goto err;
out2 = kzalloc(mlen, GFP_KERNEL);
if (!out2)
goto err;
nret = siglen;
in = mpi_read_from_buffer(sig, &nret);
if (!in)
goto err;
res = mpi_alloc(mpi_get_nlimbs(in) * 2);
if (!res)
goto err;
err = mpi_powm(res, in, pkey[1], pkey[0]);
if (err)
goto err;
if (mpi_get_nlimbs(res) * BYTES_PER_MPI_LIMB > mlen) {
err = -EINVAL;
goto err;
}
p = mpi_get_buffer(res, &l, NULL);
if (!p) {
err = -EINVAL;
goto err;
}
len = mlen;
head = len - l;
memset(out1, 0, head);
memcpy(out1 + head, p, l);
err = -EINVAL;
pkcs_1_v1_5_decode_emsa(out1, len, mblen, out2, &len, &valid);
if (valid && len == hlen)
err = memcmp(out2, h, hlen);
err:
mpi_free(in);
mpi_free(res);
kfree(out1);
kfree(out2);
mpi_free(pkey[0]);
mpi_free(pkey[1]);
err1:
up_read(&key->sem);
return err;
}
/**
* digsig_verify() - digital signature verification with public key
* @keyring: keyring to search key in
* @sig: digital signature
* @sigen: length of the signature
* @data: data
* @datalen: length of the data
* @return: 0 on success, -EINVAL otherwise
*
* Verifies data integrity against digital signature.
* Currently only RSA is supported.
* Normally hash of the content is used as a data for this function.
*
*/
int digsig_verify(struct key *keyring, const char *sig, int siglen,
const char *data, int datalen)
{
int err = -ENOMEM;
struct signature_hdr *sh = (struct signature_hdr *)sig;
struct shash_desc *desc = NULL;
unsigned char hash[SHA1_DIGEST_SIZE];
struct key *key;
char name[20];
if (siglen < sizeof(*sh) + 2)
return -EINVAL;
if (sh->algo != PUBKEY_ALGO_RSA)
return -ENOTSUPP;
sprintf(name, "%llX", __be64_to_cpup((uint64_t *)sh->keyid));
if (keyring) {
/* search in specific keyring */
key_ref_t kref;
kref = keyring_search(make_key_ref(keyring, 1UL),
&key_type_user, name);
if (IS_ERR(kref))
key = ERR_PTR(PTR_ERR(kref));
else
key = key_ref_to_ptr(kref);
} else {
key = request_key(&key_type_user, name, NULL);
}
if (IS_ERR(key)) {
pr_err("key not found, id: %s\n", name);
return PTR_ERR(key);
}
desc = kzalloc(sizeof(*desc) + crypto_shash_descsize(shash),
GFP_KERNEL);
if (!desc)
goto err;
desc->tfm = shash;
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
crypto_shash_init(desc);
crypto_shash_update(desc, data, datalen);
crypto_shash_update(desc, sig, sizeof(*sh));
crypto_shash_final(desc, hash);
kfree(desc);
/* pass signature mpis address */
err = digsig_verify_rsa(key, sig + sizeof(*sh), siglen - sizeof(*sh),
hash, sizeof(hash));
err:
key_put(key);
return err ? -EINVAL : 0;
}
EXPORT_SYMBOL_GPL(digsig_verify);
static int __init digsig_init(void)
{
shash = crypto_alloc_shash("sha1", 0, 0);
if (IS_ERR(shash)) {
pr_err("shash allocation failed\n");
return PTR_ERR(shash);
}
return 0;
}
static void __exit digsig_cleanup(void)
{
crypto_free_shash(shash);
}
module_init(digsig_init);
module_exit(digsig_cleanup);
MODULE_LICENSE("GPL");
#
# MPI multiprecision maths library (from gpg)
#
obj-$(CONFIG_MPILIB) = mpi.o
mpi-y = \
generic_mpih-lshift.o \
generic_mpih-mul1.o \
generic_mpih-mul2.o \
generic_mpih-mul3.o \
generic_mpih-rshift.o \
generic_mpih-sub1.o \
generic_mpih-add1.o \
mpicoder.o \
mpi-bit.o \
mpih-cmp.o \
mpih-div.o \
mpih-mul.o \
mpi-pow.o \
mpiutil.o
mpi-$(CONFIG_MPILIB_EXTRA) += \
mpi-add.o \
mpi-div.o \
mpi-cmp.o \
mpi-gcd.o \
mpi-inline.o \
mpi-inv.o \
mpi-mpow.o \
mpi-mul.o \
mpi-scan.o
/* This file defines some basic constants for the MPI machinery. We
* need to define the types on a per-CPU basis, so it is done with
* this file here. */
#define BYTES_PER_MPI_LIMB (SIZEOF_UNSIGNED_LONG)
/* mpihelp-add_1.c - MPI helper functions
* Copyright (C) 1994, 1996, 1997, 1998,
* 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* 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.
* The GNU MP Library itself is published under the LGPL;
* however I decided to publish this code under the plain GPL.
*/
#include "mpi-internal.h"
#include "longlong.h"
mpi_limb_t
mpihelp_add_n(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
mpi_ptr_t s2_ptr, mpi_size_t size)
{
mpi_limb_t x, y, cy;
mpi_size_t j;
/* The loop counter and index J goes from -SIZE to -1. This way
the loop becomes faster. */
j = -size;
/* Offset the base pointers to compensate for the negative indices. */
s1_ptr -= j;
s2_ptr -= j;
res_ptr -= j;
cy = 0;
do {
y = s2_ptr[j];
x = s1_ptr[j];
y += cy; /* add previous carry to one addend */
cy = y < cy; /* get out carry from that addition */
y += x; /* add other addend */
cy += y < x; /* get out carry from that add, combine */
res_ptr[j] = y;
} while (++j);
return cy;
}
/* mpihelp-lshift.c - MPI helper functions
* Copyright (C) 1994, 1996, 1998, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* 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.
* The GNU MP Library itself is published under the LGPL;
* however I decided to publish this code under the plain GPL.
*/
#include "mpi-internal.h"
/* Shift U (pointed to by UP and USIZE digits long) CNT bits to the left
* and store the USIZE least significant digits of the result at WP.
* Return the bits shifted out from the most significant digit.
*
* Argument constraints:
* 1. 0 < CNT < BITS_PER_MP_LIMB
* 2. If the result is to be written over the input, WP must be >= UP.
*/
mpi_limb_t
mpihelp_lshift(mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize, unsigned int cnt)
{
mpi_limb_t high_limb, low_limb;
unsigned sh_1, sh_2;
mpi_size_t i;
mpi_limb_t retval;
sh_1 = cnt;
wp += 1;
sh_2 = BITS_PER_MPI_LIMB - sh_1;
i = usize - 1;
low_limb = up[i];
retval = low_limb >> sh_2;
high_limb = low_limb;
while (--i >= 0) {
low_limb = up[i];
wp[i] = (high_limb << sh_1) | (low_limb >> sh_2);
high_limb = low_limb;
}
wp[i] = high_limb << sh_1;
return retval;
}
/* mpihelp-mul_1.c - MPI helper functions
* Copyright (C) 1994, 1996, 1997, 1998, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* 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.
* The GNU MP Library itself is published under the LGPL;
* however I decided to publish this code under the plain GPL.
*/
#include "mpi-internal.h"
#include "longlong.h"
mpi_limb_t
mpihelp_mul_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size,
mpi_limb_t s2_limb)
{
mpi_limb_t cy_limb;
mpi_size_t j;
mpi_limb_t prod_high, prod_low;
/* The loop counter and index J goes from -S1_SIZE to -1. This way
* the loop becomes faster. */
j = -s1_size;
/* Offset the base pointers to compensate for the negative indices. */
s1_ptr -= j;
res_ptr -= j;
cy_limb = 0;
do {
umul_ppmm(prod_high, prod_low, s1_ptr[j], s2_limb);
prod_low += cy_limb;
cy_limb = (prod_low < cy_limb ? 1 : 0) + prod_high;
res_ptr[j] = prod_low;
} while (++j);
return cy_limb;
}
/* mpihelp-mul_2.c - MPI helper functions
* Copyright (C) 1994, 1996, 1997, 1998, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* 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.
* The GNU MP Library itself is published under the LGPL;
* however I decided to publish this code under the plain GPL.
*/
#include "mpi-internal.h"
#include "longlong.h"
mpi_limb_t
mpihelp_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 cy_limb;
mpi_size_t j;
mpi_limb_t prod_high, prod_low;
mpi_limb_t x;
/* The loop counter and index J goes from -SIZE to -1. This way
* the loop becomes faster. */
j = -s1_size;
res_ptr -= j;
s1_ptr -= j;
cy_limb = 0;
do {
umul_ppmm(prod_high, prod_low, s1_ptr[j], s2_limb);
prod_low += cy_limb;
cy_limb = (prod_low < cy_limb ? 1 : 0) + prod_high;
x = res_ptr[j];
prod_low = x + prod_low;
cy_limb += prod_low < x ? 1 : 0;
res_ptr[j] = prod_low;
} while (++j);
return cy_limb;
}
/* mpihelp-mul_3.c - MPI helper functions
* Copyright (C) 1994, 1996, 1997, 1998, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* 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.
* The GNU MP Library itself is published under the LGPL;
* however I decided to publish this code under the plain GPL.
*/
#include "mpi-internal.h"
#include "longlong.h"
mpi_limb_t
mpihelp_submul_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
mpi_size_t s1_size, mpi_limb_t s2_limb)
{
mpi_limb_t cy_limb;
mpi_size_t j;
mpi_limb_t prod_high, prod_low;
mpi_limb_t x;
/* The loop counter and index J goes from -SIZE to -1. This way
* the loop becomes faster. */
j = -s1_size;
res_ptr -= j;
s1_ptr -= j;
cy_limb = 0;
do {
umul_ppmm(prod_high, prod_low, s1_ptr[j], s2_limb);
prod_low += cy_limb;
cy_limb = (prod_low < cy_limb ? 1 : 0) + prod_high;
x = res_ptr[j];
prod_low = x - prod_low;
cy_limb += prod_low > x ? 1 : 0;
res_ptr[j] = prod_low;
} while (++j);
return cy_limb;
}
/* mpih-rshift.c - MPI helper functions
* Copyright (C) 1994, 1996, 1998, 1999,
* 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GNUPG
*
* GNUPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GNUPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* 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.
* The GNU MP Library itself is published under the LGPL;
* however I decided to publish this code under the plain GPL.
*/
#include "mpi-internal.h"
/* Shift U (pointed to by UP and USIZE limbs long) CNT bits to the right
* and store the USIZE least significant limbs of the result at WP.
* The bits shifted out to the right are returned.
*
* Argument constraints:
* 1. 0 < CNT < BITS_PER_MP_LIMB
* 2. If the result is to be written over the input, WP must be <= UP.
*/
mpi_limb_t
mpihelp_rshift(mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize, unsigned cnt)
{
mpi_limb_t high_limb, low_limb;
unsigned sh_1, sh_2;
mpi_size_t i;
mpi_limb_t retval;
sh_1 = cnt;
wp -= 1;
sh_2 = BITS_PER_MPI_LIMB - sh_1;
high_limb = up[0];
retval = high_limb << sh_2;
low_limb = high_limb;
for (i = 1; i < usize; i++) {
high_limb = up[i];
wp[i] = (low_limb >> sh_1) | (high_limb << sh_2);
low_limb = high_limb;
}
wp[i] = low_limb >> sh_1;
return retval;
}
/* mpihelp-add_2.c - MPI helper functions
* Copyright (C) 1994, 1996, 1997, 1998, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* 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.
* The GNU MP Library itself is published under the LGPL;
* however I decided to publish this code under the plain GPL.
*/
#include "mpi-internal.h"
#include "longlong.h"
mpi_limb_t
mpihelp_sub_n(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
mpi_ptr_t s2_ptr, mpi_size_t size)
{
mpi_limb_t x, y, cy;
mpi_size_t j;
/* The loop counter and index J goes from -SIZE to -1. This way
the loop becomes faster. */
j = -size;
/* Offset the base pointers to compensate for the negative indices. */
s1_ptr -= j;
s2_ptr -= j;
res_ptr -= j;
cy = 0;
do {
y = s2_ptr[j];
x = s1_ptr[j];
y += cy; /* add previous carry to subtrahend */
cy = y < cy; /* get out carry from that addition */
y = x - y; /* main subtract */
cy += y > x; /* get out carry from the subtract, combine */
res_ptr[j] = y;
} while (++j);
return cy;
}
This diff is collapsed.
/* mpi-add.c - MPI functions
* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
* Copyright (C) 1994, 1996 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* 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.
* The GNU MP Library itself is published under the LGPL;
* however I decided to publish this code under the plain GPL.
*/
#include "mpi-internal.h"
/****************
* Add the unsigned integer V to the mpi-integer U and store the
* result in W. U and V may be the same.
*/
int mpi_add_ui(MPI w, const MPI u, unsigned long v)
{
mpi_ptr_t wp, up;
mpi_size_t usize, wsize;
int usign, wsign;
usize = u->nlimbs;
usign = u->sign;
wsign = 0;
/* If not space for W (and possible carry), increase space. */
wsize = usize + 1;
if (w->alloced < wsize)
if (mpi_resize(w, wsize) < 0)
return -ENOMEM;
/* These must be after realloc (U may be the same as W). */
up = u->d;
wp = w->d;
if (!usize) { /* simple */
wp[0] = v;
wsize = v ? 1 : 0;
} else if (!usign) { /* mpi is not negative */
mpi_limb_t cy;
cy = mpihelp_add_1(wp, up, usize, v);
wp[usize] = cy;
wsize = usize + cy;
} else { /* The signs are different. Need exact comparison to determine
* which operand to subtract from which. */
if (usize == 1 && up[0] < v) {
wp[0] = v - up[0];
wsize = 1;
} else {
mpihelp_sub_1(wp, up, usize, v);
/* Size can decrease with at most one limb. */
wsize = usize - (wp[usize - 1] == 0);
wsign = 1;
}
}
w->nlimbs = wsize;
w->sign = wsign;
return 0;
}
int mpi_add(MPI w, MPI u, MPI v)
{
mpi_ptr_t wp, up, vp;
mpi_size_t usize, vsize, wsize;
int usign, vsign, wsign;
if (u->nlimbs < v->nlimbs) { /* Swap U and V. */
usize = v->nlimbs;
usign = v->sign;
vsize = u->nlimbs;
vsign = u->sign;
wsize = usize + 1;
if (RESIZE_IF_NEEDED(w, wsize) < 0)
return -ENOMEM;
/* These must be after realloc (u or v may be the same as w). */
up = v->d;
vp = u->d;
} else {
usize = u->nlimbs;
usign = u->sign;
vsize = v->nlimbs;
vsign = v->sign;
wsize = usize + 1;
if (RESIZE_IF_NEEDED(w, wsize) < 0)
return -ENOMEM;
/* These must be after realloc (u or v may be the same as w). */
up = u->d;
vp = v->d;
}
wp = w->d;
wsign = 0;
if (!vsize) { /* simple */
MPN_COPY(wp, up, usize);
wsize = usize;
wsign = usign;
} else if (usign != vsign) { /* different sign */
/* This test is right since USIZE >= VSIZE */
if (usize != vsize) {
mpihelp_sub(wp, up, usize, vp, vsize);
wsize = usize;
MPN_NORMALIZE(wp, wsize);
wsign = usign;
} else if (mpihelp_cmp(up, vp, usize) < 0) {
mpihelp_sub_n(wp, vp, up, usize);
wsize = usize;
MPN_NORMALIZE(wp, wsize);
if (!usign)
wsign = 1;
} else {
mpihelp_sub_n(wp, up, vp, usize);
wsize = usize;
MPN_NORMALIZE(wp, wsize);
if (usign)
wsign = 1;
}
} else { /* U and V have same sign. Add them. */
mpi_limb_t cy = mpihelp_add(wp, up, usize, vp, vsize);
wp[usize] = cy;
wsize = usize + cy;
if (usign)
wsign = 1;
}
w->nlimbs = wsize;
w->sign = wsign;
return 0;
}
/****************
* Subtract the unsigned integer V from the mpi-integer U and store the
* result in W.
*/
int mpi_sub_ui(MPI w, MPI u, unsigned long v)
{
mpi_ptr_t wp, up;
mpi_size_t usize, wsize;
int usign, wsign;
usize = u->nlimbs;
usign = u->sign;
wsign = 0;
/* If not space for W (and possible carry), increase space. */
wsize = usize + 1;
if (w->alloced < wsize)
if (mpi_resize(w, wsize) < 0)
return -ENOMEM;
/* These must be after realloc (U may be the same as W). */
up = u->d;
wp = w->d;
if (!usize) { /* simple */
wp[0] = v;
wsize = v ? 1 : 0;
wsign = 1;
} else if (usign) { /* mpi and v are negative */
mpi_limb_t cy;
cy = mpihelp_add_1(wp, up, usize, v);
wp[usize] = cy;
wsize = usize + cy;
} else { /* The signs are different. Need exact comparison to determine
* which operand to subtract from which. */
if (usize == 1 && up[0] < v) {
wp[0] = v - up[0];
wsize = 1;
wsign = 1;
} else {
mpihelp_sub_1(wp, up, usize, v);
/* Size can decrease with at most one limb. */
wsize = usize - (wp[usize - 1] == 0);
}
}
w->nlimbs = wsize;
w->sign = wsign;
return 0;
}
int mpi_sub(MPI w, MPI u, MPI v)
{
int rc;
if (w == v) {
MPI vv;
if (mpi_copy(&vv, v) < 0)
return -ENOMEM;
vv->sign = !vv->sign;
rc = mpi_add(w, u, vv);
mpi_free(vv);
} else {
/* fixme: this is not thread-save (we temp. modify v) */
v->sign = !v->sign;
rc = mpi_add(w, u, v);
v->sign = !v->sign;
}
return rc;
}
int mpi_addm(MPI w, MPI u, MPI v, MPI m)
{
if (mpi_add(w, u, v) < 0 || mpi_fdiv_r(w, w, m) < 0)
return -ENOMEM;
return 0;
}
int mpi_subm(MPI w, MPI u, MPI v, MPI m)
{
if (mpi_sub(w, u, v) < 0 || mpi_fdiv_r(w, w, m) < 0)
return -ENOMEM;
return 0;
}
/* mpi-bit.c - MPI bit level fucntions
* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include "mpi-internal.h"
#include "longlong.h"
const unsigned char __clz_tab[] = {
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8,
};
#define A_LIMB_1 ((mpi_limb_t) 1)
/****************
* Sometimes we have MSL (most significant limbs) which are 0;
* this is for some reasons not good, so this function removes them.
*/
void mpi_normalize(MPI a)
{
for (; a->nlimbs && !a->d[a->nlimbs - 1]; a->nlimbs--)
;
}
/****************
* Return the number of bits in A.
*/
unsigned mpi_get_nbits(MPI a)
{
unsigned n;
mpi_normalize(a);
if (a->nlimbs) {
mpi_limb_t alimb = a->d[a->nlimbs - 1];
if (alimb)
count_leading_zeros(n, alimb);
else
n = BITS_PER_MPI_LIMB;
n = BITS_PER_MPI_LIMB - n + (a->nlimbs - 1) * BITS_PER_MPI_LIMB;
} else
n = 0;
return n;
}
EXPORT_SYMBOL_GPL(mpi_get_nbits);
/****************
* Test whether bit N is set.
*/
int mpi_test_bit(MPI a, unsigned n)
{
unsigned limbno, bitno;
mpi_limb_t limb;
limbno = n / BITS_PER_MPI_LIMB;
bitno = n % BITS_PER_MPI_LIMB;
if (limbno >= a->nlimbs)
return 0; /* too far left: this is a 0 */
limb = a->d[limbno];
return (limb & (A_LIMB_1 << bitno)) ? 1 : 0;
}
/****************
* Set bit N of A.
*/
int mpi_set_bit(MPI a, unsigned n)
{
unsigned limbno, bitno;
limbno = n / BITS_PER_MPI_LIMB;
bitno = n % BITS_PER_MPI_LIMB;
if (limbno >= a->nlimbs) { /* resize */
if (a->alloced >= limbno)
if (mpi_resize(a, limbno + 1) < 0)
return -ENOMEM;
a->nlimbs = limbno + 1;
}
a->d[limbno] |= (A_LIMB_1 << bitno);
return 0;
}
/****************
* Set bit N of A. and clear all bits above
*/
int mpi_set_highbit(MPI a, unsigned n)
{
unsigned limbno, bitno;
limbno = n / BITS_PER_MPI_LIMB;
bitno = n % BITS_PER_MPI_LIMB;
if (limbno >= a->nlimbs) { /* resize */
if (a->alloced >= limbno)
if (mpi_resize(a, limbno + 1) < 0)
return -ENOMEM;
a->nlimbs = limbno + 1;
}
a->d[limbno] |= (A_LIMB_1 << bitno);
for (bitno++; bitno < BITS_PER_MPI_LIMB; bitno++)
a->d[limbno] &= ~(A_LIMB_1 << bitno);
a->nlimbs = limbno + 1;
return 0;
}
/****************
* clear bit N of A and all bits above
*/
void mpi_clear_highbit(MPI a, unsigned n)
{
unsigned limbno, bitno;
limbno = n / BITS_PER_MPI_LIMB;
bitno = n % BITS_PER_MPI_LIMB;
if (limbno >= a->nlimbs)
return; /* not allocated, so need to clear bits :-) */
for (; bitno < BITS_PER_MPI_LIMB; bitno++)
a->d[limbno] &= ~(A_LIMB_1 << bitno);
a->nlimbs = limbno + 1;
}
/****************
* Clear bit N of A.
*/
void mpi_clear_bit(MPI a, unsigned n)
{
unsigned limbno, bitno;
limbno = n / BITS_PER_MPI_LIMB;
bitno = n % BITS_PER_MPI_LIMB;
if (limbno >= a->nlimbs)
return; /* don't need to clear this bit, it's to far to left */
a->d[limbno] &= ~(A_LIMB_1 << bitno);
}
/****************
* Shift A by N bits to the right
* FIXME: should use alloc_limb if X and A are same.
*/
int mpi_rshift(MPI x, MPI a, unsigned n)
{
mpi_ptr_t xp;
mpi_size_t xsize;
xsize = a->nlimbs;
x->sign = a->sign;
if (RESIZE_IF_NEEDED(x, (size_t) xsize) < 0)
return -ENOMEM;
xp = x->d;
if (xsize) {
mpihelp_rshift(xp, a->d, xsize, n);
MPN_NORMALIZE(xp, xsize);
}
x->nlimbs = xsize;
return 0;
}
/****************
* Shift A by COUNT limbs to the left
* This is used only within the MPI library
*/
int mpi_lshift_limbs(MPI a, unsigned int count)
{
mpi_ptr_t ap = a->d;
int n = a->nlimbs;
int i;
if (!count || !n)
return 0;
if (RESIZE_IF_NEEDED(a, n + count) < 0)
return -ENOMEM;
for (i = n - 1; i >= 0; i--)
ap[i + count] = ap[i];
for (i = 0; i < count; i++)
ap[i] = 0;
a->nlimbs += count;
return 0;
}
/****************
* Shift A by COUNT limbs to the right
* This is used only within the MPI library
*/
void mpi_rshift_limbs(MPI a, unsigned int count)
{
mpi_ptr_t ap = a->d;
mpi_size_t n = a->nlimbs;
unsigned int i;
if (count >= n) {
a->nlimbs = 0;
return;
}
for (i = 0; i < n - count; i++)
ap[i] = ap[i + count];
ap[i] = 0;
a->nlimbs -= count;
}
/* mpi-cmp.c - MPI functions
* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include "mpi-internal.h"
int mpi_cmp_ui(MPI u, unsigned long v)
{
mpi_limb_t limb = v;
mpi_normalize(u);
if (!u->nlimbs && !limb)
return 0;
if (u->sign)
return -1;
if (u->nlimbs > 1)
return 1;
if (u->d[0] == limb)
return 0;
else if (u->d[0] > limb)
return 1;
else
return -1;
}
int mpi_cmp(MPI u, MPI v)
{
mpi_size_t usize, vsize;
int cmp;
mpi_normalize(u);
mpi_normalize(v);
usize = u->nlimbs;
vsize = v->nlimbs;
if (!u->sign && v->sign)
return 1;
if (u->sign && !v->sign)
return -1;
if (usize != vsize && !u->sign && !v->sign)
return usize - vsize;
if (usize != vsize && u->sign && v->sign)
return vsize + usize;
if (!usize)
return 0;
cmp = mpihelp_cmp(u->d, v->d, usize);
if (!cmp)
return 0;
if ((cmp < 0 ? 1 : 0) == (u->sign ? 1 : 0))
return 1;
return -1;
}
/* mpi-div.c - MPI functions
* Copyright (C) 1994, 1996 Free Software Foundation, Inc.
* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* 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.
* The GNU MP Library itself is published under the LGPL;
* however I decided to publish this code under the plain GPL.
*/
#include <linux/string.h>
#include "mpi-internal.h"
#include "longlong.h"
int mpi_fdiv_r(MPI rem, MPI dividend, MPI divisor)
{
int rc = -ENOMEM;
int divisor_sign = divisor->sign;
MPI temp_divisor = NULL;
/* We need the original value of the divisor after the remainder has been
* preliminary calculated. We have to copy it to temporary space if it's
* the same variable as REM. */
if (rem == divisor) {
if (mpi_copy(&temp_divisor, divisor) < 0)
goto nomem;
divisor = temp_divisor;
}
if (mpi_tdiv_qr(NULL, rem, dividend, divisor) < 0)
goto nomem;
if (((divisor_sign ? 1 : 0) ^ (dividend->sign ? 1 : 0)) && rem->nlimbs)
if (mpi_add(rem, rem, divisor) < 0)
goto nomem;
rc = 0;
nomem:
if (temp_divisor)
mpi_free(temp_divisor);
return rc;
}
/****************
* Division rounding the quotient towards -infinity.
* The remainder gets the same sign as the denominator.
* rem is optional
*/
ulong mpi_fdiv_r_ui(MPI rem, MPI dividend, ulong divisor)
{
mpi_limb_t rlimb;
rlimb = mpihelp_mod_1(dividend->d, dividend->nlimbs, divisor);
if (rlimb && dividend->sign)
rlimb = divisor - rlimb;
if (rem) {
rem->d[0] = rlimb;
rem->nlimbs = rlimb ? 1 : 0;
}
return rlimb;
}
int mpi_fdiv_q(MPI quot, MPI dividend, MPI divisor)
{
MPI tmp = mpi_alloc(mpi_get_nlimbs(quot));
if (!tmp)
return -ENOMEM;
mpi_fdiv_qr(quot, tmp, dividend, divisor);
mpi_free(tmp);
return 0;
}
int mpi_fdiv_qr(MPI quot, MPI rem, MPI dividend, MPI divisor)
{
int divisor_sign = divisor->sign;
MPI temp_divisor = NULL;
if (quot == divisor || rem == divisor) {
if (mpi_copy(&temp_divisor, divisor) < 0)
return -ENOMEM;
divisor = temp_divisor;
}
if (mpi_tdiv_qr(quot, rem, dividend, divisor) < 0)
goto nomem;
if ((divisor_sign ^ dividend->sign) && rem->nlimbs) {
if (mpi_sub_ui(quot, quot, 1) < 0)
goto nomem;
if (mpi_add(rem, rem, divisor) < 0)
goto nomem;
}
if (temp_divisor)
mpi_free(temp_divisor);
return 0;
nomem:
mpi_free(temp_divisor);
return -ENOMEM;
}
/* If den == quot, den needs temporary storage.
* If den == rem, den needs temporary storage.
* If num == quot, num needs temporary storage.
* If den has temporary storage, it can be normalized while being copied,
* i.e no extra storage should be allocated.
*/
int mpi_tdiv_r(MPI rem, MPI num, MPI den)
{
return mpi_tdiv_qr(NULL, rem, num, den);
}
int mpi_tdiv_qr(MPI quot, MPI rem, MPI num, MPI den)
{
int rc = -ENOMEM;
mpi_ptr_t np, dp;
mpi_ptr_t qp, rp;
mpi_size_t nsize = num->nlimbs;
mpi_size_t dsize = den->nlimbs;
mpi_size_t qsize, rsize;
mpi_size_t sign_remainder = num->sign;
mpi_size_t sign_quotient = num->sign ^ den->sign;
unsigned normalization_steps;
mpi_limb_t q_limb;
mpi_ptr_t marker[5];
int markidx = 0;
memset(marker, 0, sizeof(marker));
/* Ensure space is enough for quotient and remainder.
* We need space for an extra limb in the remainder, because it's
* up-shifted (normalized) below. */
rsize = nsize + 1;
if (mpi_resize(rem, rsize) < 0)
goto nomem;
qsize = rsize - dsize; /* qsize cannot be bigger than this. */
if (qsize <= 0) {
if (num != rem) {
rem->nlimbs = num->nlimbs;
rem->sign = num->sign;
MPN_COPY(rem->d, num->d, nsize);
}
if (quot) {
/* This needs to follow the assignment to rem, in case the
* numerator and quotient are the same. */
quot->nlimbs = 0;
quot->sign = 0;
}
return 0;
}
if (quot)
if (mpi_resize(quot, qsize) < 0)
goto nomem;
/* Read pointers here, when reallocation is finished. */
np = num->d;
dp = den->d;
rp = rem->d;
/* Optimize division by a single-limb divisor. */
if (dsize == 1) {
mpi_limb_t rlimb;
if (quot) {
qp = quot->d;
rlimb = mpihelp_divmod_1(qp, np, nsize, dp[0]);
qsize -= qp[qsize - 1] == 0;
quot->nlimbs = qsize;
quot->sign = sign_quotient;
} else
rlimb = mpihelp_mod_1(np, nsize, dp[0]);
rp[0] = rlimb;
rsize = rlimb != 0 ? 1 : 0;
rem->nlimbs = rsize;
rem->sign = sign_remainder;
return 0;
}
if (quot) {
qp = quot->d;
/* Make sure QP and NP point to different objects. Otherwise the
* numerator would be gradually overwritten by the quotient limbs. */
if (qp == np) { /* Copy NP object to temporary space. */
np = marker[markidx++] = mpi_alloc_limb_space(nsize);
MPN_COPY(np, qp, nsize);
}
} else /* Put quotient at top of remainder. */
qp = rp + dsize;
count_leading_zeros(normalization_steps, dp[dsize - 1]);
/* Normalize the denominator, i.e. make its most significant bit set by
* shifting it NORMALIZATION_STEPS bits to the left. Also shift the
* numerator the same number of steps (to keep the quotient the same!).
*/
if (normalization_steps) {
mpi_ptr_t tp;
mpi_limb_t nlimb;
/* Shift up the denominator setting the most significant bit of
* the most significant word. Use temporary storage not to clobber
* the original contents of the denominator. */
tp = marker[markidx++] = mpi_alloc_limb_space(dsize);
if (!tp)
goto nomem;
mpihelp_lshift(tp, dp, dsize, normalization_steps);
dp = tp;
/* Shift up the numerator, possibly introducing a new most
* significant word. Move the shifted numerator in the remainder
* meanwhile. */
nlimb = mpihelp_lshift(rp, np, nsize, normalization_steps);
if (nlimb) {
rp[nsize] = nlimb;
rsize = nsize + 1;
} else
rsize = nsize;
} else {
/* The denominator is already normalized, as required. Copy it to
* temporary space if it overlaps with the quotient or remainder. */
if (dp == rp || (quot && (dp == qp))) {
mpi_ptr_t tp;
tp = marker[markidx++] = mpi_alloc_limb_space(dsize);
if (!tp)
goto nomem;
MPN_COPY(tp, dp, dsize);
dp = tp;
}
/* Move the numerator to the remainder. */
if (rp != np)
MPN_COPY(rp, np, nsize);
rsize = nsize;
}
q_limb = mpihelp_divrem(qp, 0, rp, rsize, dp, dsize);
if (quot) {
qsize = rsize - dsize;
if (q_limb) {
qp[qsize] = q_limb;
qsize += 1;
}
quot->nlimbs = qsize;
quot->sign = sign_quotient;
}
rsize = dsize;
MPN_NORMALIZE(rp, rsize);
if (normalization_steps && rsize) {
mpihelp_rshift(rp, rp, rsize, normalization_steps);
rsize -= rp[rsize - 1] == 0 ? 1 : 0;
}
rem->nlimbs = rsize;
rem->sign = sign_remainder;
rc = 0;
nomem:
while (markidx)
mpi_free_limb_space(marker[--markidx]);
return rc;
}
int mpi_tdiv_q_2exp(MPI w, MPI u, unsigned count)
{
mpi_size_t usize, wsize;
mpi_size_t limb_cnt;
usize = u->nlimbs;
limb_cnt = count / BITS_PER_MPI_LIMB;
wsize = usize - limb_cnt;
if (limb_cnt >= usize)
w->nlimbs = 0;
else {
mpi_ptr_t wp;
mpi_ptr_t up;
if (RESIZE_IF_NEEDED(w, wsize) < 0)
return -ENOMEM;
wp = w->d;
up = u->d;
count %= BITS_PER_MPI_LIMB;
if (count) {
mpihelp_rshift(wp, up + limb_cnt, wsize, count);
wsize -= !wp[wsize - 1];
} else {
MPN_COPY_INCR(wp, up + limb_cnt, wsize);
}
w->nlimbs = wsize;
}
return 0;
}
/****************
* Check whether dividend is divisible by divisor
* (note: divisor must fit into a limb)
*/
int mpi_divisible_ui(MPI dividend, ulong divisor)
{
return !mpihelp_mod_1(dividend->d, dividend->nlimbs, divisor);
}
/* mpi-gcd.c - MPI functions
* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include "mpi-internal.h"
/****************
* Find the greatest common divisor G of A and B.
* Return: true if this 1, false in all other cases
*/
int mpi_gcd(MPI g, const MPI xa, const MPI xb)
{
MPI a = NULL, b = NULL;
if (mpi_copy(&a, xa) < 0)
goto nomem;
if (mpi_copy(&b, xb) < 0)
goto nomem;
/* TAOCP Vol II, 4.5.2, Algorithm A */
a->sign = 0;
b->sign = 0;
while (mpi_cmp_ui(b, 0)) {
if (mpi_fdiv_r(g, a, b) < 0) /* g used as temorary variable */
goto nomem;
if (mpi_set(a, b) < 0)
goto nomem;
if (mpi_set(b, g) < 0)
goto nomem;
}
if (mpi_set(g, a) < 0)
goto nomem;
mpi_free(a);
mpi_free(b);
return !mpi_cmp_ui(g, 1);
nomem:
mpi_free(a);
mpi_free(b);
return -ENOMEM;
}
/* mpi-inline.c
* Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/* put the inline functions as real functions into the lib */
#define G10_MPI_INLINE_DECL
#include "mpi-internal.h"
/* always include the header becuase it is only
* included by mpi-internal if __GCC__ is defined but we
* need it here in all cases and the above definition of
* of the macro allows us to do so
*/
#include "mpi-inline.h"
/* mpi-inline.h - Internal to the Multi Precision Integers
* Copyright (C) 1994, 1996, 1998, 1999 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* 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.
* The GNU MP Library itself is published under the LGPL;
* however I decided to publish this code under the plain GPL.
*/
#ifndef G10_MPI_INLINE_H
#define G10_MPI_INLINE_H
#ifndef G10_MPI_INLINE_DECL
#define G10_MPI_INLINE_DECL extern inline
#endif
G10_MPI_INLINE_DECL mpi_limb_t
mpihelp_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 x;
x = *s1_ptr++;
s2_limb += x;
*res_ptr++ = s2_limb;
if (s2_limb < x) { /* sum is less than the left operand: handle carry */
while (--s1_size) {
x = *s1_ptr++ + 1; /* add carry */
*res_ptr++ = x; /* and store */
if (x) /* not 0 (no overflow): we can stop */
goto leave;
}
return 1; /* return carry (size of s1 to small) */
}
leave:
if (res_ptr != s1_ptr) { /* not the same variable */
mpi_size_t i; /* copy the rest */
for (i = 0; i < s1_size - 1; i++)
res_ptr[i] = s1_ptr[i];
}
return 0; /* no carry */
}
G10_MPI_INLINE_DECL mpi_limb_t
mpihelp_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)
{
mpi_limb_t cy = 0;
if (s2_size)
cy = mpihelp_add_n(res_ptr, s1_ptr, s2_ptr, s2_size);
if (s1_size - s2_size)
cy = mpihelp_add_1(res_ptr + s2_size, s1_ptr + s2_size,
s1_size - s2_size, cy);
return cy;
}
G10_MPI_INLINE_DECL mpi_limb_t
mpihelp_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 x;
x = *s1_ptr++;
s2_limb = x - s2_limb;
*res_ptr++ = s2_limb;
if (s2_limb > x) {
while (--s1_size) {
x = *s1_ptr++;
*res_ptr++ = x - 1;
if (x)
goto leave;
}
return 1;
}
leave:
if (res_ptr != s1_ptr) {
mpi_size_t i;
for (i = 0; i < s1_size - 1; i++)
res_ptr[i] = s1_ptr[i];
}
return 0;
}
G10_MPI_INLINE_DECL mpi_limb_t
mpihelp_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)
{
mpi_limb_t cy = 0;
if (s2_size)
cy = mpihelp_sub_n(res_ptr, s1_ptr, s2_ptr, s2_size);
if (s1_size - s2_size)
cy = mpihelp_sub_1(res_ptr + s2_size, s1_ptr + s2_size,
s1_size - s2_size, cy);
return cy;
}
#endif /*G10_MPI_INLINE_H */
/* mpi-internal.h - Internal to the Multi Precision Integers
* Copyright (C) 1994, 1996 Free Software Foundation, Inc.
* Copyright (C) 1998, 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* 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.
* The GNU MP Library itself is published under the LGPL;
* however I decided to publish this code under the plain GPL.
*/
#ifndef G10_MPI_INTERNAL_H
#define G10_MPI_INTERNAL_H
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/mpi.h>
#include <linux/errno.h>
#define log_debug printk
#define log_bug printk
#define assert(x) \
do { \
if (!x) \
log_bug("failed assertion\n"); \
} while (0);
/* 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))
static inline int RESIZE_IF_NEEDED(MPI a, unsigned b)
{
if (a->alloced < b)
return mpi_resize(a, b);
return 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] = (d)[_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 _q, _ql, _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 --*/
mpi_ptr_t mpi_alloc_limb_space(unsigned nlimbs);
void mpi_free_limb_space(mpi_ptr_t a);
void mpi_assign_limb_space(MPI a, mpi_ptr_t ap, unsigned nlimbs);
/*-- mpi-bit.c --*/
void mpi_rshift_limbs(MPI a, unsigned int count);
int mpi_lshift_limbs(MPI a, unsigned int count);
/*-- mpihelp-add.c --*/
mpi_limb_t mpihelp_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 mpihelp_add_n(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
mpi_ptr_t s2_ptr, mpi_size_t size);
mpi_limb_t mpihelp_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);
/*-- mpihelp-sub.c --*/
mpi_limb_t mpihelp_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 mpihelp_sub_n(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
mpi_ptr_t s2_ptr, mpi_size_t size);
mpi_limb_t mpihelp_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);
/*-- mpihelp-cmp.c --*/
int mpihelp_cmp(mpi_ptr_t op1_ptr, mpi_ptr_t op2_ptr, mpi_size_t size);
/*-- mpihelp-mul.c --*/
struct karatsuba_ctx {
struct karatsuba_ctx *next;
mpi_ptr_t tspace;
mpi_size_t tspace_size;
mpi_ptr_t tp;
mpi_size_t tp_size;
};
void mpihelp_release_karatsuba_ctx(struct karatsuba_ctx *ctx);
mpi_limb_t mpihelp_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 mpihelp_submul_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
mpi_size_t s1_size, mpi_limb_t s2_limb);
int mpihelp_mul_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t size);
int mpihelp_mul(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t usize,
mpi_ptr_t vp, mpi_size_t vsize, mpi_limb_t *_result);
void mpih_sqr_n_basecase(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size);
void mpih_sqr_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size,
mpi_ptr_t tspace);
int mpihelp_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);
/*-- mpihelp-mul_1.c (or xxx/cpu/ *.S) --*/
mpi_limb_t mpihelp_mul_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
mpi_size_t s1_size, mpi_limb_t s2_limb);
/*-- mpihelp-div.c --*/
mpi_limb_t mpihelp_mod_1(mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
mpi_limb_t divisor_limb);
mpi_limb_t mpihelp_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 mpihelp_divmod_1(mpi_ptr_t quot_ptr,
mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
mpi_limb_t divisor_limb);
/*-- mpihelp-shift.c --*/
mpi_limb_t mpihelp_lshift(mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize,
unsigned cnt);
mpi_limb_t mpihelp_rshift(mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize,
unsigned cnt);
/* 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 */
/* mpi-inv.c - MPI functions
* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include "mpi-internal.h"
/****************
* Calculate the multiplicative inverse X of A mod N
* That is: Find the solution x for
* 1 = (a*x) mod n
*/
int mpi_invm(MPI x, const MPI a, const MPI n)
{
/* Extended Euclid's algorithm (See TAOPC Vol II, 4.5.2, Alg X)
* modified according to Michael Penk's solution for Exercice 35
* with further enhancement */
MPI u = NULL, v = NULL;
MPI u1 = NULL, u2 = NULL, u3 = NULL;
MPI v1 = NULL, v2 = NULL, v3 = NULL;
MPI t1 = NULL, t2 = NULL, t3 = NULL;
unsigned k;
int sign;
int odd = 0;
int rc = -ENOMEM;
if (mpi_copy(&u, a) < 0)
goto cleanup;
if (mpi_copy(&v, n) < 0)
goto cleanup;
for (k = 0; !mpi_test_bit(u, 0) && !mpi_test_bit(v, 0); k++) {
if (mpi_rshift(u, u, 1) < 0)
goto cleanup;
if (mpi_rshift(v, v, 1) < 0)
goto cleanup;
}
odd = mpi_test_bit(v, 0);
u1 = mpi_alloc_set_ui(1);
if (!u1)
goto cleanup;
if (!odd) {
u2 = mpi_alloc_set_ui(0);
if (!u2)
goto cleanup;
}
if (mpi_copy(&u3, u) < 0)
goto cleanup;
if (mpi_copy(&v1, v) < 0)
goto cleanup;
if (!odd) {
v2 = mpi_alloc(mpi_get_nlimbs(u));
if (!v2)
goto cleanup;
if (mpi_sub(v2, u1, u) < 0)
goto cleanup; /* U is used as const 1 */
}
if (mpi_copy(&v3, v) < 0)
goto cleanup;
if (mpi_test_bit(u, 0)) { /* u is odd */
t1 = mpi_alloc_set_ui(0);
if (!t1)
goto cleanup;
if (!odd) {
t2 = mpi_alloc_set_ui(1);
if (!t2)
goto cleanup;
t2->sign = 1;
}
if (mpi_copy(&t3, v) < 0)
goto cleanup;
t3->sign = !t3->sign;
goto Y4;
} else {
t1 = mpi_alloc_set_ui(1);
if (!t1)
goto cleanup;
if (!odd) {
t2 = mpi_alloc_set_ui(0);
if (!t2)
goto cleanup;
}
if (mpi_copy(&t3, u) < 0)
goto cleanup;
}
do {
do {
if (!odd) {
if (mpi_test_bit(t1, 0) || mpi_test_bit(t2, 0)) { /* one is odd */
if (mpi_add(t1, t1, v) < 0)
goto cleanup;
if (mpi_sub(t2, t2, u) < 0)
goto cleanup;
}
if (mpi_rshift(t1, t1, 1) < 0)
goto cleanup;
if (mpi_rshift(t2, t2, 1) < 0)
goto cleanup;
if (mpi_rshift(t3, t3, 1) < 0)
goto cleanup;
} else {
if (mpi_test_bit(t1, 0))
if (mpi_add(t1, t1, v) < 0)
goto cleanup;
if (mpi_rshift(t1, t1, 1) < 0)
goto cleanup;
if (mpi_rshift(t3, t3, 1) < 0)
goto cleanup;
}
Y4:
;
} while (!mpi_test_bit(t3, 0)); /* while t3 is even */
if (!t3->sign) {
if (mpi_set(u1, t1) < 0)
goto cleanup;
if (!odd)
if (mpi_set(u2, t2) < 0)
goto cleanup;
if (mpi_set(u3, t3) < 0)
goto cleanup;
} else {
if (mpi_sub(v1, v, t1) < 0)
goto cleanup;
sign = u->sign;
u->sign = !u->sign;
if (!odd)
if (mpi_sub(v2, u, t2) < 0)
goto cleanup;
u->sign = sign;
sign = t3->sign;
t3->sign = !t3->sign;
if (mpi_set(v3, t3) < 0)
goto cleanup;
t3->sign = sign;
}
if (mpi_sub(t1, u1, v1) < 0)
goto cleanup;
if (!odd)
if (mpi_sub(t2, u2, v2) < 0)
goto cleanup;
if (mpi_sub(t3, u3, v3) < 0)
goto cleanup;
if (t1->sign) {
if (mpi_add(t1, t1, v) < 0)
goto cleanup;
if (!odd)
if (mpi_sub(t2, t2, u) < 0)
goto cleanup;
}
} while (mpi_cmp_ui(t3, 0)); /* while t3 != 0 */
/* mpi_lshift( u3, k ); */
rc = mpi_set(x, u1);
cleanup:
mpi_free(u1);
mpi_free(v1);
mpi_free(t1);
if (!odd) {
mpi_free(u2);
mpi_free(v2);
mpi_free(t2);
}
mpi_free(u3);
mpi_free(v3);
mpi_free(t3);
mpi_free(u);
mpi_free(v);
return rc;
}
/* mpi-mpow.c - MPI functions
* Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include "mpi-internal.h"
#include "longlong.h"
static int build_index(const MPI *exparray, int k, int i, int t)
{
int j, bitno;
int index = 0;
bitno = t - i;
for (j = k - 1; j >= 0; j--) {
index <<= 1;
if (mpi_test_bit(exparray[j], bitno))
index |= 1;
}
return index;
}
/****************
* RES = (BASE[0] ^ EXP[0]) * (BASE[1] ^ EXP[1]) * ... * mod M
*/
int mpi_mulpowm(MPI res, MPI *basearray, MPI *exparray, MPI m)
{
int rc = -ENOMEM;
int k; /* number of elements */
int t; /* bit size of largest exponent */
int i, j, idx;
MPI *G = NULL; /* table with precomputed values of size 2^k */
MPI tmp = NULL;
for (k = 0; basearray[k]; k++)
;
if (!k) {
pr_emerg("mpi_mulpowm: assert(k) failed\n");
BUG();
}
for (t = 0, i = 0; (tmp = exparray[i]); i++) {
j = mpi_get_nbits(tmp);
if (j > t)
t = j;
}
if (i != k) {
pr_emerg("mpi_mulpowm: assert(i==k) failed\n");
BUG();
}
if (!t) {
pr_emerg("mpi_mulpowm: assert(t) failed\n");
BUG();
}
if (k >= 10) {
pr_emerg("mpi_mulpowm: assert(k<10) failed\n");
BUG();
}
G = kzalloc((1 << k) * sizeof *G, GFP_KERNEL);
if (!G)
goto nomem;
/* and calculate */
tmp = mpi_alloc(mpi_get_nlimbs(m) + 1);
if (!tmp)
goto nomem;
if (mpi_set_ui(res, 1) < 0)
goto nomem;
for (i = 1; i <= t; i++) {
if (mpi_mulm(tmp, res, res, m) < 0)
goto nomem;
idx = build_index(exparray, k, i, t);
if (!(idx >= 0 && idx < (1 << k))) {
pr_emerg("mpi_mulpowm: assert(idx >= 0 && idx < (1<<k)) failed\n");
BUG();
}
if (!G[idx]) {
if (!idx) {
G[0] = mpi_alloc_set_ui(1);
if (!G[0])
goto nomem;
} else {
for (j = 0; j < k; j++) {
if ((idx & (1 << j))) {
if (!G[idx]) {
if (mpi_copy
(&G[idx],
basearray[j]) < 0)
goto nomem;
} else {
if (mpi_mulm
(G[idx], G[idx],
basearray[j],
m) < 0)
goto nomem;
}
}
}
if (!G[idx]) {
G[idx] = mpi_alloc(0);
if (!G[idx])
goto nomem;
}
}
}
if (mpi_mulm(res, tmp, G[idx], m) < 0)
goto nomem;
}
rc = 0;
nomem:
/* cleanup */
mpi_free(tmp);
for (i = 0; i < (1 << k); i++)
mpi_free(G[i]);
kfree(G);
return rc;
}
/* mpi-mul.c - MPI functions
* Copyright (C) 1994, 1996 Free Software Foundation, Inc.
* Copyright (C) 1998, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* 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.
* The GNU MP Library itself is published under the LGPL;
* however I decided to publish this code under the plain GPL.
*/
#include "mpi-internal.h"
int mpi_mul_ui(MPI prod, MPI mult, unsigned long small_mult)
{
mpi_size_t size, prod_size;
mpi_ptr_t prod_ptr;
mpi_limb_t cy;
int sign;
size = mult->nlimbs;
sign = mult->sign;
if (!size || !small_mult) {
prod->nlimbs = 0;
prod->sign = 0;
return 0;
}
prod_size = size + 1;
if (prod->alloced < prod_size)
if (mpi_resize(prod, prod_size) < 0)
return -ENOMEM;
prod_ptr = prod->d;
cy = mpihelp_mul_1(prod_ptr, mult->d, size, (mpi_limb_t) small_mult);
if (cy)
prod_ptr[size++] = cy;
prod->nlimbs = size;
prod->sign = sign;
return 0;
}
int mpi_mul_2exp(MPI w, MPI u, unsigned long cnt)
{
mpi_size_t usize, wsize, limb_cnt;
mpi_ptr_t wp;
mpi_limb_t wlimb;
int usign, wsign;
usize = u->nlimbs;
usign = u->sign;
if (!usize) {
w->nlimbs = 0;
w->sign = 0;
return 0;
}
limb_cnt = cnt / BITS_PER_MPI_LIMB;
wsize = usize + limb_cnt + 1;
if (w->alloced < wsize)
if (mpi_resize(w, wsize) < 0)
return -ENOMEM;
wp = w->d;
wsize = usize + limb_cnt;
wsign = usign;
cnt %= BITS_PER_MPI_LIMB;
if (cnt) {
wlimb = mpihelp_lshift(wp + limb_cnt, u->d, usize, cnt);
if (wlimb) {
wp[wsize] = wlimb;
wsize++;
}
} else {
MPN_COPY_DECR(wp + limb_cnt, u->d, usize);
}
/* Zero all whole limbs at low end. Do it here and not before calling
* mpn_lshift, not to lose for U == W. */
MPN_ZERO(wp, limb_cnt);
w->nlimbs = wsize;
w->sign = wsign;
return 0;
}
int mpi_mul(MPI w, MPI u, MPI v)
{
int rc = -ENOMEM;
mpi_size_t usize, vsize, wsize;
mpi_ptr_t up, vp, wp;
mpi_limb_t cy;
int usign, vsign, sign_product;
int assign_wp = 0;
mpi_ptr_t tmp_limb = NULL;
if (u->nlimbs < v->nlimbs) { /* Swap U and V. */
usize = v->nlimbs;
usign = v->sign;
up = v->d;
vsize = u->nlimbs;
vsign = u->sign;
vp = u->d;
} else {
usize = u->nlimbs;
usign = u->sign;
up = u->d;
vsize = v->nlimbs;
vsign = v->sign;
vp = v->d;
}
sign_product = usign ^ vsign;
wp = w->d;
/* Ensure W has space enough to store the result. */
wsize = usize + vsize;
if (w->alloced < (size_t) wsize) {
if (wp == up || wp == vp) {
wp = mpi_alloc_limb_space(wsize);
if (!wp)
goto nomem;
assign_wp = 1;
} else {
if (mpi_resize(w, wsize) < 0)
goto nomem;
wp = w->d;
}
} else { /* Make U and V not overlap with W. */
if (wp == up) {
/* W and U are identical. Allocate temporary space for U. */
up = tmp_limb = mpi_alloc_limb_space(usize);
if (!up)
goto nomem;
/* Is V identical too? Keep it identical with U. */
if (wp == vp)
vp = up;
/* Copy to the temporary space. */
MPN_COPY(up, wp, usize);
} else if (wp == vp) {
/* W and V are identical. Allocate temporary space for V. */
vp = tmp_limb = mpi_alloc_limb_space(vsize);
if (!vp)
goto nomem;
/* Copy to the temporary space. */
MPN_COPY(vp, wp, vsize);
}
}
if (!vsize)
wsize = 0;
else {
if (mpihelp_mul(wp, up, usize, vp, vsize, &cy) < 0)
goto nomem;
wsize -= cy ? 0 : 1;
}
if (assign_wp)
mpi_assign_limb_space(w, wp, wsize);
w->nlimbs = wsize;
w->sign = sign_product;
rc = 0;
nomem:
if (tmp_limb)
mpi_free_limb_space(tmp_limb);
return rc;
}
int mpi_mulm(MPI w, MPI u, MPI v, MPI m)
{
if (mpi_mul(w, u, v) < 0)
return -ENOMEM;
return mpi_fdiv_r(w, w, m);
}
/* mpi-pow.c - MPI functions
* Copyright (C) 1994, 1996, 1998, 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* 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.
* The GNU MP Library itself is published under the LGPL;
* however I decided to publish this code under the plain GPL.
*/
#include <linux/string.h>
#include "mpi-internal.h"
#include "longlong.h"
/****************
* RES = BASE ^ EXP mod MOD
*/
int mpi_powm(MPI res, MPI base, MPI exp, MPI mod)
{
mpi_ptr_t mp_marker = NULL, bp_marker = NULL, ep_marker = NULL;
mpi_ptr_t xp_marker = NULL;
mpi_ptr_t tspace = NULL;
mpi_ptr_t rp, ep, mp, bp;
mpi_size_t esize, msize, bsize, rsize;
int esign, msign, bsign, rsign;
mpi_size_t size;
int mod_shift_cnt;
int negative_result;
int assign_rp = 0;
mpi_size_t tsize = 0; /* to avoid compiler warning */
/* fixme: we should check that the warning is void */
int rc = -ENOMEM;
esize = exp->nlimbs;
msize = mod->nlimbs;
size = 2 * msize;
esign = exp->sign;
msign = mod->sign;
rp = res->d;
ep = exp->d;
if (!msize)
msize = 1 / msize; /* provoke a signal */
if (!esize) {
/* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0
* depending on if MOD equals 1. */
rp[0] = 1;
res->nlimbs = (msize == 1 && mod->d[0] == 1) ? 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 = mp_marker = mpi_alloc_limb_space(msize);
if (!mp)
goto enomem;
count_leading_zeros(mod_shift_cnt, mod->d[msize - 1]);
if (mod_shift_cnt)
mpihelp_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 = bp_marker = mpi_alloc_limb_space(bsize + 1);
if (!bp)
goto enomem;
MPN_COPY(bp, base->d, bsize);
/* We don't care about the quotient, store it above the remainder,
* at BP + MSIZE. */
mpihelp_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;
}
if (res->alloced < size) {
/* We have to allocate more space for RES. If any of the input
* parameters are identical to RES, defer deallocation of the old
* space. */
if (rp == ep || rp == mp || rp == bp) {
rp = mpi_alloc_limb_space(size);
if (!rp)
goto enomem;
assign_rp = 1;
} else {
if (mpi_resize(res, size) < 0)
goto enomem;
rp = res->d;
}
} else { /* Make BASE, EXP and MOD not overlap with RES. */
if (rp == bp) {
/* RES and BASE are identical. Allocate temp. space for BASE. */
BUG_ON(bp_marker);
bp = bp_marker = mpi_alloc_limb_space(bsize);
if (!bp)
goto enomem;
MPN_COPY(bp, rp, bsize);
}
if (rp == ep) {
/* RES and EXP are identical. Allocate temp. space for EXP. */
ep = ep_marker = mpi_alloc_limb_space(esize);
if (!ep)
goto enomem;
MPN_COPY(ep, rp, esize);
}
if (rp == mp) {
/* RES and MOD are identical. Allocate temporary space for MOD. */
BUG_ON(mp_marker);
mp = mp_marker = mpi_alloc_limb_space(msize);
if (!mp)
goto enomem;
MPN_COPY(mp, rp, msize);
}
}
MPN_COPY(rp, bp, bsize);
rsize = bsize;
rsign = bsign;
{
mpi_size_t i;
mpi_ptr_t xp;
int c;
mpi_limb_t e;
mpi_limb_t carry_limb;
struct karatsuba_ctx karactx;
xp = xp_marker = mpi_alloc_limb_space(2 * (msize + 1));
if (!xp)
goto enomem;
memset(&karactx, 0, sizeof karactx);
negative_result = (ep[0] & 1) && base->sign;
i = esize - 1;
e = ep[i];
count_leading_zeros(c, e);
e = (e << c) << 1; /* shift the exp 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 mpihelp_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;
/*if (mpihelp_mul_n(xp, rp, rp, rsize) < 0) goto enomem */
if (rsize < KARATSUBA_THRESHOLD)
mpih_sqr_n_basecase(xp, rp, rsize);
else {
if (!tspace) {
tsize = 2 * rsize;
tspace =
mpi_alloc_limb_space(tsize);
if (!tspace)
goto enomem;
} else if (tsize < (2 * rsize)) {
mpi_free_limb_space(tspace);
tsize = 2 * rsize;
tspace =
mpi_alloc_limb_space(tsize);
if (!tspace)
goto enomem;
}
mpih_sqr_n(xp, rp, rsize, tspace);
}
xsize = 2 * rsize;
if (xsize > msize) {
mpihelp_divrem(xp + msize, 0, xp, xsize,
mp, msize);
xsize = msize;
}
tp = rp;
rp = xp;
xp = tp;
rsize = xsize;
if ((mpi_limb_signed_t) e < 0) {
/*mpihelp_mul( xp, rp, rsize, bp, bsize ); */
if (bsize < KARATSUBA_THRESHOLD) {
mpi_limb_t tmp;
if (mpihelp_mul
(xp, rp, rsize, bp, bsize,
&tmp) < 0)
goto enomem;
} else {
if (mpihelp_mul_karatsuba_case
(xp, rp, rsize, bp, bsize,
&karactx) < 0)
goto enomem;
}
xsize = rsize + bsize;
if (xsize > msize) {
mpihelp_divrem(xp + msize, 0,
xp, xsize, mp,
msize);
xsize = msize;
}
tp = rp;
rp = xp;
xp = tp;
rsize = xsize;
}
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 =
mpihelp_lshift(res->d, rp, rsize, mod_shift_cnt);
rp = res->d;
if (carry_limb) {
rp[rsize] = carry_limb;
rsize++;
}
} else {
MPN_COPY(res->d, rp, rsize);
rp = res->d;
}
if (rsize >= msize) {
mpihelp_divrem(rp + msize, 0, rp, rsize, mp, msize);
rsize = msize;
}
/* Remove any leading zero words from the result. */
if (mod_shift_cnt)
mpihelp_rshift(rp, rp, rsize, mod_shift_cnt);
MPN_NORMALIZE(rp, rsize);
mpihelp_release_karatsuba_ctx(&karactx);
}
if (negative_result && rsize) {
if (mod_shift_cnt)
mpihelp_rshift(mp, mp, msize, mod_shift_cnt);
mpihelp_sub(rp, mp, msize, rp, rsize);
rsize = msize;
rsign = msign;
MPN_NORMALIZE(rp, rsize);
}
res->nlimbs = rsize;
res->sign = rsign;
leave:
rc = 0;
enomem:
if (assign_rp)
mpi_assign_limb_space(res, rp, size);
if (mp_marker)
mpi_free_limb_space(mp_marker);
if (bp_marker)
mpi_free_limb_space(bp_marker);
if (ep_marker)
mpi_free_limb_space(ep_marker);
if (xp_marker)
mpi_free_limb_space(xp_marker);
if (tspace)
mpi_free_limb_space(tspace);
return rc;
}
EXPORT_SYMBOL_GPL(mpi_powm);
/* mpi-scan.c - MPI functions
* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include "mpi-internal.h"
#include "longlong.h"
/****************
* Scan through an mpi and return byte for byte. a -1 is returned to indicate
* the end of the mpi. Scanning is done from the lsb to the msb, returned
* values are in the range of 0 .. 255.
*
* FIXME: This code is VERY ugly!
*/
int mpi_getbyte(const MPI a, unsigned idx)
{
int i, j;
unsigned n;
mpi_ptr_t ap;
mpi_limb_t limb;
ap = a->d;
for (n = 0, i = 0; i < a->nlimbs; i++) {
limb = ap[i];
for (j = 0; j < BYTES_PER_MPI_LIMB; j++, n++)
if (n == idx)
return (limb >> j * 8) & 0xff;
}
return -1;
}
/****************
* Put a value at position IDX into A. idx counts from lsb to msb
*/
void mpi_putbyte(MPI a, unsigned idx, int xc)
{
int i, j;
unsigned n;
mpi_ptr_t ap;
mpi_limb_t limb, c;
c = xc & 0xff;
ap = a->d;
for (n = 0, i = 0; i < a->alloced; i++) {
limb = ap[i];
for (j = 0; j < BYTES_PER_MPI_LIMB; j++, n++)
if (n == idx) {
#if BYTES_PER_MPI_LIMB == 4
if (j == 0)
limb = (limb & 0xffffff00) | c;
else if (j == 1)
limb = (limb & 0xffff00ff) | (c << 8);
else if (j == 2)
limb = (limb & 0xff00ffff) | (c << 16);
else
limb = (limb & 0x00ffffff) | (c << 24);
#elif BYTES_PER_MPI_LIMB == 8
if (j == 0)
limb = (limb & 0xffffffffffffff00) | c;
else if (j == 1)
limb =
(limb & 0xffffffffffff00ff) | (c <<
8);
else if (j == 2)
limb =
(limb & 0xffffffffff00ffff) | (c <<
16);
else if (j == 3)
limb =
(limb & 0xffffffff00ffffff) | (c <<
24);
else if (j == 4)
limb =
(limb & 0xffffff00ffffffff) | (c <<
32);
else if (j == 5)
limb =
(limb & 0xffff00ffffffffff) | (c <<
40);
else if (j == 6)
limb =
(limb & 0xff00ffffffffffff) | (c <<
48);
else
limb =
(limb & 0x00ffffffffffffff) | (c <<
56);
#else
#error please enhance this function, its ugly - i know.
#endif
if (a->nlimbs <= i)
a->nlimbs = i + 1;
ap[i] = limb;
return;
}
}
log_bug("index out of range\n");
}
/****************
* Count the number of zerobits at the low end of A
*/
unsigned mpi_trailing_zeros(const MPI a)
{
unsigned n, count = 0;
for (n = 0; n < a->nlimbs; n++) {
if (a->d[n]) {
unsigned nn;
mpi_limb_t alimb = a->d[n];
count_trailing_zeros(nn, alimb);
count += nn;
break;
}
count += BITS_PER_MPI_LIMB;
}
return count;
}
This diff is collapsed.
/* mpihelp-sub.c - MPI helper functions
* Copyright (C) 1994, 1996 Free Software Foundation, Inc.
* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* 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.
* The GNU MP Library itself is published under the LGPL;
* however I decided to publish this code under the plain GPL.
*/
#include "mpi-internal.h"
/****************
* Compare OP1_PTR/OP1_SIZE with OP2_PTR/OP2_SIZE.
* There are no restrictions on the relative sizes of
* the two arguments.
* Return 1 if OP1 > OP2, 0 if they are equal, and -1 if OP1 < OP2.
*/
int mpihelp_cmp(mpi_ptr_t op1_ptr, mpi_ptr_t op2_ptr, mpi_size_t size)
{
mpi_size_t i;
mpi_limb_t op1_word, op2_word;
for (i = size - 1; i >= 0; i--) {
op1_word = op1_ptr[i];
op2_word = op2_ptr[i];
if (op1_word != op2_word)
goto diff;
}
return 0;
diff:
/* This can *not* be simplified to
* op2_word - op2_word
* since that expression might give signed overflow. */
return (op1_word > op2_word) ? 1 : -1;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -3,5 +3,19 @@ config INTEGRITY
def_bool y
depends on IMA || EVM
config INTEGRITY_DIGSIG
boolean "Digital signature verification using multiple keyrings"
depends on INTEGRITY
default n
select DIGSIG
help
This option enables digital signature verification support
using multiple keyrings. It defines separate keyrings for each
of the different use cases - evm, ima, and modules.
Different keyrings improves search performance, but also allow
to "lock" certain keyring to prevent adding new keys.
This is useful for evm and module keyrings, when keys are
usually only added from initramfs.
source security/integrity/ima/Kconfig
source security/integrity/evm/Kconfig
......@@ -3,6 +3,7 @@
#
obj-$(CONFIG_INTEGRITY) += integrity.o
obj-$(CONFIG_INTEGRITY_DIGSIG) += digsig.o
integrity-y := iint.o
......
This diff is collapsed.
......@@ -12,14 +12,21 @@
* File: evm.h
*
*/
#ifndef __INTEGRITY_EVM_H
#define __INTEGRITY_EVM_H
#include <linux/xattr.h>
#include <linux/security.h>
#include "../integrity.h"
extern int evm_initialized;
extern char *evm_hmac;
extern char *evm_hash;
extern struct crypto_shash *hmac_tfm;
extern struct crypto_shash *hash_tfm;
/* List of EVM protected security xattrs */
extern char *evm_config_xattrnames[];
......@@ -32,7 +39,12 @@ extern int evm_update_evmxattr(struct dentry *dentry,
extern int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
const char *req_xattr_value,
size_t req_xattr_value_len, char *digest);
extern int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
const char *req_xattr_value,
size_t req_xattr_value_len, char *digest);
extern int evm_init_hmac(struct inode *inode, const struct xattr *xattr,
char *hmac_val);
extern int evm_init_secfs(void);
extern void evm_cleanup_secfs(void);
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment