diff --git a/crypto/external/bsd/netpgp/Makefile b/crypto/external/bsd/netpgp/Makefile index 240ccb16a933..c8e6ca2ece20 100644 --- a/crypto/external/bsd/netpgp/Makefile +++ b/crypto/external/bsd/netpgp/Makefile @@ -1,8 +1,9 @@ -# $NetBSD: Makefile,v 1.5 2010/09/02 06:00:11 agc Exp $ +# $NetBSD: Makefile,v 1.6 2012/11/20 05:26:24 agc Exp $ SUBDIR= libmj .WAIT +SUBDIR+= lib/verify .WAIT SUBDIR+= lib .WAIT -SUBDIR+= netpgp netpgpkeys netpgpverify +SUBDIR+= netpgp netpgpkeys bin #SUBDIR+= hkpc hkpd .include diff --git a/crypto/external/bsd/netpgp/bin/Makefile b/crypto/external/bsd/netpgp/bin/Makefile new file mode 100644 index 000000000000..fc5078d4296d --- /dev/null +++ b/crypto/external/bsd/netpgp/bin/Makefile @@ -0,0 +1,5 @@ +# $NetBSD: Makefile,v 1.4 2012/11/20 05:26:25 agc Exp $ + +SUBDIR+= netpgpverify + +.include diff --git a/crypto/external/bsd/netpgp/bin/netpgpverify/Makefile b/crypto/external/bsd/netpgp/bin/netpgpverify/Makefile new file mode 100644 index 000000000000..6ea30ee739d5 --- /dev/null +++ b/crypto/external/bsd/netpgp/bin/netpgpverify/Makefile @@ -0,0 +1,119 @@ +# $NetBSD: Makefile,v 1.2 2012/11/20 05:26:25 agc Exp $ + +.include + +PROG=netpgpverify +SRCS+=main.c +BINDIR=/usr/bin + +WARNS=5 +MAN=netpgpverify.1 + +CPPFLAGS+=-I${EXTDIST}/libverify + +LIBNETPGPVERIFYDIR!= cd ${.CURDIR}/../../lib/verify && ${PRINTOBJDIR} +LDADD+= -L${LIBNETPGPVERIFYDIR} -lnetpgpverify +DPADD+= ${LIBNETPGPVERIFYDIR}/libnetpgpverify.a + +LDADD+= -lz -lbz2 +DPADD+= ${LIBZ} ${LIBBZ2} + +EXTDIST= ${.CURDIR}/../../dist/src +.PATH: ${EXTDIST}/netpgpverify + +.include + +t: ${PROG} + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} -c verify b.gpg > output16 + diff expected16 output16 + rm -f output16 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} -c verify a.gpg > output17 + diff expected17 output17 + rm -f output17 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} -c verify gpgsigned-a.gpg > output18 + diff expected18 output18 + rm -f output18 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} -c verify NetBSD-6.0_RC2_hashes.asc > output19 + diff expected19 output19 + rm -f output19 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} -c cat jj.asc > output20 + diff expected20 output20 + rm -f output20 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} < a.gpg > output21 + diff expected21 output21 + rm -f output21 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} < jj.asc > output22 + diff expected22 output22 + rm -f output22 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} < NetBSD-6.0_RC2_hashes.asc > output23 + diff expected23 output23 + rm -f output23 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} < b.gpg > output24 + diff expected24 output24 + rm -f output24 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} NetBSD-6.0_RC1_hashes.gpg > output25 + diff expected25 output25 + rm -f output25 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} < NetBSD-6.0_RC1_hashes.gpg > output26 + diff expected26 output26 + rm -f output26 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} < NetBSD-6.0_hashes.asc > output27 + diff expected27 output27 + rm -f output27 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} NetBSD-6.0_hashes.asc > output28 + diff expected28 output28 + rm -f output28 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} NetBSD-6.0_RC1_hashes_ascii.gpg > output29 + diff expected29 output29 + rm -f output29 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} < NetBSD-6.0_RC1_hashes_ascii.gpg > output30 + diff expected30 output30 + rm -f output30 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} -c cat b.gpg b.gpg b.gpg > output31 + diff expected31 output31 + rm -f output31 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} b.gpg b.gpg b.gpg > output32 + diff expected32 output32 + rm -f output32 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} -c cat b.gpg jj.asc b.gpg > output33 + diff expected33 output33 + rm -f output33 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} det.sig > output34 + diff expected34 output34 + rm -f output34 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} -c cat det.sig > output35 + diff expected35 output35 + rm -f output35 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} -k dsa-pubring.gpg in1.gpg > output36 + diff expected36 output36 + rm -f output36 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} -k dsa-pubring.gpg < in1.gpg > output37 + diff expected37 output37 + rm -f output37 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} -k dsa-pubring.gpg in1.asc > output38 + diff expected38 output38 + rm -f output38 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} -k dsa-pubring.gpg < in1.asc > output39 + diff expected39 output39 + rm -f output39 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} -k dsa-pubring.gpg -c cat in1.gpg > output40 + diff expected40 output40 + rm -f output40 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} -k dsa-pubring.gpg -c cat < in1.gpg > output41 + diff expected41 output41 + rm -f output41 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} -k dsa-pubring.gpg -c cat in1.asc > output42 + diff expected42 output42 + rm -f output42 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} -k dsa-pubring.gpg -c cat < in1.asc > output43 + diff expected43 output43 + rm -f output43 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} -k dsa-pubring.gpg in2.gpg > output44 + diff expected44 output44 + rm -f output44 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} -k dsa-pubring.gpg in2.asc > output45 + diff expected45 output45 + rm -f output45 + env LD_LIBRARY_PATH=${LIBNETPGPVERIFYDIR} ./${PROG} -k problem-pubring.gpg NetBSD-6.0_hashes.asc > output46 + diff expected46 output46 + rm -f output46 diff --git a/crypto/external/bsd/netpgp/dist/src/libbn/Makefile b/crypto/external/bsd/netpgp/dist/src/libbn/Makefile new file mode 100644 index 000000000000..4c7c15c274c0 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libbn/Makefile @@ -0,0 +1,13 @@ +LIB=netbn +SRCS= bignum.c digest.c misc.c rand.c +SRCS+= stubs.c +MKMAN=no +WARNS=4 +CPPFLAGS+=-I${EXTDIST} + +INCS=bn.h digest.h +INCSDIR=/usr/include/netpgp + +EXTDIST= ${.CURDIR}/../cipher + +.include diff --git a/crypto/external/bsd/netpgp/dist/src/libbn/bignum.c b/crypto/external/bsd/netpgp/dist/src/libbn/bignum.c new file mode 100644 index 000000000000..f9d9a11eeed4 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libbn/bignum.c @@ -0,0 +1,5635 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + */ +#include +#include +#include + +#ifdef _KERNEL +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include "misc.h" +#include "bn.h" +#include "digest.h" + +/**************************************************************************/ + +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + */ + +#define MP_PREC 32 +#define DIGIT_BIT 60 +#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1)) + +#define MP_WARRAY /*LINTED*/(1U << (((sizeof(mp_word) * CHAR_BIT) - (2 * DIGIT_BIT) + 1))) + +#define MP_NO 0 +#define MP_YES 1 + +#ifndef USE_ARG +#define USE_ARG(x) /*LINTED*/(void)&(x) +#endif + +#ifndef __arraycount +#define __arraycount(__x) (sizeof(__x) / sizeof(__x[0])) +#endif + +#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO) + +#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1) + +typedef int mp_err; + +static int mp_mul(mp_int * a, mp_int * b, mp_int * c); +static int mp_sqr(mp_int * a, mp_int * b); + +static int mp_sub_d(mp_int *a, mp_digit b, mp_int *c); + +/* set to zero */ +static void +mp_zero(mp_int *a) +{ + int n; + mp_digit *tmp; + + a->sign = MP_ZPOS; + a->used = 0; + + tmp = a->dp; + /* XXX - memset */ + for (n = 0; n < a->alloc; n++) { + *tmp++ = 0; + } +} + +/* grow as required */ +static int +mp_grow(mp_int *a, int size) +{ + int i; + mp_digit *tmp; + + /* if the alloc size is smaller alloc more ram */ + if (a->alloc < size) { + /* ensure there are always at least MP_PREC digits extra on top */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* reallocate the array a->dp + * + * We store the return in a temporary variable + * in case the operation failed we don't want + * to overwrite the dp member of a. + */ + tmp = realloc(a->dp, sizeof(*tmp) * size); + if (tmp == NULL) { + /* reallocation failed but "a" is still valid [can be freed] */ + return MP_MEM; + } + + /* reallocation succeeded so set a->dp */ + a->dp = tmp; + + /* zero excess digits */ + i = a->alloc; + a->alloc = size; + for (; i < a->alloc; i++) { + a->dp[i] = 0; + } + } + return MP_OKAY; +} + +/* shift left a certain amount of digits */ +static int +mp_lshd (mp_int * a, int b) +{ + int x, res; + + /* if its less than zero return */ + if (b <= 0) { + return MP_OKAY; + } + + /* grow to fit the new digits */ + if (a->alloc < a->used + b) { + if ((res = mp_grow (a, a->used + b)) != MP_OKAY) { + return res; + } + } + + { + mp_digit *top, *bottom; + + /* increment the used by the shift amount then copy upwards */ + a->used += b; + + /* top */ + top = a->dp + a->used - 1; + + /* base */ + bottom = a->dp + a->used - 1 - b; + + /* much like mp_rshd this is implemented using a sliding window + * except the window goes the otherway around. Copying from + * the bottom to the top. see bn_mp_rshd.c for more info. + */ + for (x = a->used - 1; x >= b; x--) { + *top-- = *bottom--; + } + + /* zero the lower digits */ + top = a->dp; + for (x = 0; x < b; x++) { + *top++ = 0; + } + } + return MP_OKAY; +} + +/* trim unused digits + * + * This is used to ensure that leading zero digits are + * trimed and the leading "used" digit will be non-zero + * Typically very fast. Also fixes the sign if there + * are no more leading digits + */ +static void +mp_clamp (mp_int * a) +{ + /* decrease used while the most significant digit is + * zero. + */ + while (a->used > 0 && a->dp[a->used - 1] == 0) { + --(a->used); + } + + /* reset the sign flag if used == 0 */ + if (a->used == 0) { + a->sign = MP_ZPOS; + } +} + +/* copy, b = a */ +static int +mp_copy(BIGNUM *a, BIGNUM *b) +{ + int res, n; + + /* if dst == src do nothing */ + if (a == b) { + return MP_OKAY; + } + if (a == NULL || b == NULL) { + return MP_VAL; + } + + /* grow dest */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + /* zero b and copy the parameters over */ + { + mp_digit *tmpa, *tmpb; + + /* pointer aliases */ + + /* source */ + tmpa = a->dp; + + /* destination */ + tmpb = b->dp; + + /* copy all the digits */ + for (n = 0; n < a->used; n++) { + *tmpb++ = *tmpa++; + } + + /* clear high digits */ + for (; n < b->used; n++) { + *tmpb++ = 0; + } + } + + /* copy used count and sign */ + b->used = a->used; + b->sign = a->sign; + return MP_OKAY; +} + +/* shift left by a certain bit count */ +static int +mp_mul_2d(mp_int *a, int b, mp_int *c) +{ + mp_digit d; + int res; + + /* copy */ + if (a != c) { + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + } + + if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) { + if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) { + return res; + } + } + + /* shift any bit count < DIGIT_BIT */ + d = (mp_digit) (b % DIGIT_BIT); + if (d != 0) { + mp_digit *tmpc, shift, mask, r, rr; + int x; + + /* bitmask for carries */ + mask = (((mp_digit)1) << d) - 1; + + /* shift for msbs */ + shift = DIGIT_BIT - d; + + /* alias */ + tmpc = c->dp; + + /* carry */ + r = 0; + for (x = 0; x < c->used; x++) { + /* get the higher bits of the current word */ + rr = (*tmpc >> shift) & mask; + + /* shift the current word and OR in the carry */ + *tmpc = ((*tmpc << d) | r) & MP_MASK; + ++tmpc; + + /* set the carry to the carry bits of the current word */ + r = rr; + } + + /* set final carry */ + if (r != 0) { + c->dp[(c->used)++] = r; + } + } + mp_clamp (c); + return MP_OKAY; +} + +/* reads a unsigned char array, assumes the msb is stored first [big endian] */ +static int +mp_read_unsigned_bin(mp_int *a, const uint8_t *b, int c) +{ + int res; + + /* make sure there are at least two digits */ + if (a->alloc < 2) { + if ((res = mp_grow(a, 2)) != MP_OKAY) { + return res; + } + } + + /* zero the int */ + mp_zero (a); + + /* read the bytes in */ + while (c-- > 0) { + if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) { + return res; + } + + a->dp[0] |= *b++; + a->used += 1; + } + mp_clamp (a); + return MP_OKAY; +} + +/* returns the number of bits in an int */ +static int +mp_count_bits(const mp_int *a) +{ + int r; + mp_digit q; + + /* shortcut */ + if (a->used == 0) { + return 0; + } + + /* get number of digits and add that */ + r = (a->used - 1) * DIGIT_BIT; + + /* take the last digit and count the bits in it */ + q = a->dp[a->used - 1]; + while (q > ((mp_digit) 0)) { + ++r; + q >>= ((mp_digit) 1); + } + return r; +} + +/* compare maginitude of two ints (unsigned) */ +static int +mp_cmp_mag (mp_int * a, mp_int * b) +{ + int n; + mp_digit *tmpa, *tmpb; + + /* compare based on # of non-zero digits */ + if (a->used > b->used) { + return MP_GT; + } + + if (a->used < b->used) { + return MP_LT; + } + + /* alias for a */ + tmpa = a->dp + (a->used - 1); + + /* alias for b */ + tmpb = b->dp + (a->used - 1); + + /* compare based on digits */ + for (n = 0; n < a->used; ++n, --tmpa, --tmpb) { + if (*tmpa > *tmpb) { + return MP_GT; + } + + if (*tmpa < *tmpb) { + return MP_LT; + } + } + return MP_EQ; +} + +/* compare two ints (signed)*/ +static int +mp_cmp (mp_int * a, mp_int * b) +{ + /* compare based on sign */ + if (a->sign != b->sign) { + if (a->sign == MP_NEG) { + return MP_LT; + } else { + return MP_GT; + } + } + + /* compare digits */ + if (a->sign == MP_NEG) { + /* if negative compare opposite direction */ + return mp_cmp_mag(b, a); + } else { + return mp_cmp_mag(a, b); + } +} + +/* get the size for an unsigned equivalent */ +static int +mp_unsigned_bin_size (mp_int * a) +{ + int size = mp_count_bits (a); + return (size / 8 + ((size & 7) != 0 ? 1 : 0)); +} + +/* init a new mp_int */ +static int +mp_init (mp_int * a) +{ + int i; + + /* allocate memory required and clear it */ + a->dp = netpgp_allocate(1, sizeof (*a->dp) * MP_PREC); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the digits to zero */ + for (i = 0; i < MP_PREC; i++) { + a->dp[i] = 0; + } + + /* set the used to zero, allocated digits to the default precision + * and sign to positive */ + a->used = 0; + a->alloc = MP_PREC; + a->sign = MP_ZPOS; + + return MP_OKAY; +} + +/* clear one (frees) */ +static void +mp_clear (mp_int * a) +{ + int i; + + /* only do anything if a hasn't been freed previously */ + if (a->dp != NULL) { + /* first zero the digits */ + for (i = 0; i < a->used; i++) { + a->dp[i] = 0; + } + + /* free ram */ + netpgp_deallocate(a->dp, a->alloc); + + /* reset members to make debugging easier */ + a->dp = NULL; + a->alloc = a->used = 0; + a->sign = MP_ZPOS; + } +} + +static int +mp_init_multi(mp_int *mp, ...) +{ + mp_err res = MP_OKAY; /* Assume ok until proven otherwise */ + int n = 0; /* Number of ok inits */ + mp_int* cur_arg = mp; + va_list args; + + va_start(args, mp); /* init args to next argument from caller */ + while (cur_arg != NULL) { + if (mp_init(cur_arg) != MP_OKAY) { + /* Oops - error! Back-track and mp_clear what we already + succeeded in init-ing, then return error. + */ + va_list clean_args; + + /* end the current list */ + va_end(args); + + /* now start cleaning up */ + cur_arg = mp; + va_start(clean_args, mp); + while (n--) { + mp_clear(cur_arg); + cur_arg = va_arg(clean_args, mp_int*); + } + va_end(clean_args); + res = MP_MEM; + break; + } + n++; + cur_arg = va_arg(args, mp_int*); + } + va_end(args); + return res; /* Assumed ok, if error flagged above. */ +} + +/* init an mp_init for a given size */ +static int +mp_init_size (mp_int * a, int size) +{ + int x; + + /* pad size so there are always extra digits */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* alloc mem */ + a->dp = netpgp_allocate (1, sizeof (*a->dp) * size); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the members */ + a->used = 0; + a->alloc = size; + a->sign = MP_ZPOS; + + /* zero the digits */ + for (x = 0; x < size; x++) { + a->dp[x] = 0; + } + + return MP_OKAY; +} + +/* creates "a" then copies b into it */ +static int mp_init_copy (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_init (a)) != MP_OKAY) { + return res; + } + return mp_copy (b, a); +} + +/* low level addition, based on HAC pp.594, Algorithm 14.7 */ +static int +s_mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int *x; + int olduse, res, min, max; + + /* find sizes, we let |a| <= |b| which means we have to sort + * them. "x" will point to the input with the most digits + */ + if (a->used > b->used) { + min = b->used; + max = a->used; + x = a; + } else { + min = a->used; + max = b->used; + x = b; + } + + /* init result */ + if (c->alloc < max + 1) { + if ((res = mp_grow (c, max + 1)) != MP_OKAY) { + return res; + } + } + + /* get old used digit count and set new one */ + olduse = c->used; + c->used = max + 1; + + { + mp_digit u, *tmpa, *tmpb, *tmpc; + int i; + + /* alias for digit pointers */ + + /* first input */ + tmpa = a->dp; + + /* second input */ + tmpb = b->dp; + + /* destination */ + tmpc = c->dp; + + /* zero the carry */ + u = 0; + for (i = 0; i < min; i++) { + /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ + *tmpc = *tmpa++ + *tmpb++ + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, that is in A+B + * if A or B has more digits add those in + */ + if (min != max) { + for (; i < max; i++) { + /* T[i] = X[i] + U */ + *tmpc = x->dp[i] + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + } + + /* add carry */ + *tmpc++ = u; + + /* clear digits above oldused */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + +/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ +static int +s_mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int olduse, res, min, max; + + /* find sizes */ + min = b->used; + max = a->used; + + /* init result */ + if (c->alloc < max) { + if ((res = mp_grow (c, max)) != MP_OKAY) { + return res; + } + } + olduse = c->used; + c->used = max; + + { + mp_digit u, *tmpa, *tmpb, *tmpc; + int i; + + /* alias for digit pointers */ + tmpa = a->dp; + tmpb = b->dp; + tmpc = c->dp; + + /* set carry to zero */ + u = 0; + for (i = 0; i < min; i++) { + /* T[i] = A[i] - B[i] - U */ + *tmpc = *tmpa++ - *tmpb++ - u; + + /* U = carry bit of T[i] + * Note this saves performing an AND operation since + * if a carry does occur it will propagate all the way to the + * MSB. As a result a single shift is enough to get the carry + */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, e.g. if A has more digits than B */ + for (; i < max; i++) { + /* T[i] = A[i] - U */ + *tmpc = *tmpa++ - u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* clear digits above used (since we may not have grown result above) */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + +/* high level subtraction (handles signs) */ +static int +mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + sa = a->sign; + sb = b->sign; + + if (sa != sb) { + /* subtract a negative from a positive, OR */ + /* subtract a positive from a negative. */ + /* In either case, ADD their magnitudes, */ + /* and use the sign of the first number. */ + c->sign = sa; + res = s_mp_add (a, b, c); + } else { + /* subtract a positive from a positive, OR */ + /* subtract a negative from a negative. */ + /* First, take the difference between their */ + /* magnitudes, then... */ + if (mp_cmp_mag (a, b) != MP_LT) { + /* Copy the sign from the first */ + c->sign = sa; + /* The first has a larger or equal magnitude */ + res = s_mp_sub (a, b, c); + } else { + /* The result has the *opposite* sign from */ + /* the first number. */ + c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS; + /* The second has a larger magnitude */ + res = s_mp_sub (b, a, c); + } + } + return res; +} + +/* shift right a certain amount of digits */ +static int mp_rshd (mp_int * a, int b) +{ + int x; + + /* if b <= 0 then ignore it */ + if (b <= 0) { + return 0; + } + + /* if b > used then simply zero it and return */ + if (a->used <= b) { + mp_zero (a); + return 0; + } + + { + mp_digit *bottom, *top; + + /* shift the digits down */ + + /* bottom */ + bottom = a->dp; + + /* top [offset into digits] */ + top = a->dp + b; + + /* this is implemented as a sliding window where + * the window is b-digits long and digits from + * the top of the window are copied to the bottom + * + * e.g. + + b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> + /\ | ----> + \-------------------/ ----> + */ + for (x = 0; x < (a->used - b); x++) { + *bottom++ = *top++; + } + + /* zero the top digits */ + for (; x < a->used; x++) { + *bottom++ = 0; + } + } + + /* remove excess digits */ + a->used -= b; + return 1; +} + +/* multiply by a digit */ +static int +mp_mul_d (mp_int * a, mp_digit b, mp_int * c) +{ + mp_digit u, *tmpa, *tmpc; + mp_word r; + int ix, res, olduse; + + /* make sure c is big enough to hold a*b */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* get the original destinations used count */ + olduse = c->used; + + /* set the sign */ + c->sign = a->sign; + + /* alias for a->dp [source] */ + tmpa = a->dp; + + /* alias for c->dp [dest] */ + tmpc = c->dp; + + /* zero carry */ + u = 0; + + /* compute columns */ + for (ix = 0; ix < a->used; ix++) { + /* compute product and carry sum for this term */ + r = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b); + + /* mask off higher bits to get a single digit */ + *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* send carry into next iteration */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + + /* store final carry [if any] and increment ix offset */ + *tmpc++ = u; + ++ix; + + /* now zero digits above the top */ + while (ix++ < olduse) { + *tmpc++ = 0; + } + + /* set used count */ + c->used = a->used + 1; + mp_clamp(c); + + return MP_OKAY; +} + +/* high level addition (handles signs) */ +static int mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + /* get sign of both inputs */ + sa = a->sign; + sb = b->sign; + + /* handle two cases, not four */ + if (sa == sb) { + /* both positive or both negative */ + /* add their magnitudes, copy the sign */ + c->sign = sa; + res = s_mp_add (a, b, c); + } else { + /* one positive, the other negative */ + /* subtract the one with the greater magnitude from */ + /* the one of the lesser magnitude. The result gets */ + /* the sign of the one with the greater magnitude. */ + if (mp_cmp_mag (a, b) == MP_LT) { + c->sign = sb; + res = s_mp_sub (b, a, c); + } else { + c->sign = sa; + res = s_mp_sub (a, b, c); + } + } + return res; +} + +/* swap the elements of two integers, for cases where you can't simply swap the + * mp_int pointers around + */ +static void +mp_exch(mp_int *a, mp_int *b) +{ + mp_int t; + + t = *a; + *a = *b; + *b = t; +} + +/* calc a value mod 2**b */ +static int +mp_mod_2d (mp_int * a, int b, mp_int * c) +{ + int x, res; + + /* if b is <= 0 then zero the int */ + if (b <= 0) { + mp_zero (c); + return MP_OKAY; + } + + /* if the modulus is larger than the value than return */ + if (b >= (int) (a->used * DIGIT_BIT)) { + res = mp_copy (a, c); + return res; + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + + /* zero digits above the last digit of the modulus */ + for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) { + c->dp[x] = 0; + } + /* clear the digit that is not completely outside/inside the modulus */ + c->dp[b / DIGIT_BIT] &= + (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1)); + mp_clamp (c); + return MP_OKAY; +} + +/* shift right by a certain bit count (store quotient in c, optional remainder in d) */ +static int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) +{ + mp_digit D, r, rr; + int x, res; + mp_int t; + + + /* if the shift count is <= 0 then we do no work */ + if (b <= 0) { + res = mp_copy (a, c); + if (d != NULL) { + mp_zero (d); + } + return res; + } + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + /* get the remainder */ + if (d != NULL) { + if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + mp_rshd (c, b / DIGIT_BIT); + } + + /* shift any bit count < DIGIT_BIT */ + D = (mp_digit) (b % DIGIT_BIT); + if (D != 0) { + mp_digit *tmpc, mask, shift; + + /* mask */ + mask = (((mp_digit)1) << D) - 1; + + /* shift for lsb */ + shift = DIGIT_BIT - D; + + /* alias */ + tmpc = c->dp + (c->used - 1); + + /* carry */ + r = 0; + for (x = c->used - 1; x >= 0; x--) { + /* get the lower bits of this word in a temp */ + rr = *tmpc & mask; + + /* shift the current word and mix in the carry bits from the previous word */ + *tmpc = (*tmpc >> D) | (r << shift); + --tmpc; + + /* set the carry to the carry bits of the current word found above */ + r = rr; + } + } + mp_clamp (c); + if (d != NULL) { + mp_exch (&t, d); + } + mp_clear (&t); + return MP_OKAY; +} + +/* integer signed division. + * c*b + d == a [e.g. a/b, c=quotient, d=remainder] + * HAC pp.598 Algorithm 14.20 + * + * Note that the description in HAC is horribly + * incomplete. For example, it doesn't consider + * the case where digits are removed from 'x' in + * the inner loop. It also doesn't consider the + * case that y has fewer than three digits, etc.. + * + * The overall algorithm is as described as + * 14.20 from HAC but fixed to treat these cases. +*/ +static int +mp_div(mp_int *c, mp_int *d, mp_int *a, mp_int *b) +{ + mp_int q, x, y, t1, t2; + int res, n, t, i, norm, neg; + + /* is divisor zero ? */ + if (BN_is_zero (b) == 1) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag (a, b) == MP_LT) { + if (d != NULL) { + res = mp_copy (a, d); + } else { + res = MP_OKAY; + } + if (c != NULL) { + mp_zero (c); + } + return res; + } + + if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) { + return res; + } + q.used = a->used + 2; + + if ((res = mp_init (&t1)) != MP_OKAY) { + goto LBL_Q; + } + + if ((res = mp_init (&t2)) != MP_OKAY) { + goto LBL_T1; + } + + if ((res = mp_init_copy (&x, a)) != MP_OKAY) { + goto LBL_T2; + } + + if ((res = mp_init_copy (&y, b)) != MP_OKAY) { + goto LBL_X; + } + + /* fix the sign */ + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + x.sign = y.sign = MP_ZPOS; + + /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */ + norm = mp_count_bits(&y) % DIGIT_BIT; + if (norm < (int)(DIGIT_BIT-1)) { + norm = (DIGIT_BIT-1) - norm; + if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) { + goto LBL_Y; + } + } else { + norm = 0; + } + + /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */ + n = x.used - 1; + t = y.used - 1; + + /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */ + if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */ + goto LBL_Y; + } + + while (mp_cmp (&x, &y) != MP_LT) { + ++(q.dp[n - t]); + if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) { + goto LBL_Y; + } + } + + /* reset y by shifting it back down */ + mp_rshd (&y, n - t); + + /* step 3. for i from n down to (t + 1) */ + for (i = n; i >= (t + 1); i--) { + if (i > x.used) { + continue; + } + + /* step 3.1 if xi == yt then set q{i-t-1} to b-1, + * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */ + if (x.dp[i] == y.dp[t]) { + q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1); + } else { + mp_word tmp; + tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT); + tmp |= ((mp_word) x.dp[i - 1]); + tmp /= ((mp_word) y.dp[t]); + if (tmp > (mp_word) MP_MASK) + tmp = MP_MASK; + q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK)); + } + + /* while (q{i-t-1} * (yt * b + y{t-1})) > + xi * b**2 + xi-1 * b + xi-2 + + do q{i-t-1} -= 1; + */ + q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK; + do { + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK; + + /* find left hand */ + mp_zero (&t1); + t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; + t1.dp[1] = y.dp[t]; + t1.used = 2; + if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto LBL_Y; + } + + /* find right hand */ + t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2]; + t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1]; + t2.dp[2] = x.dp[i]; + t2.used = 3; + } while (mp_cmp_mag(&t1, &t2) == MP_GT); + + /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */ + if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) { + goto LBL_Y; + } + + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto LBL_Y; + } + + if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) { + goto LBL_Y; + } + + /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */ + if (x.sign == MP_NEG) { + if ((res = mp_copy (&y, &t1)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) { + goto LBL_Y; + } + if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) { + goto LBL_Y; + } + + q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK; + } + } + + /* now q is the quotient and x is the remainder + * [which we have to normalize] + */ + + /* get sign before writing to c */ + x.sign = x.used == 0 ? MP_ZPOS : a->sign; + + if (c != NULL) { + mp_clamp (&q); + mp_exch (&q, c); + c->sign = neg; + } + + if (d != NULL) { + mp_div_2d (&x, norm, &x, NULL); + mp_exch (&x, d); + } + + res = MP_OKAY; + +LBL_Y:mp_clear (&y); +LBL_X:mp_clear (&x); +LBL_T2:mp_clear (&t2); +LBL_T1:mp_clear (&t1); +LBL_Q:mp_clear (&q); + return res; +} + +/* c = a mod b, 0 <= c < b */ +static int +mp_mod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int t; + int res; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_div (NULL, &t, a, b)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + if (t.sign != b->sign) { + res = mp_add (b, &t, c); + } else { + res = MP_OKAY; + mp_exch (&t, c); + } + + mp_clear (&t); + return res; +} + +/* set to a digit */ +static void mp_set (mp_int * a, mp_digit b) +{ + mp_zero (a); + a->dp[0] = b & MP_MASK; + a->used = (a->dp[0] != 0) ? 1 : 0; +} + +/* b = a/2 */ +static int mp_div_2(mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* copy */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + { + mp_digit r, rr, *tmpa, *tmpb; + + /* source alias */ + tmpa = a->dp + b->used - 1; + + /* dest alias */ + tmpb = b->dp + b->used - 1; + + /* carry */ + r = 0; + for (x = b->used - 1; x >= 0; x--) { + /* get the carry for the next iteration */ + rr = *tmpa & 1; + + /* shift the current digit, add in carry and store */ + *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); + + /* forward carry to next iteration */ + r = rr; + } + + /* zero excess digits */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + mp_clamp (b); + return MP_OKAY; +} + +/* compare a digit */ +static int mp_cmp_d(mp_int * a, mp_digit b) +{ + /* compare based on sign */ + if (a->sign == MP_NEG) { + return MP_LT; + } + + /* compare based on magnitude */ + if (a->used > 1) { + return MP_GT; + } + + /* compare the only digit of a to b */ + if (a->dp[0] > b) { + return MP_GT; + } else if (a->dp[0] < b) { + return MP_LT; + } else { + return MP_EQ; + } +} + +static void mp_clear_multi(mp_int *mp, ...) +{ + mp_int* next_mp = mp; + va_list args; + va_start(args, mp); + while (next_mp != NULL) { + mp_clear(next_mp); + next_mp = va_arg(args, mp_int*); + } + va_end(args); +} + +/* computes the modular inverse via binary extended euclidean algorithm, + * that is c = 1/a mod b + * + * Based on slow invmod except this is optimized for the case where b is + * odd as per HAC Note 14.64 on pp. 610 + */ +static int +fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, B, D; + int res, neg; + + /* 2. [modified] b must be odd */ + if (BN_is_even (b) == 1) { + return MP_VAL; + } + + /* init all our temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, &B, &D, NULL)) != MP_OKAY) { + return res; + } + + /* x == modulus, y == value to invert */ + if ((res = mp_copy (b, &x)) != MP_OKAY) { + goto LBL_ERR; + } + + /* we need y = |a| */ + if ((res = mp_mod (a, b, &y)) != MP_OKAY) { + goto LBL_ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto LBL_ERR; + } + mp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (BN_is_even (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto LBL_ERR; + } + /* 4.2 if B is odd then */ + if (BN_is_odd (&B) == 1) { + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* B = B/2 */ + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 5. while v is even do */ + while (BN_is_even (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto LBL_ERR; + } + /* 5.2 if D is odd then */ + if (BN_is_odd (&D) == 1) { + /* D = (D-x)/2 */ + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* D = D/2 */ + if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 6. if u >= v then */ + if (mp_cmp (&u, &v) != MP_LT) { + /* u = u - v, B = B - D */ + if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } else { + /* v - v - u, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* if not zero goto step 4 */ + if (BN_is_zero (&u) == 0) { + goto top; + } + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto LBL_ERR; + } + + /* b is now the inverse */ + neg = a->sign; + while (D.sign == MP_NEG) { + if ((res = mp_add (&D, b, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + mp_exch (&D, c); + c->sign = neg; + res = MP_OKAY; + +LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &B, &D, NULL); + return res; +} + +/* hac 14.61, pp608 */ +static int +mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, A, B, C, D; + int res; + + /* b cannot be negative */ + if (b->sign == MP_NEG || BN_is_zero(b) == 1) { + return MP_VAL; + } + + /* init temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, + &A, &B, &C, &D, NULL)) != MP_OKAY) { + return res; + } + + /* x = a, y = b */ + if ((res = mp_mod(a, b, &x)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (b, &y)) != MP_OKAY) { + goto LBL_ERR; + } + + /* 2. [modified] if x,y are both even then return an error! */ + if (BN_is_even (&x) == 1 && BN_is_even (&y) == 1) { + res = MP_VAL; + goto LBL_ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto LBL_ERR; + } + mp_set (&A, 1); + mp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (BN_is_even (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto LBL_ERR; + } + /* 4.2 if A or B is odd then */ + if (BN_is_odd (&A) == 1 || BN_is_odd (&B) == 1) { + /* A = (A+y)/2, B = (B-x)/2 */ + if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* A = A/2, B = B/2 */ + if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 5. while v is even do */ + while (BN_is_even (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto LBL_ERR; + } + /* 5.2 if C or D is odd then */ + if (BN_is_odd (&C) == 1 || BN_is_odd (&D) == 1) { + /* C = (C+y)/2, D = (D-x)/2 */ + if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* C = C/2, D = D/2 */ + if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 6. if u >= v then */ + if (mp_cmp (&u, &v) != MP_LT) { + /* u = u - v, A = A - C, B = B - D */ + if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } else { + /* v - v - u, C = C - A, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* if not zero goto step 4 */ + if (BN_is_zero (&u) == 0) + goto top; + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto LBL_ERR; + } + + /* if its too low */ + while (mp_cmp_d(&C, 0) == MP_LT) { + if ((res = mp_add(&C, b, &C)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* too big */ + while (mp_cmp_mag(&C, b) != MP_LT) { + if ((res = mp_sub(&C, b, &C)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* C is now the inverse */ + mp_exch (&C, c); + res = MP_OKAY; +LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL); + return res; +} + +static int +mp_invmod(mp_int *c, mp_int *a, mp_int *b) +{ + /* b cannot be negative */ + if (b->sign == MP_NEG || BN_is_zero(b) == 1) { + return MP_VAL; + } + + /* if the modulus is odd we can use a faster routine instead */ + if (BN_is_odd (b) == 1) { + return fast_mp_invmod(a, b, c); + } + + return mp_invmod_slow(a, b, c); + + /*NOTREACHED*/ + return MP_VAL; +} + +/* b = |a| + * + * Simple function copies the input and fixes the sign to positive + */ +static int +mp_abs (mp_int * a, mp_int * b) +{ + int res; + + /* copy a to b */ + if (a != b) { + if ((res = mp_copy (a, b)) != MP_OKAY) { + return res; + } + } + + /* force the sign of b to positive */ + b->sign = MP_ZPOS; + + return MP_OKAY; +} + +/* determines if reduce_2k_l can be used */ +static int mp_reduce_is_2k_l(mp_int *a) +{ + int ix, iy; + + if (a->used == 0) { + return MP_NO; + } else if (a->used == 1) { + return MP_YES; + } else if (a->used > 1) { + /* if more than half of the digits are -1 we're sold */ + for (iy = ix = 0; ix < a->used; ix++) { + if (a->dp[ix] == MP_MASK) { + ++iy; + } + } + return (iy >= (a->used/2)) ? MP_YES : MP_NO; + + } + return MP_NO; +} + +/* computes a = 2**b + * + * Simple algorithm which zeroes the int, grows it then just sets one bit + * as required. + */ +static int +mp_2expt (mp_int * a, int b) +{ + int res; + + /* zero a as per default */ + mp_zero (a); + + /* grow a to accomodate the single bit */ + if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + + /* set the used count of where the bit will go */ + a->used = b / DIGIT_BIT + 1; + + /* put the single bit in its place */ + a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT); + + return MP_OKAY; +} + +/* pre-calculate the value required for Barrett reduction + * For a given modulus "b" it calulates the value required in "a" + */ +static int mp_reduce_setup (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { + return res; + } + return mp_div (a, NULL, a, b); +} + +/* b = a*2 */ +static int mp_mul_2(mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* grow to accomodate result */ + if (b->alloc < a->used + 1) { + if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + + { + mp_digit r, rr, *tmpa, *tmpb; + + /* alias for source */ + tmpa = a->dp; + + /* alias for dest */ + tmpb = b->dp; + + /* carry */ + r = 0; + for (x = 0; x < a->used; x++) { + + /* get what will be the *next* carry bit from the + * MSB of the current digit + */ + rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1)); + + /* now shift up this digit, add in the carry [from the previous] */ + *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK; + + /* copy the carry that would be from the source + * digit into the next iteration + */ + r = rr; + } + + /* new leading digit? */ + if (r != 0) { + /* add a MSB which is always 1 at this point */ + *tmpb = 1; + ++(b->used); + } + + /* now zero any excess digits on the destination + * that we didn't write to + */ + tmpb = b->dp + b->used; + for (x = b->used; x < oldused; x++) { + *tmpb++ = 0; + } + } + b->sign = a->sign; + return MP_OKAY; +} + +/* divide by three (based on routine from MPI and the GMP manual) */ +static int +mp_div_3 (mp_int * a, mp_int *c, mp_digit * d) +{ + mp_int q; + mp_word w, t; + mp_digit b; + int res, ix; + + /* b = 2**DIGIT_BIT / 3 */ + b = (((mp_word)1) << ((mp_word)DIGIT_BIT)) / ((mp_word)3); + + if ((res = mp_init_size(&q, a->used)) != MP_OKAY) { + return res; + } + + q.used = a->used; + q.sign = a->sign; + w = 0; + for (ix = a->used - 1; ix >= 0; ix--) { + w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]); + + if (w >= 3) { + /* multiply w by [1/3] */ + t = (w * ((mp_word)b)) >> ((mp_word)DIGIT_BIT); + + /* now subtract 3 * [w/3] from w, to get the remainder */ + w -= t+t+t; + + /* fixup the remainder as required since + * the optimization is not exact. + */ + while (w >= 3) { + t += 1; + w -= 3; + } + } else { + t = 0; + } + q.dp[ix] = (mp_digit)t; + } + + /* [optional] store the remainder */ + if (d != NULL) { + *d = (mp_digit)w; + } + + /* [optional] store the quotient */ + if (c != NULL) { + mp_clamp(&q); + mp_exch(&q, c); + } + mp_clear(&q); + + return res; +} + +/* multiplication using the Toom-Cook 3-way algorithm + * + * Much more complicated than Karatsuba but has a lower + * asymptotic running time of O(N**1.464). This algorithm is + * only particularly useful on VERY large inputs + * (we're talking 1000s of digits here...). +*/ +static int mp_toom_mul(mp_int *a, mp_int *b, mp_int *c) +{ + mp_int w0, w1, w2, w3, w4, tmp1, tmp2, a0, a1, a2, b0, b1, b2; + int res, B; + + /* init temps */ + if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4, + &a0, &a1, &a2, &b0, &b1, + &b2, &tmp1, &tmp2, NULL)) != MP_OKAY) { + return res; + } + + /* B */ + B = MIN(a->used, b->used) / 3; + + /* a = a2 * B**2 + a1 * B + a0 */ + if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_copy(a, &a1)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a1, B); + mp_mod_2d(&a1, DIGIT_BIT * B, &a1); + + if ((res = mp_copy(a, &a2)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a2, B*2); + + /* b = b2 * B**2 + b1 * B + b0 */ + if ((res = mp_mod_2d(b, DIGIT_BIT * B, &b0)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_copy(b, &b1)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&b1, B); + mp_mod_2d(&b1, DIGIT_BIT * B, &b1); + + if ((res = mp_copy(b, &b2)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&b2, B*2); + + /* w0 = a0*b0 */ + if ((res = mp_mul(&a0, &b0, &w0)) != MP_OKAY) { + goto ERR; + } + + /* w4 = a2 * b2 */ + if ((res = mp_mul(&a2, &b2, &w4)) != MP_OKAY) { + goto ERR; + } + + /* w1 = (a2 + 2(a1 + 2a0))(b2 + 2(b1 + 2b0)) */ + if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul_2(&b0, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b2, &tmp2)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul(&tmp1, &tmp2, &w1)) != MP_OKAY) { + goto ERR; + } + + /* w3 = (a0 + 2(a1 + 2a2))(b0 + 2(b1 + 2b2)) */ + if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul_2(&b2, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_mul(&tmp1, &tmp2, &w3)) != MP_OKAY) { + goto ERR; + } + + + /* w2 = (a2 + a1 + a0)(b2 + b1 + b0) */ + if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&b2, &b1, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul(&tmp1, &tmp2, &w2)) != MP_OKAY) { + goto ERR; + } + + /* now solve the matrix + + 0 0 0 0 1 + 1 2 4 8 16 + 1 1 1 1 1 + 16 8 4 2 1 + 1 0 0 0 0 + + using 12 subtractions, 4 shifts, + 2 small divisions and 1 small multiplication + */ + + /* r1 - r4 */ + if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r0 */ + if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/2 */ + if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3/2 */ + if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) { + goto ERR; + } + /* r2 - r0 - r4 */ + if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1 - 8r0 */ + if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - 8r4 */ + if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) { + goto ERR; + } + /* 3r2 - r1 - r3 */ + if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/3 */ + if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) { + goto ERR; + } + /* r3/3 */ + if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) { + goto ERR; + } + + /* at this point shift W[n] by B*n */ + if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_add(&w0, &w1, c)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, c, c)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear_multi(&w0, &w1, &w2, &w3, &w4, + &a0, &a1, &a2, &b0, &b1, + &b2, &tmp1, &tmp2, NULL); + return res; +} + +#define TOOM_MUL_CUTOFF 350 +#define KARATSUBA_MUL_CUTOFF 80 + +/* c = |a| * |b| using Karatsuba Multiplication using + * three half size multiplications + * + * Let B represent the radix [e.g. 2**DIGIT_BIT] and + * let n represent half of the number of digits in + * the min(a,b) + * + * a = a1 * B**n + a0 + * b = b1 * B**n + b0 + * + * Then, a * b => + a1b1 * B**2n + ((a1 + a0)(b1 + b0) - (a0b0 + a1b1)) * B + a0b0 + * + * Note that a1b1 and a0b0 are used twice and only need to be + * computed once. So in total three half size (half # of + * digit) multiplications are performed, a0b0, a1b1 and + * (a1+b1)(a0+b0) + * + * Note that a multiplication of half the digits requires + * 1/4th the number of single precision multiplications so in + * total after one call 25% of the single precision multiplications + * are saved. Note also that the call to mp_mul can end up back + * in this function if the a0, a1, b0, or b1 are above the threshold. + * This is known as divide-and-conquer and leads to the famous + * O(N**lg(3)) or O(N**1.584) work which is asymptopically lower than + * the standard O(N**2) that the baseline/comba methods use. + * Generally though the overhead of this method doesn't pay off + * until a certain size (N ~ 80) is reached. + */ +static int mp_karatsuba_mul (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x0, x1, y0, y1, t1, x0y0, x1y1; + int B; + int err; + + /* default the return code to an error */ + err = MP_MEM; + + /* min # of digits */ + B = MIN (a->used, b->used); + + /* now divide in two */ + B = (int)((unsigned)B >> 1); + + /* init copy all the temps */ + if (mp_init_size (&x0, B) != MP_OKAY) + goto ERR; + if (mp_init_size (&x1, a->used - B) != MP_OKAY) + goto X0; + if (mp_init_size (&y0, B) != MP_OKAY) + goto X1; + if (mp_init_size (&y1, b->used - B) != MP_OKAY) + goto Y0; + + /* init temps */ + if (mp_init_size (&t1, B * 2) != MP_OKAY) + goto Y1; + if (mp_init_size (&x0y0, B * 2) != MP_OKAY) + goto T1; + if (mp_init_size (&x1y1, B * 2) != MP_OKAY) + goto X0Y0; + + /* now shift the digits */ + x0.used = y0.used = B; + x1.used = a->used - B; + y1.used = b->used - B; + + { + int x; + mp_digit *tmpa, *tmpb, *tmpx, *tmpy; + + /* we copy the digits directly instead of using higher level functions + * since we also need to shift the digits + */ + tmpa = a->dp; + tmpb = b->dp; + + tmpx = x0.dp; + tmpy = y0.dp; + for (x = 0; x < B; x++) { + *tmpx++ = *tmpa++; + *tmpy++ = *tmpb++; + } + + tmpx = x1.dp; + for (x = B; x < a->used; x++) { + *tmpx++ = *tmpa++; + } + + tmpy = y1.dp; + for (x = B; x < b->used; x++) { + *tmpy++ = *tmpb++; + } + } + + /* only need to clamp the lower words since by definition the + * upper words x1/y1 must have a known number of digits + */ + mp_clamp (&x0); + mp_clamp (&y0); + + /* now calc the products x0y0 and x1y1 */ + /* after this x0 is no longer required, free temp [x0==t2]! */ + if (mp_mul (&x0, &y0, &x0y0) != MP_OKAY) + goto X1Y1; /* x0y0 = x0*y0 */ + if (mp_mul (&x1, &y1, &x1y1) != MP_OKAY) + goto X1Y1; /* x1y1 = x1*y1 */ + + /* now calc x1+x0 and y1+y0 */ + if (s_mp_add (&x1, &x0, &t1) != MP_OKAY) + goto X1Y1; /* t1 = x1 - x0 */ + if (s_mp_add (&y1, &y0, &x0) != MP_OKAY) + goto X1Y1; /* t2 = y1 - y0 */ + if (mp_mul (&t1, &x0, &t1) != MP_OKAY) + goto X1Y1; /* t1 = (x1 + x0) * (y1 + y0) */ + + /* add x0y0 */ + if (mp_add (&x0y0, &x1y1, &x0) != MP_OKAY) + goto X1Y1; /* t2 = x0y0 + x1y1 */ + if (s_mp_sub (&t1, &x0, &t1) != MP_OKAY) + goto X1Y1; /* t1 = (x1+x0)*(y1+y0) - (x1y1 + x0y0) */ + + /* shift by B */ + if (mp_lshd (&t1, B) != MP_OKAY) + goto X1Y1; /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))<alloc < digs) { + if ((res = mp_grow (c, digs)) != MP_OKAY) { + return res; + } + } + + /* number of output digits to produce */ + pa = MIN(digs, a->used + b->used); + + /* clear the carry */ + _W = 0; + for (ix = 0; ix < pa; ix++) { + int tx, ty; + int iy; + mp_digit *tmpx, *tmpy; + + /* get offsets into the two bignums */ + ty = MIN(b->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = b->dp + ty; + + /* this is the number of times the loop will iterrate, essentially + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MIN(a->used-tx, ty+1); + + /* execute loop */ + for (iz = 0; iz < iy; ++iz) { + _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); + + } + + /* store term */ + W[ix] = ((mp_digit)_W) & MP_MASK; + + /* make next carry */ + _W = _W >> ((mp_word)DIGIT_BIT); + } + + /* setup dest */ + olduse = c->used; + c->used = pa; + + { + mp_digit *tmpc; + tmpc = c->dp; + for (ix = 0; ix < pa+1; ix++) { + /* now extract the previous digit [below the carry] */ + *tmpc++ = W[ix]; + } + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpc++ = 0; + } + } + mp_clamp (c); + return MP_OKAY; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_fast_s_mp_mul_digs.c,v $ */ +/* Revision: 1.2 $ */ +/* Date: 2011/03/18 16:22:09 $ */ + + +/* multiplies |a| * |b| and only computes upto digs digits of result + * HAC pp. 595, Algorithm 14.12 Modified so you can control how + * many digits of output are created. + */ +static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ + if (((unsigned)(digs) < MP_WARRAY) && + MIN (a->used, b->used) < + (1 << (unsigned)((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_digs (a, b, c, digs); + } + + if ((res = mp_init_size (&t, digs)) != MP_OKAY) { + return res; + } + t.used = digs; + + /* compute the digits of the product directly */ + pa = a->used; + for (ix = 0; ix < pa; ix++) { + /* set the carry to zero */ + u = 0; + + /* limit ourselves to making digs digits of output */ + pb = MIN (b->used, digs - ix); + + /* setup some aliases */ + /* copy of the digit from a used within the nested loop */ + tmpx = a->dp[ix]; + + /* an alias for the destination shifted ix places */ + tmpt = t.dp + ix; + + /* an alias for the digits of b */ + tmpy = b->dp; + + /* compute the columns of the output and propagate the carry */ + for (iy = 0; iy < pb; iy++) { + /* compute the column as a mp_word */ + r = ((mp_word)*tmpt) + + ((mp_word)tmpx) * ((mp_word)*tmpy++) + + ((mp_word) u); + + /* the new column is the lower part of the result */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry word from the result */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + /* set carry if it is placed below digs */ + if (ix + iy < digs) { + *tmpt = u; + } + } + + mp_clamp (&t); + mp_exch (&t, c); + + mp_clear (&t); + return MP_OKAY; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_s_mp_mul_digs.c,v $ */ +/* Revision: 1.3 $ */ +/* Date: 2011/03/18 16:43:04 $ */ + +/* high level multiplication (handles sign) */ +static int +mp_mul(mp_int * a, mp_int * b, mp_int * c) +{ + int res, neg; + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + + /* use Toom-Cook? */ + if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) { + res = mp_toom_mul(a, b, c); + } else + /* use Karatsuba? */ + if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) { + res = mp_karatsuba_mul (a, b, c); + } else + { + /* can we use the fast multiplier? + * + * The fast multiplier can be used if the output will + * have less than MP_WARRAY digits and the number of + * digits won't affect carry propagation + */ + int digs = a->used + b->used + 1; + + if (((unsigned)digs < MP_WARRAY) && + MIN(a->used, b->used) <= + (1 << (unsigned)((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + res = fast_s_mp_mul_digs (a, b, c, digs); + } else + res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */ + + } + c->sign = (c->used > 0) ? neg : MP_ZPOS; + return res; +} + +/* this is a modified version of fast_s_mul_digs that only produces + * output digits *above* digs. See the comments for fast_s_mul_digs + * to see how it works. + * + * This is used in the Barrett reduction since for one of the multiplications + * only the higher digits were needed. This essentially halves the work. + * + * Based on Algorithm 14.12 on pp.595 of HAC. + */ +static int +fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY]; + mp_word _W; + + /* grow the destination as required */ + pa = a->used + b->used; + if (c->alloc < pa) { + if ((res = mp_grow (c, pa)) != MP_OKAY) { + return res; + } + } + + /* number of output digits to produce */ + pa = a->used + b->used; + _W = 0; + for (ix = digs; ix < pa; ix++) { + int tx, ty, iy; + mp_digit *tmpx, *tmpy; + + /* get offsets into the two bignums */ + ty = MIN(b->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = b->dp + ty; + + /* this is the number of times the loop will iterrate, essentially its + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MIN(a->used-tx, ty+1); + + /* execute loop */ + for (iz = 0; iz < iy; iz++) { + _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); + } + + /* store term */ + W[ix] = ((mp_digit)_W) & MP_MASK; + + /* make next carry */ + _W = _W >> ((mp_word)DIGIT_BIT); + } + + /* setup dest */ + olduse = c->used; + c->used = pa; + + { + mp_digit *tmpc; + + tmpc = c->dp + digs; + for (ix = digs; ix < pa; ix++) { + /* now extract the previous digit [below the carry] */ + *tmpc++ = W[ix]; + } + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpc++ = 0; + } + } + mp_clamp (c); + return MP_OKAY; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_fast_s_mp_mul_high_digs.c,v $ */ +/* Revision: 1.1.1.1 $ */ +/* Date: 2011/03/12 22:58:18 $ */ + +/* multiplies |a| * |b| and does not compute the lower digs digits + * [meant to get the higher part of the product] + */ +static int +s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ + if (((unsigned)(a->used + b->used + 1) < MP_WARRAY) + && MIN (a->used, b->used) < (1 << (unsigned)((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_high_digs (a, b, c, digs); + } + + if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) { + return res; + } + t.used = a->used + b->used + 1; + + pa = a->used; + pb = b->used; + for (ix = 0; ix < pa; ix++) { + /* clear the carry */ + u = 0; + + /* left hand side of A[ix] * B[iy] */ + tmpx = a->dp[ix]; + + /* alias to the address of where the digits will be stored */ + tmpt = &(t.dp[digs]); + + /* alias for where to read the right hand side from */ + tmpy = b->dp + (digs - ix); + + for (iy = digs - ix; iy < pb; iy++) { + /* calculate the double precision result */ + r = ((mp_word)*tmpt) + + ((mp_word)tmpx) * ((mp_word)*tmpy++) + + ((mp_word) u); + + /* get the lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* carry the carry */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + *tmpt = u; + } + mp_clamp (&t); + mp_exch (&t, c); + mp_clear (&t); + return MP_OKAY; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_s_mp_mul_high_digs.c,v $ */ +/* Revision: 1.3 $ */ +/* Date: 2011/03/18 16:43:04 $ */ + +/* reduces x mod m, assumes 0 < x < m**2, mu is + * precomputed via mp_reduce_setup. + * From HAC pp.604 Algorithm 14.42 + */ +static int +mp_reduce (mp_int * x, mp_int * m, mp_int * mu) +{ + mp_int q; + int res, um = m->used; + + /* q = x */ + if ((res = mp_init_copy (&q, x)) != MP_OKAY) { + return res; + } + + /* q1 = x / b**(k-1) */ + mp_rshd (&q, um - 1); + + /* according to HAC this optimization is ok */ + if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) { + if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) { + goto CLEANUP; + } + } else { + if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { + goto CLEANUP; + } + } + + /* q3 = q2 / b**(k+1) */ + mp_rshd (&q, um + 1); + + /* x = x mod b**(k+1), quick (no division) */ + if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) { + goto CLEANUP; + } + + /* q = q * m mod b**(k+1), quick (no division) */ + if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + + /* x = x - q */ + if ((res = mp_sub (x, &q, x)) != MP_OKAY) { + goto CLEANUP; + } + + /* If x < 0, add b**(k+1) to it */ + if (mp_cmp_d (x, 0) == MP_LT) { + mp_set (&q, 1); + if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) + goto CLEANUP; + if ((res = mp_add (x, &q, x)) != MP_OKAY) + goto CLEANUP; + } + + /* Back off if it's too big */ + while (mp_cmp (x, m) != MP_LT) { + if ((res = s_mp_sub (x, m, x)) != MP_OKAY) { + goto CLEANUP; + } + } + +CLEANUP: + mp_clear (&q); + + return res; +} + +/* determines the setup value */ +static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d) +{ + int res; + mp_int tmp; + + if ((res = mp_init(&tmp)) != MP_OKAY) { + return res; + } + + if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) { + goto ERR; + } + + if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear(&tmp); + return res; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_mp_reduce_2k_setup_l.c,v $ */ +/* Revision: 1.1.1.1 $ */ +/* Date: 2011/03/12 22:58:18 $ */ + +/* reduces a modulo n where n is of the form 2**p - d + This differs from reduce_2k since "d" can be larger + than a single digit. +*/ +static int +mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d) +{ + mp_int q; + int p, res; + + if ((res = mp_init(&q)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto ERR; + } + + /* q = q * d */ + if ((res = mp_mul(&q, d, &q)) != MP_OKAY) { + goto ERR; + } + + /* a = a + q */ + if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + s_mp_sub(a, n, a); + goto top; + } + +ERR: + mp_clear(&q); + return res; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_mp_reduce_2k_l.c,v $ */ +/* Revision: 1.1.1.1 $ */ +/* Date: 2011/03/12 22:58:18 $ */ + +/* squaring using Toom-Cook 3-way algorithm */ +static int +mp_toom_sqr(mp_int *a, mp_int *b) +{ + mp_int w0, w1, w2, w3, w4, tmp1, a0, a1, a2; + int res, B; + + /* init temps */ + if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL)) != MP_OKAY) { + return res; + } + + /* B */ + B = a->used / 3; + + /* a = a2 * B**2 + a1 * B + a0 */ + if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_copy(a, &a1)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a1, B); + mp_mod_2d(&a1, DIGIT_BIT * B, &a1); + + if ((res = mp_copy(a, &a2)) != MP_OKAY) { + goto ERR; + } + mp_rshd(&a2, B*2); + + /* w0 = a0*a0 */ + if ((res = mp_sqr(&a0, &w0)) != MP_OKAY) { + goto ERR; + } + + /* w4 = a2 * a2 */ + if ((res = mp_sqr(&a2, &w4)) != MP_OKAY) { + goto ERR; + } + + /* w1 = (a2 + 2(a1 + 2a0))**2 */ + if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_sqr(&tmp1, &w1)) != MP_OKAY) { + goto ERR; + } + + /* w3 = (a0 + 2(a1 + 2a2))**2 */ + if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_sqr(&tmp1, &w3)) != MP_OKAY) { + goto ERR; + } + + + /* w2 = (a2 + a1 + a0)**2 */ + if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sqr(&tmp1, &w2)) != MP_OKAY) { + goto ERR; + } + + /* now solve the matrix + + 0 0 0 0 1 + 1 2 4 8 16 + 1 1 1 1 1 + 16 8 4 2 1 + 1 0 0 0 0 + + using 12 subtractions, 4 shifts, 2 small divisions and 1 small multiplication. + */ + + /* r1 - r4 */ + if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r0 */ + if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/2 */ + if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3/2 */ + if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) { + goto ERR; + } + /* r2 - r0 - r4 */ + if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1 - 8r0 */ + if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - 8r4 */ + if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) { + goto ERR; + } + /* 3r2 - r1 - r3 */ + if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) { + goto ERR; + } + /* r1 - r2 */ + if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { + goto ERR; + } + /* r3 - r2 */ + if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { + goto ERR; + } + /* r1/3 */ + if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) { + goto ERR; + } + /* r3/3 */ + if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) { + goto ERR; + } + + /* at this point shift W[n] by B*n */ + if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) { + goto ERR; + } + + if ((res = mp_add(&w0, &w1, b)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) { + goto ERR; + } + if ((res = mp_add(&tmp1, b, b)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &tmp1, NULL); + return res; +} + + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_mp_toom_sqr.c,v $ */ +/* Revision: 1.1.1.1 $ */ +/* Date: 2011/03/12 22:58:18 $ */ + +/* Karatsuba squaring, computes b = a*a using three + * half size squarings + * + * See comments of karatsuba_mul for details. It + * is essentially the same algorithm but merely + * tuned to perform recursive squarings. + */ +static int mp_karatsuba_sqr (mp_int * a, mp_int * b) +{ + mp_int x0, x1, t1, t2, x0x0, x1x1; + int B, err; + + err = MP_MEM; + + /* min # of digits */ + B = a->used; + + /* now divide in two */ + B = (unsigned)B >> 1; + + /* init copy all the temps */ + if (mp_init_size (&x0, B) != MP_OKAY) + goto ERR; + if (mp_init_size (&x1, a->used - B) != MP_OKAY) + goto X0; + + /* init temps */ + if (mp_init_size (&t1, a->used * 2) != MP_OKAY) + goto X1; + if (mp_init_size (&t2, a->used * 2) != MP_OKAY) + goto T1; + if (mp_init_size (&x0x0, B * 2) != MP_OKAY) + goto T2; + if (mp_init_size (&x1x1, (a->used - B) * 2) != MP_OKAY) + goto X0X0; + + { + int x; + mp_digit *dst, *src; + + src = a->dp; + + /* now shift the digits */ + dst = x0.dp; + for (x = 0; x < B; x++) { + *dst++ = *src++; + } + + dst = x1.dp; + for (x = B; x < a->used; x++) { + *dst++ = *src++; + } + } + + x0.used = B; + x1.used = a->used - B; + + mp_clamp (&x0); + + /* now calc the products x0*x0 and x1*x1 */ + if (mp_sqr (&x0, &x0x0) != MP_OKAY) + goto X1X1; /* x0x0 = x0*x0 */ + if (mp_sqr (&x1, &x1x1) != MP_OKAY) + goto X1X1; /* x1x1 = x1*x1 */ + + /* now calc (x1+x0)**2 */ + if (s_mp_add (&x1, &x0, &t1) != MP_OKAY) + goto X1X1; /* t1 = x1 - x0 */ + if (mp_sqr (&t1, &t1) != MP_OKAY) + goto X1X1; /* t1 = (x1 - x0) * (x1 - x0) */ + + /* add x0y0 */ + if (s_mp_add (&x0x0, &x1x1, &t2) != MP_OKAY) + goto X1X1; /* t2 = x0x0 + x1x1 */ + if (s_mp_sub (&t1, &t2, &t1) != MP_OKAY) + goto X1X1; /* t1 = (x1+x0)**2 - (x0x0 + x1x1) */ + + /* shift by B */ + if (mp_lshd (&t1, B) != MP_OKAY) + goto X1X1; /* t1 = (x0x0 + x1x1 - (x1-x0)*(x1-x0))<used + a->used; + if (b->alloc < pa) { + if ((res = mp_grow (b, pa)) != MP_OKAY) { + return res; + } + } + + /* number of output digits to produce */ + W1 = 0; + for (ix = 0; ix < pa; ix++) { + int tx, ty, iy; + mp_word _W; + mp_digit *tmpy; + + /* clear counter */ + _W = 0; + + /* get offsets into the two bignums */ + ty = MIN(a->used-1, ix); + tx = ix - ty; + + /* setup temp aliases */ + tmpx = a->dp + tx; + tmpy = a->dp + ty; + + /* this is the number of times the loop will iterrate, essentially + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MIN(a->used-tx, ty+1); + + /* now for squaring tx can never equal ty + * we halve the distance since they approach at a rate of 2x + * and we have to round because odd cases need to be executed + */ + iy = MIN(iy, (int)((unsigned)(ty-tx+1)>>1)); + + /* execute loop */ + for (iz = 0; iz < iy; iz++) { + _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); + } + + /* double the inner product and add carry */ + _W = _W + _W + W1; + + /* even columns have the square term in them */ + if ((ix&1) == 0) { + _W += ((mp_word)a->dp[(unsigned)ix>>1])*((mp_word)a->dp[(unsigned)ix>>1]); + } + + /* store it */ + W[ix] = (mp_digit)(_W & MP_MASK); + + /* make next carry */ + W1 = _W >> ((mp_word)DIGIT_BIT); + } + + /* setup dest */ + olduse = b->used; + b->used = a->used+a->used; + + { + mp_digit *tmpb; + tmpb = b->dp; + for (ix = 0; ix < pa; ix++) { + *tmpb++ = W[ix] & MP_MASK; + } + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpb++ = 0; + } + } + mp_clamp (b); + return MP_OKAY; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_fast_s_mp_sqr.c,v $ */ +/* Revision: 1.3 $ */ +/* Date: 2011/03/18 16:43:04 $ */ + +/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ +static int +s_mp_sqr (mp_int * a, mp_int * b) +{ + mp_int t; + int res, ix, iy, pa; + mp_word r; + mp_digit u, tmpx, *tmpt; + + pa = a->used; + if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) { + return res; + } + + /* default used is maximum possible size */ + t.used = 2*pa + 1; + + for (ix = 0; ix < pa; ix++) { + /* first calculate the digit at 2*ix */ + /* calculate double precision result */ + r = ((mp_word) t.dp[2*ix]) + + ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]); + + /* store lower part in result */ + t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + + /* left hand side of A[ix] * A[iy] */ + tmpx = a->dp[ix]; + + /* alias for where to store the results */ + tmpt = t.dp + (2*ix + 1); + + for (iy = ix + 1; iy < pa; iy++) { + /* first calculate the product */ + r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]); + + /* now calculate the double precision result, note we use + * addition instead of *2 since it's easier to optimize + */ + r = ((mp_word) *tmpt) + r + r + ((mp_word) u); + + /* store lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + } + /* propagate upwards */ + while (u != ((mp_digit) 0)) { + r = ((mp_word) *tmpt) + ((mp_word) u); + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + } + } + + mp_clamp (&t); + mp_exch (&t, b); + mp_clear (&t); + return MP_OKAY; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_s_mp_sqr.c,v $ */ +/* Revision: 1.1.1.1 $ */ +/* Date: 2011/03/12 22:58:18 $ */ + +#define TOOM_SQR_CUTOFF 400 +#define KARATSUBA_SQR_CUTOFF 120 + +/* computes b = a*a */ +static int +mp_sqr (mp_int * a, mp_int * b) +{ + int res; + + /* use Toom-Cook? */ + if (a->used >= TOOM_SQR_CUTOFF) { + res = mp_toom_sqr(a, b); + /* Karatsuba? */ + } else +if (a->used >= KARATSUBA_SQR_CUTOFF) { + res = mp_karatsuba_sqr (a, b); + } else + { + /* can we use the fast comba multiplier? */ + if (((unsigned)a->used * 2 + 1) < MP_WARRAY && + a->used < + (1 << (unsigned)(sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) { + res = fast_s_mp_sqr (a, b); + } else + res = s_mp_sqr (a, b); + } + b->sign = MP_ZPOS; + return res; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_mp_sqr.c,v $ */ +/* Revision: 1.3 $ */ +/* Date: 2011/03/18 16:43:04 $ */ + +#define TAB_SIZE 256 + +static int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) +{ + mp_int M[TAB_SIZE], res, mu; + mp_digit buf; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + int (*redux)(mp_int*,mp_int*,mp_int*); + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear (&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* create mu, used for Barrett reduction */ + if ((err = mp_init (&mu)) != MP_OKAY) { + goto LBL_M; + } + + if (redmode == 0) { + if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) { + goto LBL_MU; + } + redux = mp_reduce; + } else { + if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) { + goto LBL_MU; + } + redux = mp_reduce_2k_l; + } + + /* create M table + * + * The M table contains powers of the base, + * e.g. M[x] = G**x mod P + * + * The first half of the table is not + * computed though accept for M[0] and M[1] + */ + if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) { + goto LBL_MU; + } + + /* compute the value at M[1<<(winsize-1)] by squaring + * M[1] (winsize-1) times + */ + if ((err = mp_copy ( &M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_MU; + } + + for (x = 0; x < (winsize - 1); x++) { + /* square it */ + if ((err = mp_sqr (&M[1 << (winsize - 1)], + &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_MU; + } + + /* reduce modulo P */ + if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) { + goto LBL_MU; + } + } + + /* create upper table, that is M[x] = M[x-1] * M[1] (mod P) + * for x = (2**(winsize - 1) + 1) to (2**winsize - 1) + */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto LBL_MU; + } + if ((err = redux (&M[x], P, &mu)) != MP_OKAY) { + goto LBL_MU; + } + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto LBL_MU; + } + mp_set (&res, 1); + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits */ + if (digidx == -1) { + break; + } + /* read next digit and reset the bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int) DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (unsigned)(buf >> (mp_digit)(DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + } + } + } + + mp_exch (&res, Y); + err = MP_OKAY; +LBL_RES:mp_clear (&res); +LBL_MU:mp_clear (&mu); +LBL_M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} + +/* determines if a number is a valid DR modulus */ +static int +mp_dr_is_modulus(mp_int *a) +{ + int ix; + + /* must be at least two digits */ + if (a->used < 2) { + return 0; + } + + /* must be of the form b**k - a [a <= b] so all + * but the first digit must be equal to -1 (mod b). + */ + for (ix = 1; ix < a->used; ix++) { + if (a->dp[ix] != MP_MASK) { + return 0; + } + } + return 1; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_mp_dr_is_modulus.c,v $ */ +/* Revision: 1.1.1.1 $ */ +/* Date: 2011/03/12 22:58:18 $ */ + +/* determines if mp_reduce_2k can be used */ +static int mp_reduce_is_2k(mp_int *a) +{ + int ix, iy, iw; + mp_digit iz; + + if (a->used == 0) { + return MP_NO; + } else if (a->used == 1) { + return MP_YES; + } else if (a->used > 1) { + iy = mp_count_bits(a); + iz = 1; + iw = 1; + + /* Test every bit from the second digit up, must be 1 */ + for (ix = DIGIT_BIT; ix < iy; ix++) { + if ((a->dp[iw] & iz) == 0) { + return MP_NO; + } + iz <<= 1; + if (iz > (mp_digit)MP_MASK) { + ++iw; + iz = 1; + } + } + } + return MP_YES; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_mp_reduce_is_2k.c,v $ */ +/* Revision: 1.1.1.1 $ */ +/* Date: 2011/03/12 22:58:18 $ */ + + +/* d = a * b (mod c) */ +static int +mp_mulmod (mp_int *d, mp_int * a, mp_int * b, mp_int * c) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_mul (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_mp_mulmod.c,v $ */ +/* Revision: 1.1.1.1 $ */ +/* Date: 2011/03/12 22:58:18 $ */ + +/* setups the montgomery reduction stuff */ +static int +mp_montgomery_setup (mp_int * n, mp_digit * rho) +{ + mp_digit x, b; + +/* fast inversion mod 2**k + * + * Based on the fact that + * + * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n) + * => 2*X*A - X*X*A*A = 1 + * => 2*(1) - (1) = 1 + */ + b = n->dp[0]; + + if ((b & 1) == 0) { + return MP_VAL; + } + + x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */ + x *= 2 - b * x; /* here x*a==1 mod 2**8 */ + x *= 2 - b * x; /* here x*a==1 mod 2**16 */ + x *= 2 - b * x; /* here x*a==1 mod 2**32 */ + if (/*CONSTCOND*/sizeof(mp_digit) == 8) { + x *= 2 - b * x; /* here x*a==1 mod 2**64 */ + } + + /* rho = -1/m mod b */ + *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK; + + return MP_OKAY; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_mp_montgomery_setup.c,v $ */ +/* Revision: 1.1.1.1 $ */ +/* Date: 2011/03/12 22:58:18 $ */ + +/* computes xR**-1 == x (mod N) via Montgomery Reduction + * + * This is an optimized implementation of montgomery_reduce + * which uses the comba method to quickly calculate the columns of the + * reduction. + * + * Based on Algorithm 14.32 on pp.601 of HAC. +*/ +static int +fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) +{ + int ix, res, olduse; + /*LINTED*/ + mp_word W[MP_WARRAY]; + + /* get old used count */ + olduse = x->used; + + /* grow a as required */ + if (x->alloc < n->used + 1) { + if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) { + return res; + } + } + + /* first we have to get the digits of the input into + * an array of double precision words W[...] + */ + { + mp_word *_W; + mp_digit *tmpx; + + /* alias for the W[] array */ + _W = W; + + /* alias for the digits of x*/ + tmpx = x->dp; + + /* copy the digits of a into W[0..a->used-1] */ + for (ix = 0; ix < x->used; ix++) { + *_W++ = *tmpx++; + } + + /* zero the high words of W[a->used..m->used*2] */ + for (; ix < n->used * 2 + 1; ix++) { + *_W++ = 0; + } + } + + /* now we proceed to zero successive digits + * from the least significant upwards + */ + for (ix = 0; ix < n->used; ix++) { + /* mu = ai * m' mod b + * + * We avoid a double precision multiplication (which isn't required) + * by casting the value down to a mp_digit. Note this requires + * that W[ix-1] have the carry cleared (see after the inner loop) + */ + mp_digit mu; + mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK); + + /* a = a + mu * m * b**i + * + * This is computed in place and on the fly. The multiplication + * by b**i is handled by offseting which columns the results + * are added to. + * + * Note the comba method normally doesn't handle carries in the + * inner loop In this case we fix the carry from the previous + * column since the Montgomery reduction requires digits of the + * result (so far) [see above] to work. This is + * handled by fixing up one carry after the inner loop. The + * carry fixups are done in order so after these loops the + * first m->used words of W[] have the carries fixed + */ + { + int iy; + mp_digit *tmpn; + mp_word *_W; + + /* alias for the digits of the modulus */ + tmpn = n->dp; + + /* Alias for the columns set by an offset of ix */ + _W = W + ix; + + /* inner loop */ + for (iy = 0; iy < n->used; iy++) { + *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++); + } + } + + /* now fix carry for next digit, W[ix+1] */ + W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT); + } + + /* now we have to propagate the carries and + * shift the words downward [all those least + * significant digits we zeroed]. + */ + { + mp_digit *tmpx; + mp_word *_W, *_W1; + + /* nox fix rest of carries */ + + /* alias for current word */ + _W1 = W + ix; + + /* alias for next word, where the carry goes */ + _W = W + ++ix; + + for (; ix <= n->used * 2 + 1; ix++) { + *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT); + } + + /* copy out, A = A/b**n + * + * The result is A/b**n but instead of converting from an + * array of mp_word to mp_digit than calling mp_rshd + * we just copy them in the right order + */ + + /* alias for destination word */ + tmpx = x->dp; + + /* alias for shifted double precision result */ + _W = W + n->used; + + for (ix = 0; ix < n->used + 1; ix++) { + *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK)); + } + + /* zero oldused digits, if the input a was larger than + * m->used+1 we'll have to clear the digits + */ + for (; ix < olduse; ix++) { + *tmpx++ = 0; + } + } + + /* set the max used and clamp */ + x->used = n->used + 1; + mp_clamp (x); + + /* if A >= m then A = A - m */ + if (mp_cmp_mag (x, n) != MP_LT) { + return s_mp_sub (x, n, x); + } + return MP_OKAY; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_fast_mp_montgomery_reduce.c,v $ */ +/* Revision: 1.2 $ */ +/* Date: 2011/03/18 16:22:09 $ */ + +/* computes xR**-1 == x (mod N) via Montgomery Reduction */ +static int +mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) +{ + int ix, res, digs; + mp_digit mu; + + /* can the fast reduction [comba] method be used? + * + * Note that unlike in mul you're safely allowed *less* + * than the available columns [255 per default] since carries + * are fixed up in the inner loop. + */ + digs = n->used * 2 + 1; + if (((unsigned)digs < MP_WARRAY) && + n->used < + (1 << (unsigned)((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_mp_montgomery_reduce (x, n, rho); + } + + /* grow the input as required */ + if (x->alloc < digs) { + if ((res = mp_grow (x, digs)) != MP_OKAY) { + return res; + } + } + x->used = digs; + + for (ix = 0; ix < n->used; ix++) { + /* mu = ai * rho mod b + * + * The value of rho must be precalculated via + * montgomery_setup() such that + * it equals -1/n0 mod b this allows the + * following inner loop to reduce the + * input one digit at a time + */ + mu = (mp_digit) (((mp_word)x->dp[ix]) * ((mp_word)rho) & MP_MASK); + + /* a = a + mu * m * b**i */ + { + int iy; + mp_digit *tmpn, *tmpx, u; + mp_word r; + + /* alias for digits of the modulus */ + tmpn = n->dp; + + /* alias for the digits of x [the input] */ + tmpx = x->dp + ix; + + /* set the carry to zero */ + u = 0; + + /* Multiply and add in place */ + for (iy = 0; iy < n->used; iy++) { + /* compute product and sum */ + r = ((mp_word)mu) * ((mp_word)*tmpn++) + + ((mp_word) u) + ((mp_word) * tmpx); + + /* get carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + + /* fix digit */ + *tmpx++ = (mp_digit)(r & ((mp_word) MP_MASK)); + } + /* At this point the ix'th digit of x should be zero */ + + + /* propagate carries upwards as required*/ + while (u) { + *tmpx += u; + u = *tmpx >> DIGIT_BIT; + *tmpx++ &= MP_MASK; + } + } + } + + /* at this point the n.used'th least + * significant digits of x are all zero + * which means we can shift x to the + * right by n.used digits and the + * residue is unchanged. + */ + + /* x = x/b**n.used */ + mp_clamp(x); + mp_rshd (x, n->used); + + /* if x >= n then x = x - n */ + if (mp_cmp_mag (x, n) != MP_LT) { + return s_mp_sub (x, n, x); + } + + return MP_OKAY; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_mp_montgomery_reduce.c,v $ */ +/* Revision: 1.3 $ */ +/* Date: 2011/03/18 16:43:04 $ */ + +/* determines the setup value */ +static void +mp_dr_setup(mp_int *a, mp_digit *d) +{ + /* the casts are required if DIGIT_BIT is one less than + * the number of bits in a mp_digit [e.g. DIGIT_BIT==31] + */ + *d = (mp_digit)((((mp_word)1) << ((mp_word)DIGIT_BIT)) - + ((mp_word)a->dp[0])); +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_mp_dr_setup.c,v $ */ +/* Revision: 1.1.1.1 $ */ +/* Date: 2011/03/12 22:58:18 $ */ + +/* reduce "x" in place modulo "n" using the Diminished Radix algorithm. + * + * Based on algorithm from the paper + * + * "Generating Efficient Primes for Discrete Log Cryptosystems" + * Chae Hoon Lim, Pil Joong Lee, + * POSTECH Information Research Laboratories + * + * The modulus must be of a special format [see manual] + * + * Has been modified to use algorithm 7.10 from the LTM book instead + * + * Input x must be in the range 0 <= x <= (n-1)**2 + */ +static int +mp_dr_reduce (mp_int * x, mp_int * n, mp_digit k) +{ + int err, i, m; + mp_word r; + mp_digit mu, *tmpx1, *tmpx2; + + /* m = digits in modulus */ + m = n->used; + + /* ensure that "x" has at least 2m digits */ + if (x->alloc < m + m) { + if ((err = mp_grow (x, m + m)) != MP_OKAY) { + return err; + } + } + +/* top of loop, this is where the code resumes if + * another reduction pass is required. + */ +top: + /* aliases for digits */ + /* alias for lower half of x */ + tmpx1 = x->dp; + + /* alias for upper half of x, or x/B**m */ + tmpx2 = x->dp + m; + + /* set carry to zero */ + mu = 0; + + /* compute (x mod B**m) + k * [x/B**m] inline and inplace */ + for (i = 0; i < m; i++) { + r = ((mp_word)*tmpx2++) * ((mp_word)k) + *tmpx1 + mu; + *tmpx1++ = (mp_digit)(r & MP_MASK); + mu = (mp_digit)(r >> ((mp_word)DIGIT_BIT)); + } + + /* set final carry */ + *tmpx1++ = mu; + + /* zero words above m */ + for (i = m + 1; i < x->used; i++) { + *tmpx1++ = 0; + } + + /* clamp, sub and return */ + mp_clamp (x); + + /* if x >= n then subtract and reduce again + * Each successive "recursion" makes the input smaller and smaller. + */ + if (mp_cmp_mag (x, n) != MP_LT) { + s_mp_sub(x, n, x); + goto top; + } + return MP_OKAY; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_mp_dr_reduce.c,v $ */ +/* Revision: 1.1.1.1 $ */ +/* Date: 2011/03/12 22:58:18 $ */ + +/* determines the setup value */ +static int +mp_reduce_2k_setup(mp_int *a, mp_digit *d) +{ + int res, p; + mp_int tmp; + + if ((res = mp_init(&tmp)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(a); + if ((res = mp_2expt(&tmp, p)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + if ((res = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + *d = tmp.dp[0]; + mp_clear(&tmp); + return MP_OKAY; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_mp_reduce_2k_setup.c,v $ */ +/* Revision: 1.1.1.1 $ */ +/* Date: 2011/03/12 22:58:18 $ */ + +/* reduces a modulo n where n is of the form 2**p - d */ +static int +mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d) +{ + mp_int q; + int p, res; + + if ((res = mp_init(&q)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (d != 1) { + /* q = q * d */ + if ((res = mp_mul_d(&q, d, &q)) != MP_OKAY) { + goto ERR; + } + } + + /* a = a + q */ + if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + s_mp_sub(a, n, a); + goto top; + } + +ERR: + mp_clear(&q); + return res; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_mp_reduce_2k.c,v $ */ +/* Revision: 1.1.1.1 $ */ +/* Date: 2011/03/12 22:58:18 $ */ + +/* + * shifts with subtractions when the result is greater than b. + * + * The method is slightly modified to shift B unconditionally upto just under + * the leading bit of b. This saves alot of multiple precision shifting. + */ +static int +mp_montgomery_calc_normalization (mp_int * a, mp_int * b) +{ + int x, bits, res; + + /* how many bits of last digit does b use */ + bits = mp_count_bits (b) % DIGIT_BIT; + + if (b->used > 1) { + if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) { + return res; + } + } else { + mp_set(a, 1); + bits = 1; + } + + + /* now compute C = A * B mod b */ + for (x = bits - 1; x < (int)DIGIT_BIT; x++) { + if ((res = mp_mul_2 (a, a)) != MP_OKAY) { + return res; + } + if (mp_cmp_mag (a, b) != MP_LT) { + if ((res = s_mp_sub (a, b, a)) != MP_OKAY) { + return res; + } + } + } + + return MP_OKAY; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_mp_montgomery_calc_normalization.c,v $ */ +/* Revision: 1.1.1.1 $ */ +/* Date: 2011/03/12 22:58:18 $ */ + +/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85 + * + * Uses a left-to-right k-ary sliding window to compute the modular exponentiation. + * The value of k changes based on the size of the exponent. + * + * Uses Montgomery or Diminished Radix reduction [whichever appropriate] + */ + +#define TAB_SIZE 256 + +static int +mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) +{ + mp_int M[TAB_SIZE], res; + mp_digit buf, mp; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + + /* use a pointer to the reduction algorithm. This allows us to use + * one of many reduction algorithms without modding the guts of + * the code with if statements everywhere. + */ + int (*redux)(mp_int*,mp_int*,mp_digit); + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear (&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* determine and setup reduction code */ + if (redmode == 0) { + /* now setup montgomery */ + if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { + goto LBL_M; + } + + /* automatically pick the comba one if available (saves quite a few calls/ifs) */ + if (((unsigned)(P->used * 2 + 1) < MP_WARRAY) && + P->used < (1 << (unsigned)((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + redux = fast_mp_montgomery_reduce; + } else + { + /* use slower baseline Montgomery method */ + redux = mp_montgomery_reduce; + } + } else if (redmode == 1) { + /* setup DR reduction for moduli of the form B**k - b */ + mp_dr_setup(P, &mp); + redux = mp_dr_reduce; + } else { + /* setup DR reduction for moduli of the form 2**k - b */ + if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) { + goto LBL_M; + } + redux = mp_reduce_2k; + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto LBL_M; + } + + /* create M table + * + + * + * The first half of the table is not computed though accept for M[0] and M[1] + */ + + if (redmode == 0) { + /* now we need R mod m */ + if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) { + goto LBL_RES; + } + + /* now set M[1] to G * R mod m */ + if ((err = mp_mulmod (&M[1], G, &res, P)) != MP_OKAY) { + goto LBL_RES; + } + } else { + mp_set(&res, 1); + if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) { + goto LBL_RES; + } + } + + /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ + if ((err = mp_copy ( &M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_RES; + } + + for (x = 0; x < (winsize - 1); x++) { + if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* create upper table */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&M[x], P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* set initial mode and bit cnt */ + mode = 0; + bitcnt = 1; + buf = 0; + digidx = X->used - 1; + bitcpy = 0; + bitbuf = 0; + + for (;;) { + /* grab next digit as required */ + if (--bitcnt == 0) { + /* if digidx == -1 we are out of digits so break */ + if (digidx == -1) { + break; + } + /* read next digit and reset bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int)DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (int)(mp_digit)((mp_digit)buf >> (unsigned)(DIGIT_BIT - 1)) & 1; + buf <<= (mp_digit)1; + + /* if the bit is zero and mode == 0 then we ignore it + * These represent the leading zero bits before the first 1 bit + * in the exponent. Technically this opt is not required but it + * does lower the # of trivial squaring/reductions used + */ + if (mode == 0 && y == 0) { + continue; + } + + /* if the bit is zero and mode == 1 then we square */ + if (mode == 1 && y == 0) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + continue; + } + + /* else we add it to the window */ + bitbuf |= (y << (winsize - ++bitcpy)); + mode = 2; + + if (bitcpy == winsize) { + /* ok window is filled so square as required and multiply */ + /* square first */ + for (x = 0; x < winsize; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + + /* empty window and reset */ + bitcpy = 0; + bitbuf = 0; + mode = 1; + } + } + + /* if bits remain then square/multiply */ + if (mode == 2 && bitcpy > 0) { + /* square then multiply if the bit is set */ + for (x = 0; x < bitcpy; x++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + + /* get next bit of the window */ + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + } + } + + if (redmode == 0) { + /* fixup result if Montgomery reduction is used + * recall that any value in a Montgomery system is + * actually multiplied by R mod n. So we have + * to reduce one more time to cancel out the factor + * of R. + */ + if ((err = redux(&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* swap res with Y */ + mp_exch (&res, Y); + err = MP_OKAY; +LBL_RES:mp_clear (&res); +LBL_M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} + +/* Source: /usr/cvsroot/libtommath/dist/libtommath/bn_mp_exptmod_fast.c,v $ */ +/* Revision: 1.4 $ */ +/* Date: 2011/03/18 16:43:04 $ */ + +/* this is a shell function that calls either the normal or Montgomery + * exptmod functions. Originally the call to the montgomery code was + * embedded in the normal function but that wasted alot of stack space + * for nothing (since 99% of the time the Montgomery code would be called) + */ +static int +mp_exptmod(mp_int * G, mp_int * X, mp_int * P, mp_int *Y) +{ + int dr; + + /* modulus P must be positive */ + if (P->sign == MP_NEG) { + return MP_VAL; + } + + /* if exponent X is negative we have to recurse */ + if (X->sign == MP_NEG) { + mp_int tmpG, tmpX; + int err; + + /* first compute 1/G mod P */ + if ((err = mp_init(&tmpG)) != MP_OKAY) { + return err; + } + if ((err = mp_invmod(&tmpG, G, P)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + + /* now get |X| */ + if ((err = mp_init(&tmpX)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + + /* and now compute (1/G)**|X| instead of G**X [X < 0] */ + err = mp_exptmod(&tmpG, &tmpX, P, Y); + mp_clear_multi(&tmpG, &tmpX, NULL); + return err; + } + +/* modified diminished radix reduction */ + if (mp_reduce_is_2k_l(P) == MP_YES) { + return s_mp_exptmod(G, X, P, Y, 1); + } + + /* is it a DR modulus? */ + dr = mp_dr_is_modulus(P); + + /* if not, is it a unrestricted DR modulus? */ + if (dr == 0) { + dr = mp_reduce_is_2k(P) << 1; + } + + /* if the modulus is odd or dr != 0 use the montgomery method */ + if (BN_is_odd (P) == 1 || dr != 0) { + return mp_exptmod_fast (G, X, P, Y, dr); + } else { + /* otherwise use the generic Barrett reduction technique */ + return s_mp_exptmod (G, X, P, Y, 0); + } +} + +/* reverse an array, used for radix code */ +static void +bn_reverse(unsigned char *s, int len) +{ + int ix, iy; + unsigned char t; + + ix = 0; + iy = len - 1; + while (ix < iy) { + t = s[ix]; + s[ix] = s[iy]; + s[iy] = t; + ++ix; + --iy; + } +} + +static int +s_is_power_of_two(mp_digit b, int *p) +{ + int x; + + /* fast return if no power of two */ + if ((b==0) || (b & (b-1))) { + return 0; + } + + for (x = 0; x < DIGIT_BIT; x++) { + if (b == (((mp_digit)1)<dp[0] & ((((mp_digit)1)<used)) != MP_OKAY) { + return res; + } + + q.used = a->used; + q.sign = a->sign; + w = 0; + for (ix = a->used - 1; ix >= 0; ix--) { + w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]); + + if (w >= b) { + t = (mp_digit)(w / b); + w -= ((mp_word)t) * ((mp_word)b); + } else { + t = 0; + } + q.dp[ix] = (mp_digit)t; + } + + if (d != NULL) { + *d = (mp_digit)w; + } + + if (c != NULL) { + mp_clamp(&q); + mp_exch(&q, c); + } + mp_clear(&q); + + return res; +} + +static int +mp_mod_d(mp_int *a, mp_digit b, mp_digit *c) +{ + return mp_div_d(a, b, NULL, c); +} + +static const mp_digit ltm_prime_tab[] = { + 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, + 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035, + 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059, + 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, +#ifndef MP_8BIT + 0x0083, + 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD, + 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF, + 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107, + 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137, + + 0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167, + 0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199, + 0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9, + 0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7, + 0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239, + 0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265, + 0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293, + 0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF, + + 0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301, + 0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B, + 0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371, + 0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD, + 0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5, + 0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419, + 0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449, + 0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B, + + 0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7, + 0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503, + 0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529, + 0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F, + 0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3, + 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7, + 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623, + 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653 +#endif +}; + +#define PRIME_SIZE __arraycount(ltm_prime_tab) + +static int +mp_prime_is_divisible(mp_int *a, int *result) +{ + int err, ix; + mp_digit res; + + /* default to not */ + *result = MP_NO; + + for (ix = 0; ix < (int)PRIME_SIZE; ix++) { + /* what is a mod LBL_prime_tab[ix] */ + if ((err = mp_mod_d (a, ltm_prime_tab[ix], &res)) != MP_OKAY) { + return err; + } + + /* is the residue zero? */ + if (res == 0) { + *result = MP_YES; + return MP_OKAY; + } + } + + return MP_OKAY; +} + +/* single digit addition */ +static int +mp_add_d(mp_int *a, mp_digit b, mp_int *c) +{ + int res, ix, oldused; + mp_digit *tmpa, *tmpc, mu; + + /* grow c as required */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* if a is negative and |a| >= b, call c = |a| - b */ + if (a->sign == MP_NEG && (a->used > 1 || a->dp[0] >= b)) { + /* temporarily fix sign of a */ + a->sign = MP_ZPOS; + + /* c = |a| - b */ + res = mp_sub_d(a, b, c); + + /* fix sign */ + a->sign = c->sign = MP_NEG; + + /* clamp */ + mp_clamp(c); + + return res; + } + + /* old number of used digits in c */ + oldused = c->used; + + /* sign always positive */ + c->sign = MP_ZPOS; + + /* source alias */ + tmpa = a->dp; + + /* destination alias */ + tmpc = c->dp; + + /* if a is positive */ + if (a->sign == MP_ZPOS) { + /* add digit, after this we're propagating + * the carry. + */ + *tmpc = *tmpa++ + b; + mu = *tmpc >> DIGIT_BIT; + *tmpc++ &= MP_MASK; + + /* now handle rest of the digits */ + for (ix = 1; ix < a->used; ix++) { + *tmpc = *tmpa++ + mu; + mu = *tmpc >> DIGIT_BIT; + *tmpc++ &= MP_MASK; + } + /* set final carry */ + ix++; + *tmpc++ = mu; + + /* setup size */ + c->used = a->used + 1; + } else { + /* a was negative and |a| < b */ + c->used = 1; + + /* the result is a single digit */ + if (a->used == 1) { + *tmpc++ = b - a->dp[0]; + } else { + *tmpc++ = b; + } + + /* setup count so the clearing of oldused + * can fall through correctly + */ + ix = 1; + } + + /* now zero to oldused */ + while (ix++ < oldused) { + *tmpc++ = 0; + } + mp_clamp(c); + + return MP_OKAY; +} + +/* single digit subtraction */ +static int +mp_sub_d(mp_int *a, mp_digit b, mp_int *c) +{ + mp_digit *tmpa, *tmpc, mu; + int res, ix, oldused; + + /* grow c as required */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* if a is negative just do an unsigned + * addition [with fudged signs] + */ + if (a->sign == MP_NEG) { + a->sign = MP_ZPOS; + res = mp_add_d(a, b, c); + a->sign = c->sign = MP_NEG; + + /* clamp */ + mp_clamp(c); + + return res; + } + + /* setup regs */ + oldused = c->used; + tmpa = a->dp; + tmpc = c->dp; + + /* if a <= b simply fix the single digit */ + if ((a->used == 1 && a->dp[0] <= b) || a->used == 0) { + if (a->used == 1) { + *tmpc++ = b - *tmpa; + } else { + *tmpc++ = b; + } + ix = 1; + + /* negative/1digit */ + c->sign = MP_NEG; + c->used = 1; + } else { + /* positive/size */ + c->sign = MP_ZPOS; + c->used = a->used; + + /* subtract first digit */ + *tmpc = *tmpa++ - b; + mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1); + *tmpc++ &= MP_MASK; + + /* handle rest of the digits */ + for (ix = 1; ix < a->used; ix++) { + *tmpc = *tmpa++ - mu; + mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1); + *tmpc++ &= MP_MASK; + } + } + + /* zero excess digits */ + while (ix++ < oldused) { + *tmpc++ = 0; + } + mp_clamp(c); + return MP_OKAY; +} + +static const int lnz[16] = { + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +}; + +/* Counts the number of lsbs which are zero before the first zero bit */ +static int +mp_cnt_lsb(mp_int *a) +{ + int x; + mp_digit q, qq; + + /* easy out */ + if (mp_iszero(a) == 1) { + return 0; + } + + /* scan lower digits until non-zero */ + for (x = 0; x < a->used && a->dp[x] == 0; x++); + q = a->dp[x]; + x *= DIGIT_BIT; + + /* now scan this digit until a 1 is found */ + if ((q & 1) == 0) { + do { + qq = q & 15; + x += lnz[qq]; + q >>= 4; + } while (qq == 0); + } + return x; +} + +/* c = a * a (mod b) */ +static int +mp_sqrmod(mp_int *a, mp_int *b, mp_int *c) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_sqr (a, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, b, c); + mp_clear (&t); + return res; +} +static int +mp_prime_miller_rabin(mp_int *a, mp_int *b, int *result) +{ + mp_int n1, y, r; + int s, j, err; + + /* default */ + *result = MP_NO; + + /* ensure b > 1 */ + if (mp_cmp_d(b, 1) != MP_GT) { + return MP_VAL; + } + + /* get n1 = a - 1 */ + if ((err = mp_init_copy (&n1, a)) != MP_OKAY) { + return err; + } + if ((err = mp_sub_d (&n1, 1, &n1)) != MP_OKAY) { + goto LBL_N1; + } + + /* set 2**s * r = n1 */ + if ((err = mp_init_copy (&r, &n1)) != MP_OKAY) { + goto LBL_N1; + } + + /* count the number of least significant bits + * which are zero + */ + s = mp_cnt_lsb(&r); + + /* now divide n - 1 by 2**s */ + if ((err = mp_div_2d (&r, s, &r, NULL)) != MP_OKAY) { + goto LBL_R; + } + + /* compute y = b**r mod a */ + if ((err = mp_init (&y)) != MP_OKAY) { + goto LBL_R; + } + if ((err = mp_exptmod (b, &r, a, &y)) != MP_OKAY) { + goto LBL_Y; + } + + /* if y != 1 and y != n1 do */ + if (mp_cmp_d (&y, 1) != MP_EQ && mp_cmp (&y, &n1) != MP_EQ) { + j = 1; + /* while j <= s-1 and y != n1 */ + while ((j <= (s - 1)) && mp_cmp (&y, &n1) != MP_EQ) { + if ((err = mp_sqrmod (&y, a, &y)) != MP_OKAY) { + goto LBL_Y; + } + + /* if y == 1 then composite */ + if (mp_cmp_d (&y, 1) == MP_EQ) { + goto LBL_Y; + } + + ++j; + } + + /* if y != n1 then composite */ + if (mp_cmp (&y, &n1) != MP_EQ) { + goto LBL_Y; + } + } + + /* probably prime now */ + *result = MP_YES; +LBL_Y:mp_clear (&y); +LBL_R:mp_clear (&r); +LBL_N1:mp_clear (&n1); + return err; +} + +/* performs a variable number of rounds of Miller-Rabin + * + * Probability of error after t rounds is no more than + + * + * Sets result to 1 if probably prime, 0 otherwise + */ +static int +mp_prime_is_prime(mp_int *a, int t, int *result) +{ + mp_int b; + int ix, err, res; + + /* default to no */ + *result = MP_NO; + + /* valid value of t? */ + if (t <= 0 || t > (int)PRIME_SIZE) { + return MP_VAL; + } + + /* is the input equal to one of the primes in the table? */ + for (ix = 0; ix < (int)PRIME_SIZE; ix++) { + if (mp_cmp_d(a, ltm_prime_tab[ix]) == MP_EQ) { + *result = 1; + return MP_OKAY; + } + } + + /* first perform trial division */ + if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) { + return err; + } + + /* return if it was trivially divisible */ + if (res == MP_YES) { + return MP_OKAY; + } + + /* now perform the miller-rabin rounds */ + if ((err = mp_init (&b)) != MP_OKAY) { + return err; + } + + for (ix = 0; ix < t; ix++) { + /* set the prime */ + mp_set (&b, ltm_prime_tab[ix]); + + if ((err = mp_prime_miller_rabin (a, &b, &res)) != MP_OKAY) { + goto LBL_B; + } + + if (res == MP_NO) { + goto LBL_B; + } + } + + /* passed the test */ + *result = MP_YES; +LBL_B:mp_clear (&b); + return err; +} + +/* returns size of ASCII reprensentation */ +static int +mp_radix_size (mp_int *a, int radix, int *size) +{ + int res, digs; + mp_int t; + mp_digit d; + + *size = 0; + + /* special case for binary */ + if (radix == 2) { + *size = mp_count_bits (a) + (a->sign == MP_NEG ? 1 : 0) + 1; + return MP_OKAY; + } + + /* make sure the radix is in range */ + if (radix < 2 || radix > 64) { + return MP_VAL; + } + + if (mp_iszero(a) == MP_YES) { + *size = 2; + return MP_OKAY; + } + + /* digs is the digit count */ + digs = 0; + + /* if it's negative add one for the sign */ + if (a->sign == MP_NEG) { + ++digs; + } + + /* init a copy of the input */ + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + /* force temp to positive */ + t.sign = MP_ZPOS; + + /* fetch out all of the digits */ + while (mp_iszero (&t) == MP_NO) { + if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { + mp_clear (&t); + return res; + } + ++digs; + } + mp_clear (&t); + + /* return digs + 1, the 1 is for the NULL byte that would be required. */ + *size = digs + 1; + return MP_OKAY; +} + +static const char *mp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; + +/* stores a bignum as a ASCII string in a given radix (2..64) + * + * Stores upto maxlen-1 chars and always a NULL byte + */ +static int +mp_toradix_n(mp_int * a, char *str, int radix, int maxlen) +{ + int res, digs; + mp_int t; + mp_digit d; + char *_s = str; + + /* check range of the maxlen, radix */ + if (maxlen < 2 || radix < 2 || radix > 64) { + return MP_VAL; + } + + /* quick out if its zero */ + if (mp_iszero(a) == MP_YES) { + *str++ = '0'; + *str = '\0'; + return MP_OKAY; + } + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + /* if it is negative output a - */ + if (t.sign == MP_NEG) { + /* we have to reverse our digits later... but not the - sign!! */ + ++_s; + + /* store the flag and mark the number as positive */ + *str++ = '-'; + t.sign = MP_ZPOS; + + /* subtract a char */ + --maxlen; + } + + digs = 0; + while (mp_iszero (&t) == 0) { + if (--maxlen < 1) { + /* no more room */ + break; + } + if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) { + mp_clear (&t); + return res; + } + *str++ = mp_s_rmap[d]; + ++digs; + } + + /* reverse the digits of the string. In this case _s points + * to the first digit [exluding the sign] of the number + */ + bn_reverse ((unsigned char *)_s, digs); + + /* append a NULL so the string is properly terminated */ + *str = '\0'; + + mp_clear (&t); + return MP_OKAY; +} + +static char * +formatbn(const BIGNUM *a, const int radix) +{ + char *s; + int len; + + if (mp_radix_size(__UNCONST(a), radix, &len) != MP_OKAY) { + return NULL; + } + if ((s = netpgp_allocate(1, len)) != NULL) { + if (mp_toradix_n(__UNCONST(a), s, radix, len) != MP_OKAY) { + netpgp_deallocate(s, len); + return NULL; + } + } + return s; +} + +static int +mp_getradix_num(mp_int *a, int radix, char *s) +{ + int err, ch, neg, y; + + /* clear a */ + mp_zero(a); + + /* if first digit is - then set negative */ + if ((ch = *s++) == '-') { + neg = MP_NEG; + ch = *s++; + } else { + neg = MP_ZPOS; + } + + for (;;) { + /* find y in the radix map */ + for (y = 0; y < radix; y++) { + if (mp_s_rmap[y] == ch) { + break; + } + } + if (y == radix) { + break; + } + + /* shift up and add */ + if ((err = mp_mul_d(a, radix, a)) != MP_OKAY) { + return err; + } + if ((err = mp_add_d(a, y, a)) != MP_OKAY) { + return err; + } + + ch = *s++; + } + if (mp_cmp_d(a, 0) != MP_EQ) { + a->sign = neg; + } + + return MP_OKAY; +} + +static int +getbn(BIGNUM **a, const char *str, int radix) +{ + int len; + + if (a == NULL || str == NULL || (*a = BN_new()) == NULL) { + return 0; + } + if (mp_getradix_num(*a, radix, __UNCONST(str)) != MP_OKAY) { + return 0; + } + mp_radix_size(__UNCONST(a), radix, &len); + return len - 1; +} + +/* d = a - b (mod c) */ +static int +mp_submod(mp_int *a, mp_int *b, mp_int *c, mp_int *d) +{ + int res; + mp_int t; + + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_sub (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} + +/**************************************************************************/ + +/* BIGNUM emulation layer */ + +/* essentiually, these are just wrappers around the libtommath functions */ +/* usually the order of args changes */ +/* the BIGNUM API tends to have more const poisoning */ +/* these wrappers also check the arguments passed for sanity */ + +BIGNUM * +BN_bin2bn(const uint8_t *data, int len, BIGNUM *ret) +{ + if (data == NULL) { + return BN_new(); + } + if (ret == NULL) { + ret = BN_new(); + } + return (mp_read_unsigned_bin(ret, data, len) == MP_OKAY) ? ret : NULL; +} + +/* store in unsigned [big endian] format */ +int +BN_bn2bin(const BIGNUM *a, unsigned char *b) +{ + BIGNUM t; + int x; + + if (a == NULL || b == NULL) { + return -1; + } + if (mp_init_copy (&t, __UNCONST(a)) != MP_OKAY) { + return -1; + } + for (x = 0; !BN_is_zero(&t) ; ) { + b[x++] = (unsigned char) (t.dp[0] & 0xff); + if (mp_div_2d (&t, 8, &t, NULL) != MP_OKAY) { + mp_clear(&t); + return -1; + } + } + bn_reverse(b, x); + mp_clear(&t); + return x; +} + +void +BN_init(BIGNUM *a) +{ + if (a != NULL) { + mp_init(a); + } +} + +BIGNUM * +BN_new(void) +{ + BIGNUM *a; + + if ((a = netpgp_allocate(1, sizeof(*a))) != NULL) { + mp_init(a); + } + return a; +} + +/* copy, b = a */ +int +BN_copy(BIGNUM *b, const BIGNUM *a) +{ + if (a == NULL || b == NULL) { + return MP_VAL; + } + return mp_copy(__UNCONST(a), b); +} + +BIGNUM * +BN_dup(const BIGNUM *a) +{ + BIGNUM *ret; + + if (a == NULL) { + return NULL; + } + if ((ret = BN_new()) != NULL) { + BN_copy(ret, a); + } + return ret; +} + +void +BN_swap(BIGNUM *a, BIGNUM *b) +{ + if (a && b) { + mp_exch(a, b); + } +} + +int +BN_lshift(BIGNUM *r, const BIGNUM *a, int n) +{ + if (r == NULL || a == NULL || n < 0) { + return 0; + } + BN_copy(r, a); + return mp_lshd(r, n) == MP_OKAY; +} + +int +BN_lshift1(BIGNUM *r, BIGNUM *a) +{ + if (r == NULL || a == NULL) { + return 0; + } + BN_copy(r, a); + return mp_lshd(r, 1) == MP_OKAY; +} + +int +BN_rshift(BIGNUM *r, const BIGNUM *a, int n) +{ + if (r == NULL || a == NULL || n < 0) { + return MP_VAL; + } + BN_copy(r, a); + return mp_rshd(r, n) == MP_OKAY; +} + +int +BN_rshift1(BIGNUM *r, BIGNUM *a) +{ + if (r == NULL || a == NULL) { + return 0; + } + BN_copy(r, a); + return mp_rshd(r, 1) == MP_OKAY; +} + +int +BN_set_word(BIGNUM *a, BN_ULONG w) +{ + if (a == NULL) { + return 0; + } + mp_set(a, w); + return 1; +} + +int +BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) +{ + if (a == NULL || b == NULL || r == NULL) { + return 0; + } + return mp_add(__UNCONST(a), __UNCONST(b), r) == MP_OKAY; +} + +int +BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) +{ + if (a == NULL || b == NULL || r == NULL) { + return 0; + } + return mp_sub(__UNCONST(a), __UNCONST(b), r) == MP_OKAY; +} + +int +BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) +{ + if (a == NULL || b == NULL || r == NULL) { + return 0; + } + USE_ARG(ctx); + return mp_mul(__UNCONST(a), __UNCONST(b), r) == MP_OKAY; +} + +int +BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *a, const BIGNUM *d, BN_CTX *ctx) +{ + if ((dv == NULL && rem == NULL) || a == NULL || d == NULL) { + return 0; + } + USE_ARG(ctx); + return mp_div(dv, rem, __UNCONST(a), __UNCONST(d)) == MP_OKAY; +} + +void +BN_free(BIGNUM *a) +{ + if (a) { + mp_clear(a); + } +} + +void +BN_clear(BIGNUM *a) +{ + if (a) { + mp_clear(a); + } +} + +void +BN_clear_free(BIGNUM *a) +{ + if (a) { + mp_clear(a); + } +} + +int +BN_num_bytes(const BIGNUM *a) +{ + if (a == NULL) { + return MP_VAL; + } + return mp_unsigned_bin_size(__UNCONST(a)); +} + +int +BN_num_bits(const BIGNUM *a) +{ + if (a == NULL) { + return 0; + } + return mp_count_bits(a); +} + +void +BN_set_negative(BIGNUM *a, int n) +{ + if (a) { + a->sign = (n) ? MP_NEG : 0; + } +} + +int +BN_cmp(BIGNUM *a, BIGNUM *b) +{ + if (a == NULL || b == NULL) { + return MP_VAL; + } + switch(mp_cmp(a, b)) { + case MP_LT: + return -1; + case MP_GT: + return 1; + case MP_EQ: + default: + return 0; + } +} + +int +BN_mod_exp(BIGNUM *Y, BIGNUM *G, BIGNUM *X, BIGNUM *P, BN_CTX *ctx) +{ + if (Y == NULL || G == NULL || X == NULL || P == NULL) { + return MP_VAL; + } + USE_ARG(ctx); + return mp_exptmod(G, X, P, Y) == MP_OKAY; +} + +BIGNUM * +BN_mod_inverse(BIGNUM *r, BIGNUM *a, const BIGNUM *n, BN_CTX *ctx) +{ + USE_ARG(ctx); + if (r == NULL || a == NULL || n == NULL) { + return NULL; + } + return (mp_invmod(r, a, __UNCONST(n)) == MP_OKAY) ? r : NULL; +} + +int +BN_mod_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, const BIGNUM *m, BN_CTX *ctx) +{ + USE_ARG(ctx); + if (ret == NULL || a == NULL || b == NULL || m == NULL) { + return 0; + } + return mp_mulmod(ret, a, b, __UNCONST(m)) == MP_OKAY; +} + +BN_CTX * +BN_CTX_new(void) +{ + return netpgp_allocate(1, sizeof(BN_CTX)); +} + +void +BN_CTX_init(BN_CTX *c) +{ + if (c != NULL) { + c->arraysize = 15; + if ((c->v = netpgp_allocate(sizeof(*c->v), c->arraysize)) == NULL) { + c->arraysize = 0; + } + } +} + +BIGNUM * +BN_CTX_get(BN_CTX *ctx) +{ + if (ctx == NULL || ctx->v == NULL || ctx->arraysize == 0 || ctx->count == ctx->arraysize - 1) { + return NULL; + } + return ctx->v[ctx->count++] = BN_new(); +} + +void +BN_CTX_start(BN_CTX *ctx) +{ + BN_CTX_init(ctx); +} + +void +BN_CTX_free(BN_CTX *c) +{ + unsigned i; + + if (c != NULL && c->v != NULL) { + for (i = 0 ; i < c->count ; i++) { + BN_clear_free(c->v[i]); + } + netpgp_deallocate(c->v, sizeof(*c->v) * c->arraysize); + } +} + +void +BN_CTX_end(BN_CTX *ctx) +{ + BN_CTX_free(ctx); +} + +char * +BN_bn2hex(const BIGNUM *a) +{ + return (a == NULL) ? NULL : formatbn(a, 16); +} + +char * +BN_bn2dec(const BIGNUM *a) +{ + return (a == NULL) ? NULL : formatbn(a, 10); +} + +#ifndef _KERNEL +int +BN_print_fp(FILE *fp, const BIGNUM *a) +{ + char *s; + int ret; + + if (fp == NULL || a == NULL) { + return 0; + } + s = BN_bn2hex(a); + ret = fprintf(fp, "%s", s); + netpgp_deallocate(s, strlen(s) + 1); + return ret; +} +#endif + +int +BN_rand(BIGNUM *rnd, int bits, int top, int bottom) +{ + uint64_t r; + int digits; + int i; + + if (rnd == NULL) { + return 0; + } + mp_init_size(rnd, digits = howmany(bits, DIGIT_BIT)); + for (i = 0 ; i < digits ; i++) { + r = (uint64_t)arc4random(); + r <<= 32; + r |= arc4random(); + rnd->dp[i] = (r & MP_MASK); + } + if (top == 0) { + rnd->dp[rnd->used - 1] |= (((mp_digit)1)<<((mp_digit)DIGIT_BIT)); + } + if (top == 1) { + rnd->dp[rnd->used - 1] |= (((mp_digit)1)<<((mp_digit)DIGIT_BIT)); + rnd->dp[rnd->used - 1] |= (((mp_digit)1)<<((mp_digit)(DIGIT_BIT - 1))); + } + if (bottom) { + rnd->dp[0] |= 0x1; + } + return 1; +} + +int +BN_rand_range(BIGNUM *rnd, BIGNUM *range) +{ + if (rnd == NULL || range == NULL || BN_is_zero(range)) { + return 0; + } + BN_rand(rnd, BN_num_bits(range), 1, 0); + return mp_mod(rnd, range, rnd) == MP_OKAY; +} + +int +BN_is_prime(const BIGNUM *a, int checks, void (*callback)(int, int, void *), BN_CTX *ctx, void *cb_arg) +{ + int primality; + + if (a == NULL) { + return 0; + } + USE_ARG(ctx); + USE_ARG(cb_arg); + USE_ARG(callback); + return (mp_prime_is_prime(__UNCONST(a), checks, &primality) == MP_OKAY) ? primality : 0; +} + +const BIGNUM * +BN_value_one(void) +{ + static mp_digit digit = 1UL; + static const BIGNUM one = { &digit, 1, 1, 0 }; + + return &one; +} + +int +BN_hex2bn(BIGNUM **a, const char *str) +{ + return getbn(a, str, 16); +} + +int +BN_dec2bn(BIGNUM **a, const char *str) +{ + return getbn(a, str, 10); +} + +int +BN_mod_sub(BIGNUM *r, BIGNUM *a, BIGNUM *b, const BIGNUM *m, BN_CTX *ctx) +{ + USE_ARG(ctx); + if (r == NULL || a == NULL || b == NULL || m == NULL) { + return 0; + } + return mp_submod(a, b, __UNCONST(m), r) == MP_OKAY; +} + +int +BN_is_bit_set(const BIGNUM *a, int n) +{ + if (a == NULL || n < 0 || n >= a->used * DIGIT_BIT) { + return 0; + } + return (a->dp[n / DIGIT_BIT] & (1 << (n % DIGIT_BIT))) ? 1 : 0; +} diff --git a/crypto/external/bsd/netpgp/dist/src/libbn/bn.h b/crypto/external/bsd/netpgp/dist/src/libbn/bn.h new file mode 100644 index 000000000000..f5a1d8c696ea --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libbn/bn.h @@ -0,0 +1,145 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef FAUXBN_H_ +#define FAUXBN_H_ 20100108 + +#include + +#ifndef _KERNEL +# include +# include +#endif + +#ifndef __BEGIN_DECLS +# if defined(__cplusplus) +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +# else +# define __BEGIN_DECLS +# define __END_DECLS +# endif +#endif + +__BEGIN_DECLS + +typedef unsigned long mp_digit; +typedef unsigned long mp_word __attribute__ ((mode(TI))); + +/* multi-precision integer */ +typedef struct mp_int { + mp_digit *dp; /* array of digits */ + int used; /* # of digits used */ + int alloc; /* # of digits allocated */ + int sign; /* non-zero if negative */ +} mp_int; + +#define BIGNUM mp_int +#define BN_ULONG mp_digit + +/* a "context" of mp integers - never really used */ +typedef struct bn_ctx_t { + size_t count; + size_t arraysize; + BIGNUM **v; +} BN_CTX; + +#define MP_LT -1 +#define MP_EQ 0 +#define MP_GT 1 + +#define MP_ZPOS 0 +#define MP_NEG 1 + +#define MP_OKAY 0 +#define MP_MEM -2 +#define MP_VAL -3 +#define MP_RANGE MP_VAL + +/*********************************/ + +#define BN_is_negative(x) ((x)->sign == MP_NEG) +#define BN_is_zero(a) (((a)->used == 0) ? 1 : 0) +#define BN_is_odd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? 1 : 0) +#define BN_is_even(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? 1 : 0) + +BIGNUM *BN_new(void); +BIGNUM *BN_dup(const BIGNUM */*a*/); +int BN_copy(BIGNUM */*b*/, const BIGNUM */*a*/); + +void BN_init(BIGNUM */*a*/); +void BN_free(BIGNUM */*a*/); +void BN_clear(BIGNUM */*a*/); +void BN_clear_free(BIGNUM */*a*/); + +int BN_cmp(BIGNUM */*a*/, BIGNUM */*b*/); + +BIGNUM *BN_bin2bn(const uint8_t */*buf*/, int /*size*/, BIGNUM */*bn*/); +int BN_bn2bin(const BIGNUM */*a*/, unsigned char */*b*/); +char *BN_bn2hex(const BIGNUM */*a*/); +char *BN_bn2dec(const BIGNUM */*a*/); +int BN_hex2bn(BIGNUM **/*a*/, const char */*str*/); +int BN_dec2bn(BIGNUM **/*a*/, const char */*str*/); +#ifndef _KERNEL +int BN_print_fp(FILE */*fp*/, const BIGNUM */*a*/); +#endif + +int BN_add(BIGNUM */*r*/, const BIGNUM */*a*/, const BIGNUM */*b*/); +int BN_sub(BIGNUM */*r*/, const BIGNUM */*a*/, const BIGNUM */*b*/); +int BN_mul(BIGNUM */*r*/, const BIGNUM */*a*/, const BIGNUM */*b*/, BN_CTX */*ctx*/); +int BN_div(BIGNUM */*q*/, BIGNUM */*r*/, const BIGNUM */*a*/, const BIGNUM */*b*/, BN_CTX */*ctx*/); +void BN_swap(BIGNUM */*a*/, BIGNUM */*b*/); +int BN_lshift(BIGNUM */*r*/, const BIGNUM */*a*/, int /*n*/); +int BN_lshift1(BIGNUM */*r*/, BIGNUM */*a*/); +int BN_rshift(BIGNUM */*r*/, const BIGNUM */*a*/, int /*n*/); +int BN_rshift1(BIGNUM */*r*/, BIGNUM */*a*/); +int BN_set_word(BIGNUM */*a*/, BN_ULONG /*w*/); +void BN_set_negative(BIGNUM */*a*/, int /*n*/); + +int BN_num_bytes(const BIGNUM */*a*/); +int BN_num_bits(const BIGNUM */*a*/); + +int BN_mod_exp(BIGNUM */*r*/, BIGNUM */*a*/, BIGNUM */*p*/, BIGNUM */*m*/, BN_CTX */*ctx*/); +BIGNUM *BN_mod_inverse(BIGNUM */*ret*/, BIGNUM */*a*/, const BIGNUM */*n*/, BN_CTX */*ctx*/); +int BN_mod_mul(BIGNUM */*ret*/, BIGNUM */*a*/, BIGNUM */*b*/, const BIGNUM */*m*/, BN_CTX */*ctx*/); +int BN_mod_sub(BIGNUM */*r*/, BIGNUM */*a*/, BIGNUM */*b*/, const BIGNUM */*m*/, BN_CTX */*ctx*/); + +BN_CTX *BN_CTX_new(void); +BIGNUM *BN_CTX_get(BN_CTX */*ctx*/); +void BN_CTX_start(BN_CTX */*ctx*/); +void BN_CTX_end(BN_CTX */*ctx*/); +void BN_CTX_init(BN_CTX */*c*/); +void BN_CTX_free(BN_CTX */*c*/); + +int BN_rand(BIGNUM */*rnd*/, int /*bits*/, int /*top*/, int /*bottom*/); +int BN_rand_range(BIGNUM */*rnd*/, BIGNUM */*range*/); + +int BN_is_prime(const BIGNUM */*a*/, int /*checks*/, void (*callback)(int, int, void *), BN_CTX */*ctx*/, void */*cb_arg*/); + +const BIGNUM *BN_value_one(void); +int BN_is_bit_set(const BIGNUM */*a*/, int /*n*/); + +__END_DECLS + +#endif diff --git a/crypto/external/bsd/netpgp/dist/src/libbn/libnetpgpbn.3 b/crypto/external/bsd/netpgp/dist/src/libbn/libnetpgpbn.3 new file mode 100644 index 000000000000..59a9864459a2 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libbn/libnetpgpbn.3 @@ -0,0 +1,304 @@ +.\" $NetBSD: libnetpgpbn.3,v 1.2 2012/11/20 05:26:25 agc Exp $ +.\" +.\" Copyright (c) 2010 Alistair Crooks +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd April 13, 2012 +.Dt LIBNETPGPBN 3 +.Os +.Sh NAME +.Nm libnetpgpbn +.Nd BIGNUM library of multi-precision integers +.Sh LIBRARY +.Lb libnetpgpbn +.Sh SYNOPSIS +.In netpgp/bn.h +.Ft BIGNUM * +.Fo BN_new +.Fa "void" +.Fc +.Ft BIGNUM * +.Fo BN_dup +.Fa "const BIGNUM *orig" +.Fc +.Ft int +.Fo BN_copy +.Fa "BIGNUM *to" "const BIGNUM *from" +.Fc +.Ft void +.Fo BN_swap +.Fa "BIGNUM *a" "BIGNUM *b" +.Fc +.Pp +.Ft void +.Fo BN_init +.Fa "BIGNUM *bn" +.Fc +.Ft void +.Fo BN_free +.Fa "BIGNUM *bn" +.Fc +.Ft void +.Fo BN_clear +.Fa "BIGNUM *bn" +.Fc +.Ft void +.Fo BN_clear_free +.Fa "BIGNUM *bn" +.Fc +.Pp +.Ft void +.Fo BN_clear_free +.Fa "BIGNUM *bn" +.Fc +.Pp +.Ft int +.Fo BN_cmp +.Fa "BIGNUM *lhs" "BIGNUM *rhs" +.Fc +.Ft int +.Fo BN_is_negative +.Fa "BIGNUM *bn" +.Fc +.Ft int +.Fo BN_is_zero +.Fa "BIGNUM *bn" +.Fc +.Ft int +.Fo BN_is_odd +.Fa "BIGNUM *bn" +.Fc +.Ft int +.Fo BN_is_even +.Fa "BIGNUM *bn" +.Fc +.Pp +.Ft BIGNUM * +.Fo BN_bin2bn +.Fa "const uint8_t *buf" "int size" "BIGNUM *bn" +.Fc +.Ft int +.Fo BN_bn2bin +.Fa "BIGNUM *bn" "uint8_t *buf" +.Fc +.Ft int +.Fo BN_bn2bin +.Fa "BIGNUM *bn" "uint8_t *buf" +.Fc +.Ft char * +.Fo BN_bn2hex +.Fa "const BIGNUM *bn" +.Fc +.Ft char * +.Fo BN_bn2dec +.Fa "const BIGNUM *bn" +.Fc +.Ft int +.Fo BN_hex2bn +.Fa "BIGNUM **bn" "const char *str" +.Fc +.Ft int +.Fo BN_dec2bn +.Fa "BIGNUM **bn" "const char *str" +.Fc +.Ft int +.Fo BN_print_fp +.Fa "FILE *fp" "const BIGNUM *bn" +.Fc +.Pp +.Ft int +.Fo BN_add +.Fa "BIGNUM *sum" "const BIGNUM *a" "const BIGNUM *b" +.Fc +.Ft int +.Fo BN_sub +.Fa "BIGNUM *sum" "const BIGNUM *a" "const BIGNUM *b" +.Fc +.Ft int +.Fo BN_mul +.Fa "BIGNUM *product" "const BIGNUM *a" "const BIGNUM *b" "BN_CTX *context" +.Fc +.Ft int +.Fo BN_div +.Fa "BIGNUM *quotient" "BIGNUM *remainder" "const BIGNUM *a" "const BIGNUM *b" "BN_CTX *context" +.Fc +.Pp +.Ft int +.Fo BN_lshift +.Fa "BIGNUM *result" "const BIGNUM *bn" "int n" +.Fc +.Ft int +.Fo BN_lshift1 +.Fa "BIGNUM *result" "const BIGNUM *bn" +.Fc +.Ft int +.Fo BN_rshift +.Fa "BIGNUM *result" "const BIGNUM *bn" "int n" +.Fc +.Ft int +.Fo BN_rshift1 +.Fa "BIGNUM *result" "const BIGNUM *bn" +.Fc +.Pp +.Ft int +.Fo BN_set_word +.Fa "BIGNUM *result" "unsigned long val" +.Fc +.Ft int +.Fo BN_set_negative +.Fa "BIGNUM *result" "int val" +.Fc +.Pp +.Ft int +.Fo BN_num_bytes +.Fa "const BIGNUM *bn" +.Fc +.Ft int +.Fo BN_num_bits +.Fa "const BIGNUM *bn" +.Fc +.Pp +.Ft int +.Fo BN_mod_exp +.Fa "BIGNUM *result" "BIGNUM *a" "BIGNUM *p" "BIGNUM *m" "BN_CTX *context" +.Fc +.Ft BIGNUM * +.Fo BN_mod_inverse +.Fa "BIGNUM *result" "BIGNUM *a" "BIGNUM *n" "BN_CTX *context" +.Fc +.Ft int +.Fo BN_mod_mul +.Fa "BIGNUM *result" "BIGNUM *a" "BIGNUM *b" "BIGNUM *m" "BN_CTX *context" +.Fc +.Ft int +.Fo BN_mod_sub +.Fa "BIGNUM *result" "BIGNUM *a" "BIGNUM *b" "BIGNUM *m" "BN_CTX *context" +.Fc +.Pp +.Ft BN_CTX * +.Fo BN_CTX_new +.Fa "void" +.Fc +.Ft BIGNUM * +.Fo BN_CTX_get +.Fa "BN_CTX *context" +.Fc +.Ft void +.Fo BN_CTX_start +.Fa "BN_CTX *context" +.Fc +.Ft void +.Fo BN_CTX_end +.Fa "BN_CTX *context" +.Fc +.Ft void +.Fo BN_CTX_init +.Fa "BN_CTX *context" +.Fc +.Ft void +.Fo BN_CTX_free +.Fa "BN_CTX *context" +.Fc +.Ft int +.Fo BN_rand +.Fa "BIGNUM *result" "int bits" "int top" "int bottom" +.Fc +.Ft int +.Fo BN_rand_range +.Fa "BIGNUM *result" "BIGNUM *range" +.Fc +.Ft int +.Fo BN_is_prime +.Fa "const BIGNUM *bn" "int checks" "void (*callback)(int int void)" +.Fa "BN_CTX *context" "void *callbackarg" +.Fc +.Pp +.Ft const BIGNUM * +.Fo BN_value_one +.Fa "void" +.Fc +.Ft int +.Fo BN_is_bit_set +.Fa "const BIGNUM *bn" "int n" +.Fc +.Sh DESCRIPTION +.Nm +emulates the API of the openssl +.Xr bn 3 +library. +It is implemented using Tom St Denis +.Dq libtommath +library. +.Sh EXAMPLES +The follow code fragment will make a JSON object +out of the string +.Dq Hello \en +in the +buffer called +.Dq buf +where +.Dq USERNAME +is the name of the user taken from the runtime environment. +The encoded text will be in an allocated buffer called +.Dq s +.Bd -literal -offset indent +mj_t atom; +char buf[BUFSIZ]; +char *s; +int cc; + +(void) memset(\*[Am]atom, 0x0, sizeof(atom)); +cc = snprintf(buf, sizeof(buf), "Hello %s\en", getenv("USER")); +mj_create(\*[Am]atom, "string", buf, cc); +cc = mj_asprint(\*[Am]s, \*[Am]atom, MJ_JSON_ENCODE); +.Ed +.Pp +and the following example will take the (binary) text which has been encoded into +JSON and is in the buffer +.Dq buf , +such as in the previous example, and re-create the original text: +.Bd -literal -offset indent +int from, to, tok, cc; +char *s; +mj_t atom; + +(void) memset(\*[Am]atom, 0x0, sizeof(atom)); +from = to = tok = 0; +mj_parse(\*[Am]atom, buf, \*[Am]from, \*[Am]to, \*[Am]tok); +cc = mj_asprint(\*[Am]s, \*[Am]atom, MJ_HUMAN); +printf("%.*s", cc, s); +.Ed +.Pp +The +.Dv s +pointer points to allocated storage with the original NUL-terminated string +in it. +.Sh SEE ALSO +.Xr bn 3 +.Sh HISTORY +The +.Nm +library first appeared in +.Nx 7.0 . +.Sh AUTHORS +.An Alistair Crooks Aq agc@NetBSD.org diff --git a/crypto/external/bsd/netpgp/dist/src/libbn/misc.c b/crypto/external/bsd/netpgp/dist/src/libbn/misc.c new file mode 100644 index 000000000000..b3bb5ea68f83 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libbn/misc.c @@ -0,0 +1,82 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include + +#ifdef _KERNEL +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include "misc.h" + +#ifndef USE_ARG +#define USE_ARG(x) /*LINTED*/(void)&(x) +#endif + +void * +netpgp_allocate(size_t n, size_t nels) +{ +#ifdef _KERNEL + return kmem_zalloc(n * nels, KM_SLEEP); +#else + return calloc(n, nels); +#endif +} + +void +netpgp_deallocate(void *ptr, size_t size) +{ +#ifdef _KERNEL + kmem_free(ptr, size); +#else + USE_ARG(size); + free(ptr); +#endif +} + +#ifndef _KERNEL +void +logmessage(const int level, const char *fmt, ...) +{ + va_list args; + + USE_ARG(level); + if (fmt != NULL) { + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + } +} +#endif diff --git a/crypto/external/bsd/netpgp/dist/src/libbn/misc.h b/crypto/external/bsd/netpgp/dist/src/libbn/misc.h new file mode 100644 index 000000000000..dbace86fdcf6 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libbn/misc.h @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef MISC_H_ +#define MISC_H_ 20110705 + +#include + +#include + +#ifndef __BEGIN_DECLS +# if defined(__cplusplus) +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +# else +# define __BEGIN_DECLS +# define __END_DECLS +# endif +#endif + +__BEGIN_DECLS + +void *netpgp_allocate(size_t /*n*/, size_t /*nels*/); +void netpgp_deallocate(void */*ptr*/, size_t /*size*/); + +#ifndef _KERNEL +void logmessage(const int /*level*/, const char */*fmt*/, ...); +#endif + +__END_DECLS + +#endif diff --git a/crypto/external/bsd/netpgp/dist/src/libbn/rand.c b/crypto/external/bsd/netpgp/dist/src/libbn/rand.c new file mode 100644 index 000000000000..d2bcc1196e6d --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libbn/rand.c @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include + +#ifdef _KERNEL +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include "rand.h" + +int +RAND_bytes(unsigned char *buf, int num) +{ + uint32_t r; + size_t cc; + int i; + + if (buf == NULL || num < 0) { + return 0; + } + for (i = 0 ; i < num ; i += sizeof(r)) { + r = arc4random(); + cc = MIN(sizeof(r), (size_t)(num - i)); + (void) memcpy(&buf[i], &r, cc); + } + return 1; +} diff --git a/crypto/external/bsd/netpgp/dist/src/libbn/rand.h b/crypto/external/bsd/netpgp/dist/src/libbn/rand.h new file mode 100644 index 000000000000..c2bdc9501494 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libbn/rand.h @@ -0,0 +1,44 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef RAND_H_ +#define RAND_H_ 20120327 + +#ifndef __BEGIN_DECLS +# if defined(__cplusplus) +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +# else +# define __BEGIN_DECLS +# define __END_DECLS +# endif +#endif + +__BEGIN_DECLS + +int RAND_bytes(unsigned char */*buf*/, int /*len*/); + +__END_DECLS + +#endif diff --git a/crypto/external/bsd/netpgp/dist/src/libbn/stubs.c b/crypto/external/bsd/netpgp/dist/src/libbn/stubs.c new file mode 100644 index 000000000000..5e78fab880b1 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libbn/stubs.c @@ -0,0 +1,217 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include + +#ifdef _KERNEL +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include "misc.h" +#include "bn.h" + +#include "stubs.h" + +#ifndef USE_ARG +#define USE_ARG(x) /*LINTED*/(void)&(x) +#endif + +void +OpenSSL_add_all_algorithms(void) +{ +} + +void +OPENSSL_add_all_algorithms_noconf(void) +{ +} + +void +CRYPTO_cleanup_all_ex_data(void) +{ +} + +BIO * +BIO_new_fd(int fd, int close_flag) +{ + USE_ARG(fd); + USE_ARG(close_flag); + return NULL; +} + +unsigned long +ERR_get_error(void) +{ + return 0; +} + +char * +ERR_error_string(unsigned long e, char *buf) +{ + static char staticbuf[120]; + + if (buf == NULL) { + buf = staticbuf; + } + snprintf(buf, 120, "error:%lu:netssl:[unknown function]:[unknown error]", e); + return buf; +} + +void +ERR_remove_state(unsigned long pid) +{ + USE_ARG(pid); +} + +void +ERR_print_errors(BIO *bp) +{ + USE_ARG(bp); +} + +void +idea_set_encrypt_key(uint8_t *key, IDEA_KEY_SCHEDULE *ks) +{ + printf("idea_set_encrypt_key stubbed\n"); + USE_ARG(key); + USE_ARG(ks); +} + +void +idea_set_decrypt_key(IDEA_KEY_SCHEDULE *encrypt_ks, IDEA_KEY_SCHEDULE *decrypt_ks) +{ + printf("idea_set_decrypt_key stubbed\n"); + USE_ARG(encrypt_ks); + USE_ARG(decrypt_ks); +} + +void +idea_cfb64_encrypt(uint8_t *in, uint8_t *out, long length, des_key_schedule *ks, des_cblock *ivec, int *num, int enc) +{ + printf("idea_cfb64_encrypt stubbed\n"); + USE_ARG(in); + USE_ARG(out); + USE_ARG(length); + USE_ARG(ks); + USE_ARG(ivec); + USE_ARG(num); + USE_ARG(enc); +} + +void +idea_ecb_encrypt(uint8_t *in, uint8_t *out, IDEA_KEY_SCHEDULE *ks) +{ + printf("idea_cfb64_decrypt stubbed\n"); + USE_ARG(in); + USE_ARG(out); + USE_ARG(ks); +} + +int +Camellia_set_key(const unsigned char *userKey, const int bits, CAMELLIA_KEY *key) +{ + printf("Camellia_set_key stubbed\n"); + USE_ARG(userKey); + USE_ARG(bits); + USE_ARG(key); + return 0; +} + +void +Camellia_encrypt(const unsigned char *in, unsigned char *out, const CAMELLIA_KEY *key) +{ + printf("Camellia_encrypt stubbed\n"); + USE_ARG(in); + USE_ARG(out); + USE_ARG(key); +} + +void +Camellia_cfb128_encrypt(const unsigned char *in, unsigned char *out, size_t length, const CAMELLIA_KEY *key, unsigned char *ivec, int *num, const int enc) +{ + printf("Camellia_cfb128_encrypt stubbed\n"); + USE_ARG(in); + USE_ARG(out); + USE_ARG(length); + USE_ARG(key); + USE_ARG(ivec); + USE_ARG(num); + USE_ARG(enc); +} + +void +Camellia_decrypt(const unsigned char *in, unsigned char *out, const CAMELLIA_KEY *key) +{ + printf("Camellia_decrypt stubbed\n"); + USE_ARG(in); + USE_ARG(out); + USE_ARG(key); +} + +int +DES_set_key(const_DES_cblock *key, DES_key_schedule *schedule) +{ + printf("DES_set_key stubbed\n"); + USE_ARG(key); + USE_ARG(schedule); + return 0; +} + +void +DES_ecb3_encrypt(const_DES_cblock *input, DES_cblock *output, DES_key_schedule *ks1,DES_key_schedule *ks2, DES_key_schedule *ks3, int enc) +{ + printf("DES_ecb3_encrypt stubbed\n"); + USE_ARG(input); + USE_ARG(output); + USE_ARG(ks1); + USE_ARG(ks2); + USE_ARG(ks3); + USE_ARG(enc); +} + +void +DES_ede3_cfb64_encrypt(const unsigned char *in,unsigned char *out, long length,DES_key_schedule *ks1, DES_key_schedule *ks2,DES_key_schedule *ks3, DES_cblock *ivec,int *num,int enc) +{ + printf("DES_ede3_cfb64_encrypt stubbed\n"); + USE_ARG(in); + USE_ARG(out); + USE_ARG(length); + USE_ARG(ks1); + USE_ARG(ks2); + USE_ARG(ks3); + USE_ARG(ivec); + USE_ARG(num); + USE_ARG(enc); +} diff --git a/crypto/external/bsd/netpgp/dist/src/libbn/stubs.h b/crypto/external/bsd/netpgp/dist/src/libbn/stubs.h new file mode 100644 index 000000000000..6441b22606c1 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libbn/stubs.h @@ -0,0 +1,94 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef STUBS_H_ +#define STUBS_H_ 20120327 + +#ifndef __BEGIN_DECLS +# if defined(__cplusplus) +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +# else +# define __BEGIN_DECLS +# define __END_DECLS +# endif +#endif + +__BEGIN_DECLS + +/*********************************/ +/* stubs */ +/*********************************/ + +void OpenSSL_add_all_algorithms(void); +void OPENSSL_add_all_algorithms_noconf(void); +void CRYPTO_cleanup_all_ex_data(void); + +#include + +#define BIO FILE + +BIO *BIO_new_fd(int /*fd*/, int /*close_flag*/); + +unsigned long ERR_get_error(void); +char *ERR_error_string(unsigned long /*e*/, char */*buf*/); +void ERR_remove_state(unsigned long /*pid*/); +void ERR_print_errors(BIO */*bp*/); + +#define IDEA_KEY_SCHEDULE void +#define des_key_schedule void +#define des_cblock void +#define IDEA_DECRYPT 0 +#define IDEA_ENCRYPT 1 +#define IDEA_BLOCK 8 +#define IDEA_KEY_LENGTH 16 + +void idea_set_encrypt_key(uint8_t *key, IDEA_KEY_SCHEDULE *ks); +void idea_set_decrypt_key(IDEA_KEY_SCHEDULE *encrypt_ks, IDEA_KEY_SCHEDULE *decrypt_ks); +void idea_cfb64_encrypt(uint8_t *in, uint8_t *out, long length, des_key_schedule *ks, des_cblock *ivec, int *num, int enc); +void idea_ecb_encrypt(uint8_t *in, uint8_t *out, IDEA_KEY_SCHEDULE *ks); + +#define CAMELLIA_KEY void +#define CAMELLIA_DECRYPT 0 +#define CAMELLIA_ENCRYPT 1 +#define CAMELLIA_BLOCK_SIZE 16 + +int Camellia_set_key(const unsigned char *userKey, const int bits, CAMELLIA_KEY *key); +void Camellia_encrypt(const unsigned char *in, unsigned char *out, const CAMELLIA_KEY *key); +void Camellia_cfb128_encrypt(const unsigned char *in, unsigned char *out, size_t length, const CAMELLIA_KEY *key, unsigned char *ivec, int *num, const int enc); +void Camellia_decrypt(const unsigned char *in, unsigned char *out, const CAMELLIA_KEY *key); + +#define const_DES_cblock void +#define DES_cblock void +#define DES_key_schedule void +#define DES_DECRYPT 0 +#define DES_ENCRYPT 1 + +int DES_set_key(const_DES_cblock *key, DES_key_schedule *schedule); +void DES_ecb3_encrypt(const_DES_cblock *input, DES_cblock *output, DES_key_schedule *ks1,DES_key_schedule *ks2, DES_key_schedule *ks3, int enc); +void DES_ede3_cfb64_encrypt(const unsigned char *in,unsigned char *out, long length,DES_key_schedule *ks1, DES_key_schedule *ks2,DES_key_schedule *ks3, DES_cblock *ivec,int *num,int enc); + +__END_DECLS + +#endif diff --git a/crypto/external/bsd/netpgp/dist/src/libdigest/Makefile b/crypto/external/bsd/netpgp/dist/src/libdigest/Makefile new file mode 100644 index 000000000000..4226113735f4 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libdigest/Makefile @@ -0,0 +1,16 @@ +LIB=netdigest +SRCS= tiger.c digest.c +MKMAN=no +WARNS=4 +CPPFLAGS+=-I${EXTDIST} + +INCS=digest.h tiger.h +INCSDIR=/usr/include/netpgp +EXTDIST=${.CURDIR} + +.include + +.if ${HAVE_GCC} >= 45 +#COPTS.isns_pdu.c+= -fno-strict-aliasing +CPPFLAGS+= -fno-strict-aliasing +.endif diff --git a/crypto/external/bsd/netpgp/dist/src/libdigest/digest.c b/crypto/external/bsd/netpgp/dist/src/libdigest/digest.c new file mode 100644 index 000000000000..8b30da7ebd5b --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libdigest/digest.c @@ -0,0 +1,383 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include + +#ifdef _KERNEL +# include +# include +# include +# include +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include "digest.h" + +static uint8_t prefix_md5[] = { + 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, + 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 +}; + +static uint8_t prefix_sha1[] = { + 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E, 0x03, 0x02, + 0x1A, 0x05, 0x00, 0x04, 0x14 +}; + +static uint8_t prefix_sha256[] = { + 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 +}; + +static uint64_t prefix_tiger[] = { + 0x0123456789ABCDEFLL, + 0xFEDCBA9876543210LL, + 0xF096A5B4C3B2E187LL +}; + +static uint8_t prefix_rmd160[] = { + 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24, + 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14 +}; + +static uint8_t prefix_sha512[] = { + 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40 +}; + +#define V4_SIGNATURE 4 + +/*************************************************************************/ + +void +MD5_Init(MD5_CTX *context) +{ + if (context) { + MD5Init(context); + } +} + +void +MD5_Update(MD5_CTX *context, const unsigned char *data, unsigned int len) +{ + if (context && data) { + MD5Update(context, data, len); + } +} + +void +MD5_Final(unsigned char digest[16], MD5_CTX *context) +{ + if (digest && context) { + MD5Final(digest, context); + } +} + +void +SHA1_Init(SHA1_CTX *context) +{ + if (context) { + SHA1Init(context); + } +} + +void +SHA1_Update(SHA1_CTX *context, const unsigned char *data, unsigned int len) +{ + if (context && data) { + SHA1Update(context, data, len); + } +} + +void +SHA1_Final(unsigned char digest[20], SHA1_CTX *context) +{ + if (digest && context) { + SHA1Final(digest, context); + } +} + +void +RMD160_Init(RMD160_CTX *context) +{ + if (context) { + RMD160Init(context); + } +} + +void +RMD160_Update(RMD160_CTX *context, const unsigned char *data, unsigned int len) +{ + if (context && data) { + RMD160Update(context, data, len); + } +} + +void +RMD160_Final(unsigned char digest[20], RMD160_CTX *context) +{ + if (context && digest) { + RMD160Final(digest, context); + } +} + + +/* algorithm size (raw) */ +int +digest_alg_size(unsigned alg) +{ + switch(alg) { + case MD5_HASH_ALG: + return 16; + case SHA1_HASH_ALG: + return 20; + case RIPEMD_HASH_ALG: + return RMD160_DIGEST_LENGTH; + case SHA256_HASH_ALG: + return 32; + case SHA512_HASH_ALG: + return 64; + case TIGER_HASH_ALG: + case TIGER2_HASH_ALG: + return TIGER_DIGEST_LENGTH; + default: + printf("hash_any: bad algorithm\n"); + return 0; + } +} + +/* initialise the hash structure */ +int +digest_init(digest_t *hash, const uint32_t hashalg) +{ + if (hash == NULL) { + return 0; + } + switch(hash->alg = hashalg) { + case MD5_HASH_ALG: + MD5Init(&hash->u.md5ctx); + hash->size = 16; + hash->prefix = prefix_md5; + hash->len = sizeof(prefix_md5); + hash->ctx = &hash->u.md5ctx; + return 1; + case SHA1_HASH_ALG: + SHA1Init(&hash->u.sha1ctx); + hash->size = 20; + hash->prefix = prefix_sha1; + hash->len = sizeof(prefix_sha1); + hash->ctx = &hash->u.sha1ctx; + return 1; + case RIPEMD_HASH_ALG: + RMD160Init(&hash->u.rmd160ctx); + hash->size = 20; + hash->prefix = prefix_rmd160; + hash->len = sizeof(prefix_rmd160); + hash->ctx = &hash->u.rmd160ctx; + return 1; + case SHA256_HASH_ALG: + SHA256_Init(&hash->u.sha256ctx); + hash->size = 32; + hash->prefix = prefix_sha256; + hash->len = sizeof(prefix_sha256); + hash->ctx = &hash->u.sha256ctx; + return 1; + case SHA512_HASH_ALG: + SHA512_Init(&hash->u.sha512ctx); + hash->size = 64; + hash->prefix = prefix_sha512; + hash->len = sizeof(prefix_sha512); + hash->ctx = &hash->u.sha512ctx; + return 1; + case TIGER_HASH_ALG: + TIGER_Init(&hash->u.tigerctx); + hash->size = TIGER_DIGEST_LENGTH; + hash->prefix = prefix_tiger; + hash->len = sizeof(prefix_tiger); + hash->ctx = &hash->u.tigerctx; + return 1; + case TIGER2_HASH_ALG: + TIGER2_Init(&hash->u.tigerctx); + hash->size = TIGER_DIGEST_LENGTH; + hash->prefix = prefix_tiger; + hash->len = sizeof(prefix_tiger); + hash->ctx = &hash->u.tigerctx; + return 1; + default: + printf("hash_any: bad algorithm\n"); + return 0; + } +} + +typedef struct rec_t { + const char *s; + const unsigned alg; +} rec_t; + +static rec_t hashalgs[] = { + { "md5", MD5_HASH_ALG }, + { "sha1", SHA1_HASH_ALG }, + { "ripemd", RIPEMD_HASH_ALG }, + { "sha256", SHA256_HASH_ALG }, + { "sha512", SHA512_HASH_ALG }, + { "tiger", TIGER_HASH_ALG }, + { "tiger2", TIGER2_HASH_ALG }, + { NULL, 0 } +}; + +/* initialise by string alg name */ +unsigned +digest_get_alg(const char *hashalg) +{ + rec_t *r; + + for (r = hashalgs ; hashalg && r->s ; r++) { + if (strcasecmp(r->s, hashalg) == 0) { + return r->alg; + } + } + return 0; +} + +int +digest_update(digest_t *hash, const uint8_t *data, size_t length) +{ + if (hash == NULL || data == NULL) { + return 0; + } + switch(hash->alg) { + case MD5_HASH_ALG: + MD5Update(hash->ctx, data, (unsigned)length); + return 1; + case SHA1_HASH_ALG: + SHA1Update(hash->ctx, data, (unsigned)length); + return 1; + case RIPEMD_HASH_ALG: + RMD160Update(hash->ctx, data, (unsigned)length); + return 1; + case SHA256_HASH_ALG: + SHA256_Update(hash->ctx, data, length); + return 1; + case SHA512_HASH_ALG: + SHA512_Update(hash->ctx, data, length); + return 1; + case TIGER_HASH_ALG: + case TIGER2_HASH_ALG: + TIGER_Update(hash->ctx, data, length); + return 1; + default: + printf("hash_any: bad algorithm\n"); + return 0; + } +} + +unsigned +digest_final(uint8_t *out, digest_t *hash) +{ + if (hash == NULL || out == NULL) { + return 0; + } + switch(hash->alg) { + case MD5_HASH_ALG: + MD5Final(out, hash->ctx); + break; + case SHA1_HASH_ALG: + SHA1Final(out, hash->ctx); + break; + case RIPEMD_HASH_ALG: + RMD160Final(out, hash->ctx); + break; + case SHA256_HASH_ALG: + SHA256_Final(out, hash->ctx); + break; + case SHA512_HASH_ALG: + SHA512_Final(out, hash->ctx); + break; + case TIGER_HASH_ALG: + TIGER_Final(out, hash->ctx); + break; + default: + printf("hash_any: bad algorithm\n"); + return 0; + } + (void) memset(hash->ctx, 0x0, hash->size); + return (unsigned)hash->size; +} + +int +digest_length(digest_t *hash, unsigned hashedlen) +{ + uint8_t trailer[6]; + + if (hash == NULL) { + return 0; + } + trailer[0] = V4_SIGNATURE; + trailer[1] = 0xFF; + trailer[2] = (uint8_t)((hashedlen >> 24) & 0xff); + trailer[3] = (uint8_t)((hashedlen >> 16) & 0xff); + trailer[4] = (uint8_t)((hashedlen >> 8) & 0xff); + trailer[5] = (uint8_t)(hashedlen & 0xff); + digest_update(hash, trailer, sizeof(trailer)); + return 1; +} + +unsigned +digest_get_prefix(unsigned hashalg, uint8_t *prefix, size_t size) +{ + if (prefix == NULL) { + return 0; + } + switch (hashalg) { + case MD5_HASH_ALG: + memcpy(prefix, prefix_md5, sizeof(prefix_md5)); + return sizeof(prefix_md5); + case SHA1_HASH_ALG: + memcpy(prefix, prefix_sha1, sizeof(prefix_sha1)); + return sizeof(prefix_sha1); + case SHA256_HASH_ALG: + memcpy(prefix, prefix_sha256, sizeof(prefix_sha256)); + return sizeof(prefix_sha256); + default: + printf("digest_get_prefix: unknown hash algorithm: %d\n", hashalg); + return 0; + } +} + diff --git a/crypto/external/bsd/netpgp/dist/src/libdigest/digest.h b/crypto/external/bsd/netpgp/dist/src/libdigest/digest.h new file mode 100644 index 000000000000..28d1ebd08bec --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libdigest/digest.h @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef DIGEST_H_ +#define DIGEST_H_ 20100108 + +#include + +#ifdef _KERNEL +# include +# include +# include +# include +#else +# include +# include +# include +# include +# include +#endif + +#include "tiger.h" + +#ifndef __BEGIN_DECLS +# if defined(__cplusplus) +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +# else +# define __BEGIN_DECLS +# define __END_DECLS +# endif +#endif + +__BEGIN_DECLS + +#define MD5_HASH_ALG 1 +#define SHA1_HASH_ALG 2 +#define RIPEMD_HASH_ALG 3 +#define TIGER_HASH_ALG 6 /* from rfc2440 */ +#define SHA256_HASH_ALG 8 +#define SHA384_HASH_ALG 9 +#define SHA512_HASH_ALG 10 +#define SHA224_HASH_ALG 11 +#define TIGER2_HASH_ALG 100 /* private/experimental from rfc4880 */ + +/* structure to describe digest methods */ +typedef struct digest_t { + uint32_t alg; /* algorithm */ + size_t size; /* size */ + union { + MD5_CTX md5ctx; /* MD5 */ + SHA1_CTX sha1ctx; /* SHA1 */ + RMD160_CTX rmd160ctx; /* RIPEMD */ + SHA256_CTX sha256ctx; /* SHA256 */ + SHA512_CTX sha512ctx; /* SHA512 */ + TIGER_CTX tigerctx; /* TIGER/TIGER2 */ + } u; + void *prefix; /* points to specific prefix */ + uint32_t len; /* prefix length */ + void *ctx; /* pointer to context array */ +} digest_t; + +unsigned digest_get_alg(const char */*hashalg*/); + +int digest_init(digest_t */*digest*/, const uint32_t /*hashalg*/); + +int digest_update(digest_t */*digest*/, const uint8_t */*data*/, size_t /*size*/); +unsigned digest_final(uint8_t */*out*/, digest_t */*digest*/); +int digest_alg_size(unsigned /*alg*/); +int digest_length(digest_t */*hash*/, unsigned /*hashedlen*/); + +void MD5_Init(MD5_CTX */*context*/); +void MD5_Update(MD5_CTX */*context*/, const unsigned char */*data*/, unsigned int /*len*/); +void MD5_Final(unsigned char /*digest*/[16], MD5_CTX */*context*/); + +void SHA1_Init(SHA1_CTX */*context*/); +void SHA1_Update(SHA1_CTX */*context*/, const unsigned char */*data*/, unsigned int /*len*/); +void SHA1_Final(unsigned char /*digest*/[20], SHA1_CTX */*context*/); + +void RMD160_Init(RMD160_CTX */*ctx*/); +void RMD160_Update(RMD160_CTX */*ctx*/, const unsigned char */*data*/, uint32_t /*len*/); +void RMD160_Final(unsigned char /*digest*/[RMD160_DIGEST_LENGTH], RMD160_CTX */*ctx*/); + +unsigned digest_get_prefix(unsigned /*hashalg*/, uint8_t */*prefix*/, size_t /*size*/); + +__END_DECLS + +#endif diff --git a/crypto/external/bsd/netpgp/dist/src/libdigest/tiger.3 b/crypto/external/bsd/netpgp/dist/src/libdigest/tiger.3 new file mode 100644 index 000000000000..34730340b7bb --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libdigest/tiger.3 @@ -0,0 +1,219 @@ +.\" $NetBSD: tiger.3,v 1.2 2012/11/20 05:26:25 agc Exp $ +.\" +.\" Copyright (c) 2011 Alistair Crooks +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd May 30, 2011 +.Dt TIGER 3 +.Os +.Sh NAME +.Nm TIGER_Init , +.Nm TIGER_Update , +.Nm TIGER_Final , +.Nm TIGER_End , +.Nm TIGER_File , +.Nm TIGER_Data +.Nd calculate TIGER message digests +.Sh SYNOPSIS +.In tiger.h +.Ft void +.Fo TIGER_Init +.Fa "TIGER_CTX *context" +.Fc +.Ft void +.Fo TIGER_Update +.Fa "TIGER_CTX *context" "const uint8_t *data" "u_int len" +.Fc +.Ft void +.Fo TIGER_Final +.Fa "uint8_t digest[20]" "TIGER_CTX *context" +.Fc +.Ft "char *" +.Fo TIGER_End +.Fa "TIGER_CTX *context" "char *buf" +.Fc +.Ft "char *" +.Fo TIGER_File +.Fa "char *filename" "char *buf" +.Fc +.Ft "char *" +.Fo TIGER_Data +.Fa "uint8_t *data" "size_t len" "char *buf" +.Fc +.Sh DESCRIPTION +The TIGER functions calculate TIGER message digest functions, +as defined by Ross Anderson and Eli Biham. +The algorithm takes a +message less than 2^64 bits as input and produces a 192-bit digest +suitable for use as a digital signature. +.Pp +At the time of writing, +May 2011, +no attacks or pre-imaging have been discovered against the +.Nm +message digests, whilst the same cannot be said of +.Xr md5 3 +or +.Xr sha1 3 . +.Pp +The +.Fn TIGER_Init +function initializes a TIGER_CTX +.Ar context +for use with +.Fn TIGER_Update , +and +.Fn TIGER_Final . +The +.Fn TIGER_Update +function adds +.Ar data +of length +.Ar len +to the TIGER_CTX specified by +.Ar context . +.Fn TIGER_Final +is called when all data has been added via +.Fn TIGER_Update +and stores a message digest in the +.Ar digest +parameter. +When a +.Dv NULL +pointer is passed to +.Fn TIGER_Final +as first argument only the final padding will be applied and the +current context can still be used with +.Fn TIGER_Update . +.Pp +The core of the TIGER message digest is performed by +.Fn TIGER_Update . +Most programs should use the interface provided by +.Fn TIGER_Init , +.Fn TIGER_Update , +and +.Fn TIGER_Final . +.Pp +The +.Fn TIGER_End +function is a front end for +.Fn TIGER_Final +which converts the digest into an +.Tn ASCII +representation of the 160 bit digest in hexadecimal. +.Pp +The +.Fn TIGER_File +function calculates the digest for a file and returns the result via +.Fn TIGER_End . +If +.Fn TIGER_File +is unable to open the file a +.Dv NULL +pointer is returned. +.Pp +The +.Fn TIGER_Data +function +calculates the digest of an arbitrary string and returns the result via +.Fn TIGER_End . +.Pp +For each of the +.Fn TIGER_End , +.Fn TIGER_File , +and +.Fn TIGER_Data +functions the +.Ar buf +parameter should either be a string of at least 41 characters in +size or a +.Dv NULL +pointer. +In the latter case, space will be dynamically allocated via +.Xr malloc 3 +and should be freed using +.Xr free 3 +when it is no longer needed. +.Sh EXAMPLES +The follow code fragment will calculate the digest for the string +"The quick brown fox jumps over the lazy dog" +which is +.Dq 6d12a41e72e644f017b6f0e2f7b44c6285f06dd5d2c5b075 . +.Bd -literal -offset indent +TIGER_CTX tiger; +uint8_t results[24]; +char *buf; +int n; + +buf = "The quick brown fox jumps over the lazy dog"; +n = strlen(buf); +TIGER_Init(\*[Am]tiger); +TIGER_Update(\*[Am]tiger, (uint8_t *)buf, n); +TIGER_Final(results, \*[Am]tiger); + +/* Print the digest as one long hex value */ +printf("0x"); +for (n = 0; n \*[Lt] 24; n++) + printf("%02x", results[n]); +putchar('\en'); +.Ed +.Pp +Alternately, the helper functions could be used in the following way: +.Bd -literal -offset indent +TIGER_CTX tiger; +uint8_t output[49]; +char *buf = "The quick brown fox jumps over the lazy dog"; + +printf("0x%s", TIGER_Data(buf, strlen(buf), output)); +.Ed +.Sh SEE ALSO +.Xr md5 3 , +.Xr sha1 3 +.Pp +.Rs +.%A Ross Anderson +.%A Eli Biham +.%T "Tiger - A Fast New Hash Function" +.%B Proceedings of Fast Software Encryption 3, Cambridge +.%D 1996 +.Re +.Sh HISTORY +The TIGER functions appeared in +.Nx 6.0 . +.Sh AUTHORS +.An -nosplit +This implementation of TIGER was adapted by +.An Alistair Crooks Aq agc@NetBSD.org +from the original reference code. +.Pp +The +.Fn TIGER_End , +.Fn TIGER_File , +and +.Fn TIGER_Data +helper functions are derived from code written by Poul-Henning Kamp. +.Sh BUGS +All attempts have bene made to optimise for the underlying hardware, +as well as to format the digest properly in an endian-neutral manner. +The author has no VAX hardware on which to test, and so it is not known +whether that platform is supported. diff --git a/crypto/external/bsd/netpgp/dist/src/libdigest/tiger.c b/crypto/external/bsd/netpgp/dist/src/libdigest/tiger.c new file mode 100644 index 000000000000..e0b44d912e77 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libdigest/tiger.c @@ -0,0 +1,906 @@ +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "tiger.h" + +#ifndef IS_LITTLE_ENDIAN +#define IS_LITTLE_ENDIAN(x) (*(char *)(void *)&x) +#define IS_BIG_ENDIAN(x) !(*(char *)(void *)&x) +#endif + +#define BSWAP64(x) ((((x) & 0xffULL) << 56) | \ + (((x) & 0xff00ULL) << 40) | \ + (((x) & 0xff0000ULL) << 24) | \ + (((x) & 0xff000000ULL) << 8) | \ + (((x) & 0xff00000000ULL) >> 8) | \ + (((x) & 0xff0000000000ULL) >> 24) | \ + (((x) & 0xff000000000000ULL) >> 40) | \ + (((x) & 0xff00000000000000ULL) >> 56)) + +/* sboxes.c: Tiger S boxes */ +static uint64_t table[4*256] = { + 0x02AAB17CF7E90C5ELL /* 0 */, 0xAC424B03E243A8ECLL /* 1 */, + 0x72CD5BE30DD5FCD3LL /* 2 */, 0x6D019B93F6F97F3ALL /* 3 */, + 0xCD9978FFD21F9193LL /* 4 */, 0x7573A1C9708029E2LL /* 5 */, + 0xB164326B922A83C3LL /* 6 */, 0x46883EEE04915870LL /* 7 */, + 0xEAACE3057103ECE6LL /* 8 */, 0xC54169B808A3535CLL /* 9 */, + 0x4CE754918DDEC47CLL /* 10 */, 0x0AA2F4DFDC0DF40CLL /* 11 */, + 0x10B76F18A74DBEFALL /* 12 */, 0xC6CCB6235AD1AB6ALL /* 13 */, + 0x13726121572FE2FFLL /* 14 */, 0x1A488C6F199D921ELL /* 15 */, + 0x4BC9F9F4DA0007CALL /* 16 */, 0x26F5E6F6E85241C7LL /* 17 */, + 0x859079DBEA5947B6LL /* 18 */, 0x4F1885C5C99E8C92LL /* 19 */, + 0xD78E761EA96F864BLL /* 20 */, 0x8E36428C52B5C17DLL /* 21 */, + 0x69CF6827373063C1LL /* 22 */, 0xB607C93D9BB4C56ELL /* 23 */, + 0x7D820E760E76B5EALL /* 24 */, 0x645C9CC6F07FDC42LL /* 25 */, + 0xBF38A078243342E0LL /* 26 */, 0x5F6B343C9D2E7D04LL /* 27 */, + 0xF2C28AEB600B0EC6LL /* 28 */, 0x6C0ED85F7254BCACLL /* 29 */, + 0x71592281A4DB4FE5LL /* 30 */, 0x1967FA69CE0FED9FLL /* 31 */, + 0xFD5293F8B96545DBLL /* 32 */, 0xC879E9D7F2A7600BLL /* 33 */, + 0x860248920193194ELL /* 34 */, 0xA4F9533B2D9CC0B3LL /* 35 */, + 0x9053836C15957613LL /* 36 */, 0xDB6DCF8AFC357BF1LL /* 37 */, + 0x18BEEA7A7A370F57LL /* 38 */, 0x037117CA50B99066LL /* 39 */, + 0x6AB30A9774424A35LL /* 40 */, 0xF4E92F02E325249BLL /* 41 */, + 0x7739DB07061CCAE1LL /* 42 */, 0xD8F3B49CECA42A05LL /* 43 */, + 0xBD56BE3F51382F73LL /* 44 */, 0x45FAED5843B0BB28LL /* 45 */, + 0x1C813D5C11BF1F83LL /* 46 */, 0x8AF0E4B6D75FA169LL /* 47 */, + 0x33EE18A487AD9999LL /* 48 */, 0x3C26E8EAB1C94410LL /* 49 */, + 0xB510102BC0A822F9LL /* 50 */, 0x141EEF310CE6123BLL /* 51 */, + 0xFC65B90059DDB154LL /* 52 */, 0xE0158640C5E0E607LL /* 53 */, + 0x884E079826C3A3CFLL /* 54 */, 0x930D0D9523C535FDLL /* 55 */, + 0x35638D754E9A2B00LL /* 56 */, 0x4085FCCF40469DD5LL /* 57 */, + 0xC4B17AD28BE23A4CLL /* 58 */, 0xCAB2F0FC6A3E6A2ELL /* 59 */, + 0x2860971A6B943FCDLL /* 60 */, 0x3DDE6EE212E30446LL /* 61 */, + 0x6222F32AE01765AELL /* 62 */, 0x5D550BB5478308FELL /* 63 */, + 0xA9EFA98DA0EDA22ALL /* 64 */, 0xC351A71686C40DA7LL /* 65 */, + 0x1105586D9C867C84LL /* 66 */, 0xDCFFEE85FDA22853LL /* 67 */, + 0xCCFBD0262C5EEF76LL /* 68 */, 0xBAF294CB8990D201LL /* 69 */, + 0xE69464F52AFAD975LL /* 70 */, 0x94B013AFDF133E14LL /* 71 */, + 0x06A7D1A32823C958LL /* 72 */, 0x6F95FE5130F61119LL /* 73 */, + 0xD92AB34E462C06C0LL /* 74 */, 0xED7BDE33887C71D2LL /* 75 */, + 0x79746D6E6518393ELL /* 76 */, 0x5BA419385D713329LL /* 77 */, + 0x7C1BA6B948A97564LL /* 78 */, 0x31987C197BFDAC67LL /* 79 */, + 0xDE6C23C44B053D02LL /* 80 */, 0x581C49FED002D64DLL /* 81 */, + 0xDD474D6338261571LL /* 82 */, 0xAA4546C3E473D062LL /* 83 */, + 0x928FCE349455F860LL /* 84 */, 0x48161BBACAAB94D9LL /* 85 */, + 0x63912430770E6F68LL /* 86 */, 0x6EC8A5E602C6641CLL /* 87 */, + 0x87282515337DDD2BLL /* 88 */, 0x2CDA6B42034B701BLL /* 89 */, + 0xB03D37C181CB096DLL /* 90 */, 0xE108438266C71C6FLL /* 91 */, + 0x2B3180C7EB51B255LL /* 92 */, 0xDF92B82F96C08BBCLL /* 93 */, + 0x5C68C8C0A632F3BALL /* 94 */, 0x5504CC861C3D0556LL /* 95 */, + 0xABBFA4E55FB26B8FLL /* 96 */, 0x41848B0AB3BACEB4LL /* 97 */, + 0xB334A273AA445D32LL /* 98 */, 0xBCA696F0A85AD881LL /* 99 */, + 0x24F6EC65B528D56CLL /* 100 */, 0x0CE1512E90F4524ALL /* 101 */, + 0x4E9DD79D5506D35ALL /* 102 */, 0x258905FAC6CE9779LL /* 103 */, + 0x2019295B3E109B33LL /* 104 */, 0xF8A9478B73A054CCLL /* 105 */, + 0x2924F2F934417EB0LL /* 106 */, 0x3993357D536D1BC4LL /* 107 */, + 0x38A81AC21DB6FF8BLL /* 108 */, 0x47C4FBF17D6016BFLL /* 109 */, + 0x1E0FAADD7667E3F5LL /* 110 */, 0x7ABCFF62938BEB96LL /* 111 */, + 0xA78DAD948FC179C9LL /* 112 */, 0x8F1F98B72911E50DLL /* 113 */, + 0x61E48EAE27121A91LL /* 114 */, 0x4D62F7AD31859808LL /* 115 */, + 0xECEBA345EF5CEAEBLL /* 116 */, 0xF5CEB25EBC9684CELL /* 117 */, + 0xF633E20CB7F76221LL /* 118 */, 0xA32CDF06AB8293E4LL /* 119 */, + 0x985A202CA5EE2CA4LL /* 120 */, 0xCF0B8447CC8A8FB1LL /* 121 */, + 0x9F765244979859A3LL /* 122 */, 0xA8D516B1A1240017LL /* 123 */, + 0x0BD7BA3EBB5DC726LL /* 124 */, 0xE54BCA55B86ADB39LL /* 125 */, + 0x1D7A3AFD6C478063LL /* 126 */, 0x519EC608E7669EDDLL /* 127 */, + 0x0E5715A2D149AA23LL /* 128 */, 0x177D4571848FF194LL /* 129 */, + 0xEEB55F3241014C22LL /* 130 */, 0x0F5E5CA13A6E2EC2LL /* 131 */, + 0x8029927B75F5C361LL /* 132 */, 0xAD139FABC3D6E436LL /* 133 */, + 0x0D5DF1A94CCF402FLL /* 134 */, 0x3E8BD948BEA5DFC8LL /* 135 */, + 0xA5A0D357BD3FF77ELL /* 136 */, 0xA2D12E251F74F645LL /* 137 */, + 0x66FD9E525E81A082LL /* 138 */, 0x2E0C90CE7F687A49LL /* 139 */, + 0xC2E8BCBEBA973BC5LL /* 140 */, 0x000001BCE509745FLL /* 141 */, + 0x423777BBE6DAB3D6LL /* 142 */, 0xD1661C7EAEF06EB5LL /* 143 */, + 0xA1781F354DAACFD8LL /* 144 */, 0x2D11284A2B16AFFCLL /* 145 */, + 0xF1FC4F67FA891D1FLL /* 146 */, 0x73ECC25DCB920ADALL /* 147 */, + 0xAE610C22C2A12651LL /* 148 */, 0x96E0A810D356B78ALL /* 149 */, + 0x5A9A381F2FE7870FLL /* 150 */, 0xD5AD62EDE94E5530LL /* 151 */, + 0xD225E5E8368D1427LL /* 152 */, 0x65977B70C7AF4631LL /* 153 */, + 0x99F889B2DE39D74FLL /* 154 */, 0x233F30BF54E1D143LL /* 155 */, + 0x9A9675D3D9A63C97LL /* 156 */, 0x5470554FF334F9A8LL /* 157 */, + 0x166ACB744A4F5688LL /* 158 */, 0x70C74CAAB2E4AEADLL /* 159 */, + 0xF0D091646F294D12LL /* 160 */, 0x57B82A89684031D1LL /* 161 */, + 0xEFD95A5A61BE0B6BLL /* 162 */, 0x2FBD12E969F2F29ALL /* 163 */, + 0x9BD37013FEFF9FE8LL /* 164 */, 0x3F9B0404D6085A06LL /* 165 */, + 0x4940C1F3166CFE15LL /* 166 */, 0x09542C4DCDF3DEFBLL /* 167 */, + 0xB4C5218385CD5CE3LL /* 168 */, 0xC935B7DC4462A641LL /* 169 */, + 0x3417F8A68ED3B63FLL /* 170 */, 0xB80959295B215B40LL /* 171 */, + 0xF99CDAEF3B8C8572LL /* 172 */, 0x018C0614F8FCB95DLL /* 173 */, + 0x1B14ACCD1A3ACDF3LL /* 174 */, 0x84D471F200BB732DLL /* 175 */, + 0xC1A3110E95E8DA16LL /* 176 */, 0x430A7220BF1A82B8LL /* 177 */, + 0xB77E090D39DF210ELL /* 178 */, 0x5EF4BD9F3CD05E9DLL /* 179 */, + 0x9D4FF6DA7E57A444LL /* 180 */, 0xDA1D60E183D4A5F8LL /* 181 */, + 0xB287C38417998E47LL /* 182 */, 0xFE3EDC121BB31886LL /* 183 */, + 0xC7FE3CCC980CCBEFLL /* 184 */, 0xE46FB590189BFD03LL /* 185 */, + 0x3732FD469A4C57DCLL /* 186 */, 0x7EF700A07CF1AD65LL /* 187 */, + 0x59C64468A31D8859LL /* 188 */, 0x762FB0B4D45B61F6LL /* 189 */, + 0x155BAED099047718LL /* 190 */, 0x68755E4C3D50BAA6LL /* 191 */, + 0xE9214E7F22D8B4DFLL /* 192 */, 0x2ADDBF532EAC95F4LL /* 193 */, + 0x32AE3909B4BD0109LL /* 194 */, 0x834DF537B08E3450LL /* 195 */, + 0xFA209DA84220728DLL /* 196 */, 0x9E691D9B9EFE23F7LL /* 197 */, + 0x0446D288C4AE8D7FLL /* 198 */, 0x7B4CC524E169785BLL /* 199 */, + 0x21D87F0135CA1385LL /* 200 */, 0xCEBB400F137B8AA5LL /* 201 */, + 0x272E2B66580796BELL /* 202 */, 0x3612264125C2B0DELL /* 203 */, + 0x057702BDAD1EFBB2LL /* 204 */, 0xD4BABB8EACF84BE9LL /* 205 */, + 0x91583139641BC67BLL /* 206 */, 0x8BDC2DE08036E024LL /* 207 */, + 0x603C8156F49F68EDLL /* 208 */, 0xF7D236F7DBEF5111LL /* 209 */, + 0x9727C4598AD21E80LL /* 210 */, 0xA08A0896670A5FD7LL /* 211 */, + 0xCB4A8F4309EBA9CBLL /* 212 */, 0x81AF564B0F7036A1LL /* 213 */, + 0xC0B99AA778199ABDLL /* 214 */, 0x959F1EC83FC8E952LL /* 215 */, + 0x8C505077794A81B9LL /* 216 */, 0x3ACAAF8F056338F0LL /* 217 */, + 0x07B43F50627A6778LL /* 218 */, 0x4A44AB49F5ECCC77LL /* 219 */, + 0x3BC3D6E4B679EE98LL /* 220 */, 0x9CC0D4D1CF14108CLL /* 221 */, + 0x4406C00B206BC8A0LL /* 222 */, 0x82A18854C8D72D89LL /* 223 */, + 0x67E366B35C3C432CLL /* 224 */, 0xB923DD61102B37F2LL /* 225 */, + 0x56AB2779D884271DLL /* 226 */, 0xBE83E1B0FF1525AFLL /* 227 */, + 0xFB7C65D4217E49A9LL /* 228 */, 0x6BDBE0E76D48E7D4LL /* 229 */, + 0x08DF828745D9179ELL /* 230 */, 0x22EA6A9ADD53BD34LL /* 231 */, + 0xE36E141C5622200ALL /* 232 */, 0x7F805D1B8CB750EELL /* 233 */, + 0xAFE5C7A59F58E837LL /* 234 */, 0xE27F996A4FB1C23CLL /* 235 */, + 0xD3867DFB0775F0D0LL /* 236 */, 0xD0E673DE6E88891ALL /* 237 */, + 0x123AEB9EAFB86C25LL /* 238 */, 0x30F1D5D5C145B895LL /* 239 */, + 0xBB434A2DEE7269E7LL /* 240 */, 0x78CB67ECF931FA38LL /* 241 */, + 0xF33B0372323BBF9CLL /* 242 */, 0x52D66336FB279C74LL /* 243 */, + 0x505F33AC0AFB4EAALL /* 244 */, 0xE8A5CD99A2CCE187LL /* 245 */, + 0x534974801E2D30BBLL /* 246 */, 0x8D2D5711D5876D90LL /* 247 */, + 0x1F1A412891BC038ELL /* 248 */, 0xD6E2E71D82E56648LL /* 249 */, + 0x74036C3A497732B7LL /* 250 */, 0x89B67ED96361F5ABLL /* 251 */, + 0xFFED95D8F1EA02A2LL /* 252 */, 0xE72B3BD61464D43DLL /* 253 */, + 0xA6300F170BDC4820LL /* 254 */, 0xEBC18760ED78A77ALL /* 255 */, + 0xE6A6BE5A05A12138LL /* 256 */, 0xB5A122A5B4F87C98LL /* 257 */, + 0x563C6089140B6990LL /* 258 */, 0x4C46CB2E391F5DD5LL /* 259 */, + 0xD932ADDBC9B79434LL /* 260 */, 0x08EA70E42015AFF5LL /* 261 */, + 0xD765A6673E478CF1LL /* 262 */, 0xC4FB757EAB278D99LL /* 263 */, + 0xDF11C6862D6E0692LL /* 264 */, 0xDDEB84F10D7F3B16LL /* 265 */, + 0x6F2EF604A665EA04LL /* 266 */, 0x4A8E0F0FF0E0DFB3LL /* 267 */, + 0xA5EDEEF83DBCBA51LL /* 268 */, 0xFC4F0A2A0EA4371ELL /* 269 */, + 0xE83E1DA85CB38429LL /* 270 */, 0xDC8FF882BA1B1CE2LL /* 271 */, + 0xCD45505E8353E80DLL /* 272 */, 0x18D19A00D4DB0717LL /* 273 */, + 0x34A0CFEDA5F38101LL /* 274 */, 0x0BE77E518887CAF2LL /* 275 */, + 0x1E341438B3C45136LL /* 276 */, 0xE05797F49089CCF9LL /* 277 */, + 0xFFD23F9DF2591D14LL /* 278 */, 0x543DDA228595C5CDLL /* 279 */, + 0x661F81FD99052A33LL /* 280 */, 0x8736E641DB0F7B76LL /* 281 */, + 0x15227725418E5307LL /* 282 */, 0xE25F7F46162EB2FALL /* 283 */, + 0x48A8B2126C13D9FELL /* 284 */, 0xAFDC541792E76EEALL /* 285 */, + 0x03D912BFC6D1898FLL /* 286 */, 0x31B1AAFA1B83F51BLL /* 287 */, + 0xF1AC2796E42AB7D9LL /* 288 */, 0x40A3A7D7FCD2EBACLL /* 289 */, + 0x1056136D0AFBBCC5LL /* 290 */, 0x7889E1DD9A6D0C85LL /* 291 */, + 0xD33525782A7974AALL /* 292 */, 0xA7E25D09078AC09BLL /* 293 */, + 0xBD4138B3EAC6EDD0LL /* 294 */, 0x920ABFBE71EB9E70LL /* 295 */, + 0xA2A5D0F54FC2625CLL /* 296 */, 0xC054E36B0B1290A3LL /* 297 */, + 0xF6DD59FF62FE932BLL /* 298 */, 0x3537354511A8AC7DLL /* 299 */, + 0xCA845E9172FADCD4LL /* 300 */, 0x84F82B60329D20DCLL /* 301 */, + 0x79C62CE1CD672F18LL /* 302 */, 0x8B09A2ADD124642CLL /* 303 */, + 0xD0C1E96A19D9E726LL /* 304 */, 0x5A786A9B4BA9500CLL /* 305 */, + 0x0E020336634C43F3LL /* 306 */, 0xC17B474AEB66D822LL /* 307 */, + 0x6A731AE3EC9BAAC2LL /* 308 */, 0x8226667AE0840258LL /* 309 */, + 0x67D4567691CAECA5LL /* 310 */, 0x1D94155C4875ADB5LL /* 311 */, + 0x6D00FD985B813FDFLL /* 312 */, 0x51286EFCB774CD06LL /* 313 */, + 0x5E8834471FA744AFLL /* 314 */, 0xF72CA0AEE761AE2ELL /* 315 */, + 0xBE40E4CDAEE8E09ALL /* 316 */, 0xE9970BBB5118F665LL /* 317 */, + 0x726E4BEB33DF1964LL /* 318 */, 0x703B000729199762LL /* 319 */, + 0x4631D816F5EF30A7LL /* 320 */, 0xB880B5B51504A6BELL /* 321 */, + 0x641793C37ED84B6CLL /* 322 */, 0x7B21ED77F6E97D96LL /* 323 */, + 0x776306312EF96B73LL /* 324 */, 0xAE528948E86FF3F4LL /* 325 */, + 0x53DBD7F286A3F8F8LL /* 326 */, 0x16CADCE74CFC1063LL /* 327 */, + 0x005C19BDFA52C6DDLL /* 328 */, 0x68868F5D64D46AD3LL /* 329 */, + 0x3A9D512CCF1E186ALL /* 330 */, 0x367E62C2385660AELL /* 331 */, + 0xE359E7EA77DCB1D7LL /* 332 */, 0x526C0773749ABE6ELL /* 333 */, + 0x735AE5F9D09F734BLL /* 334 */, 0x493FC7CC8A558BA8LL /* 335 */, + 0xB0B9C1533041AB45LL /* 336 */, 0x321958BA470A59BDLL /* 337 */, + 0x852DB00B5F46C393LL /* 338 */, 0x91209B2BD336B0E5LL /* 339 */, + 0x6E604F7D659EF19FLL /* 340 */, 0xB99A8AE2782CCB24LL /* 341 */, + 0xCCF52AB6C814C4C7LL /* 342 */, 0x4727D9AFBE11727BLL /* 343 */, + 0x7E950D0C0121B34DLL /* 344 */, 0x756F435670AD471FLL /* 345 */, + 0xF5ADD442615A6849LL /* 346 */, 0x4E87E09980B9957ALL /* 347 */, + 0x2ACFA1DF50AEE355LL /* 348 */, 0xD898263AFD2FD556LL /* 349 */, + 0xC8F4924DD80C8FD6LL /* 350 */, 0xCF99CA3D754A173ALL /* 351 */, + 0xFE477BACAF91BF3CLL /* 352 */, 0xED5371F6D690C12DLL /* 353 */, + 0x831A5C285E687094LL /* 354 */, 0xC5D3C90A3708A0A4LL /* 355 */, + 0x0F7F903717D06580LL /* 356 */, 0x19F9BB13B8FDF27FLL /* 357 */, + 0xB1BD6F1B4D502843LL /* 358 */, 0x1C761BA38FFF4012LL /* 359 */, + 0x0D1530C4E2E21F3BLL /* 360 */, 0x8943CE69A7372C8ALL /* 361 */, + 0xE5184E11FEB5CE66LL /* 362 */, 0x618BDB80BD736621LL /* 363 */, + 0x7D29BAD68B574D0BLL /* 364 */, 0x81BB613E25E6FE5BLL /* 365 */, + 0x071C9C10BC07913FLL /* 366 */, 0xC7BEEB7909AC2D97LL /* 367 */, + 0xC3E58D353BC5D757LL /* 368 */, 0xEB017892F38F61E8LL /* 369 */, + 0xD4EFFB9C9B1CC21ALL /* 370 */, 0x99727D26F494F7ABLL /* 371 */, + 0xA3E063A2956B3E03LL /* 372 */, 0x9D4A8B9A4AA09C30LL /* 373 */, + 0x3F6AB7D500090FB4LL /* 374 */, 0x9CC0F2A057268AC0LL /* 375 */, + 0x3DEE9D2DEDBF42D1LL /* 376 */, 0x330F49C87960A972LL /* 377 */, + 0xC6B2720287421B41LL /* 378 */, 0x0AC59EC07C00369CLL /* 379 */, + 0xEF4EAC49CB353425LL /* 380 */, 0xF450244EEF0129D8LL /* 381 */, + 0x8ACC46E5CAF4DEB6LL /* 382 */, 0x2FFEAB63989263F7LL /* 383 */, + 0x8F7CB9FE5D7A4578LL /* 384 */, 0x5BD8F7644E634635LL /* 385 */, + 0x427A7315BF2DC900LL /* 386 */, 0x17D0C4AA2125261CLL /* 387 */, + 0x3992486C93518E50LL /* 388 */, 0xB4CBFEE0A2D7D4C3LL /* 389 */, + 0x7C75D6202C5DDD8DLL /* 390 */, 0xDBC295D8E35B6C61LL /* 391 */, + 0x60B369D302032B19LL /* 392 */, 0xCE42685FDCE44132LL /* 393 */, + 0x06F3DDB9DDF65610LL /* 394 */, 0x8EA4D21DB5E148F0LL /* 395 */, + 0x20B0FCE62FCD496FLL /* 396 */, 0x2C1B912358B0EE31LL /* 397 */, + 0xB28317B818F5A308LL /* 398 */, 0xA89C1E189CA6D2CFLL /* 399 */, + 0x0C6B18576AAADBC8LL /* 400 */, 0xB65DEAA91299FAE3LL /* 401 */, + 0xFB2B794B7F1027E7LL /* 402 */, 0x04E4317F443B5BEBLL /* 403 */, + 0x4B852D325939D0A6LL /* 404 */, 0xD5AE6BEEFB207FFCLL /* 405 */, + 0x309682B281C7D374LL /* 406 */, 0xBAE309A194C3B475LL /* 407 */, + 0x8CC3F97B13B49F05LL /* 408 */, 0x98A9422FF8293967LL /* 409 */, + 0x244B16B01076FF7CLL /* 410 */, 0xF8BF571C663D67EELL /* 411 */, + 0x1F0D6758EEE30DA1LL /* 412 */, 0xC9B611D97ADEB9B7LL /* 413 */, + 0xB7AFD5887B6C57A2LL /* 414 */, 0x6290AE846B984FE1LL /* 415 */, + 0x94DF4CDEACC1A5FDLL /* 416 */, 0x058A5BD1C5483AFFLL /* 417 */, + 0x63166CC142BA3C37LL /* 418 */, 0x8DB8526EB2F76F40LL /* 419 */, + 0xE10880036F0D6D4ELL /* 420 */, 0x9E0523C9971D311DLL /* 421 */, + 0x45EC2824CC7CD691LL /* 422 */, 0x575B8359E62382C9LL /* 423 */, + 0xFA9E400DC4889995LL /* 424 */, 0xD1823ECB45721568LL /* 425 */, + 0xDAFD983B8206082FLL /* 426 */, 0xAA7D29082386A8CBLL /* 427 */, + 0x269FCD4403B87588LL /* 428 */, 0x1B91F5F728BDD1E0LL /* 429 */, + 0xE4669F39040201F6LL /* 430 */, 0x7A1D7C218CF04ADELL /* 431 */, + 0x65623C29D79CE5CELL /* 432 */, 0x2368449096C00BB1LL /* 433 */, + 0xAB9BF1879DA503BALL /* 434 */, 0xBC23ECB1A458058ELL /* 435 */, + 0x9A58DF01BB401ECCLL /* 436 */, 0xA070E868A85F143DLL /* 437 */, + 0x4FF188307DF2239ELL /* 438 */, 0x14D565B41A641183LL /* 439 */, + 0xEE13337452701602LL /* 440 */, 0x950E3DCF3F285E09LL /* 441 */, + 0x59930254B9C80953LL /* 442 */, 0x3BF299408930DA6DLL /* 443 */, + 0xA955943F53691387LL /* 444 */, 0xA15EDECAA9CB8784LL /* 445 */, + 0x29142127352BE9A0LL /* 446 */, 0x76F0371FFF4E7AFBLL /* 447 */, + 0x0239F450274F2228LL /* 448 */, 0xBB073AF01D5E868BLL /* 449 */, + 0xBFC80571C10E96C1LL /* 450 */, 0xD267088568222E23LL /* 451 */, + 0x9671A3D48E80B5B0LL /* 452 */, 0x55B5D38AE193BB81LL /* 453 */, + 0x693AE2D0A18B04B8LL /* 454 */, 0x5C48B4ECADD5335FLL /* 455 */, + 0xFD743B194916A1CALL /* 456 */, 0x2577018134BE98C4LL /* 457 */, + 0xE77987E83C54A4ADLL /* 458 */, 0x28E11014DA33E1B9LL /* 459 */, + 0x270CC59E226AA213LL /* 460 */, 0x71495F756D1A5F60LL /* 461 */, + 0x9BE853FB60AFEF77LL /* 462 */, 0xADC786A7F7443DBFLL /* 463 */, + 0x0904456173B29A82LL /* 464 */, 0x58BC7A66C232BD5ELL /* 465 */, + 0xF306558C673AC8B2LL /* 466 */, 0x41F639C6B6C9772ALL /* 467 */, + 0x216DEFE99FDA35DALL /* 468 */, 0x11640CC71C7BE615LL /* 469 */, + 0x93C43694565C5527LL /* 470 */, 0xEA038E6246777839LL /* 471 */, + 0xF9ABF3CE5A3E2469LL /* 472 */, 0x741E768D0FD312D2LL /* 473 */, + 0x0144B883CED652C6LL /* 474 */, 0xC20B5A5BA33F8552LL /* 475 */, + 0x1AE69633C3435A9DLL /* 476 */, 0x97A28CA4088CFDECLL /* 477 */, + 0x8824A43C1E96F420LL /* 478 */, 0x37612FA66EEEA746LL /* 479 */, + 0x6B4CB165F9CF0E5ALL /* 480 */, 0x43AA1C06A0ABFB4ALL /* 481 */, + 0x7F4DC26FF162796BLL /* 482 */, 0x6CBACC8E54ED9B0FLL /* 483 */, + 0xA6B7FFEFD2BB253ELL /* 484 */, 0x2E25BC95B0A29D4FLL /* 485 */, + 0x86D6A58BDEF1388CLL /* 486 */, 0xDED74AC576B6F054LL /* 487 */, + 0x8030BDBC2B45805DLL /* 488 */, 0x3C81AF70E94D9289LL /* 489 */, + 0x3EFF6DDA9E3100DBLL /* 490 */, 0xB38DC39FDFCC8847LL /* 491 */, + 0x123885528D17B87ELL /* 492 */, 0xF2DA0ED240B1B642LL /* 493 */, + 0x44CEFADCD54BF9A9LL /* 494 */, 0x1312200E433C7EE6LL /* 495 */, + 0x9FFCC84F3A78C748LL /* 496 */, 0xF0CD1F72248576BBLL /* 497 */, + 0xEC6974053638CFE4LL /* 498 */, 0x2BA7B67C0CEC4E4CLL /* 499 */, + 0xAC2F4DF3E5CE32EDLL /* 500 */, 0xCB33D14326EA4C11LL /* 501 */, + 0xA4E9044CC77E58BCLL /* 502 */, 0x5F513293D934FCEFLL /* 503 */, + 0x5DC9645506E55444LL /* 504 */, 0x50DE418F317DE40ALL /* 505 */, + 0x388CB31A69DDE259LL /* 506 */, 0x2DB4A83455820A86LL /* 507 */, + 0x9010A91E84711AE9LL /* 508 */, 0x4DF7F0B7B1498371LL /* 509 */, + 0xD62A2EABC0977179LL /* 510 */, 0x22FAC097AA8D5C0ELL /* 511 */, + 0xF49FCC2FF1DAF39BLL /* 512 */, 0x487FD5C66FF29281LL /* 513 */, + 0xE8A30667FCDCA83FLL /* 514 */, 0x2C9B4BE3D2FCCE63LL /* 515 */, + 0xDA3FF74B93FBBBC2LL /* 516 */, 0x2FA165D2FE70BA66LL /* 517 */, + 0xA103E279970E93D4LL /* 518 */, 0xBECDEC77B0E45E71LL /* 519 */, + 0xCFB41E723985E497LL /* 520 */, 0xB70AAA025EF75017LL /* 521 */, + 0xD42309F03840B8E0LL /* 522 */, 0x8EFC1AD035898579LL /* 523 */, + 0x96C6920BE2B2ABC5LL /* 524 */, 0x66AF4163375A9172LL /* 525 */, + 0x2174ABDCCA7127FBLL /* 526 */, 0xB33CCEA64A72FF41LL /* 527 */, + 0xF04A4933083066A5LL /* 528 */, 0x8D970ACDD7289AF5LL /* 529 */, + 0x8F96E8E031C8C25ELL /* 530 */, 0xF3FEC02276875D47LL /* 531 */, + 0xEC7BF310056190DDLL /* 532 */, 0xF5ADB0AEBB0F1491LL /* 533 */, + 0x9B50F8850FD58892LL /* 534 */, 0x4975488358B74DE8LL /* 535 */, + 0xA3354FF691531C61LL /* 536 */, 0x0702BBE481D2C6EELL /* 537 */, + 0x89FB24057DEDED98LL /* 538 */, 0xAC3075138596E902LL /* 539 */, + 0x1D2D3580172772EDLL /* 540 */, 0xEB738FC28E6BC30DLL /* 541 */, + 0x5854EF8F63044326LL /* 542 */, 0x9E5C52325ADD3BBELL /* 543 */, + 0x90AA53CF325C4623LL /* 544 */, 0xC1D24D51349DD067LL /* 545 */, + 0x2051CFEEA69EA624LL /* 546 */, 0x13220F0A862E7E4FLL /* 547 */, + 0xCE39399404E04864LL /* 548 */, 0xD9C42CA47086FCB7LL /* 549 */, + 0x685AD2238A03E7CCLL /* 550 */, 0x066484B2AB2FF1DBLL /* 551 */, + 0xFE9D5D70EFBF79ECLL /* 552 */, 0x5B13B9DD9C481854LL /* 553 */, + 0x15F0D475ED1509ADLL /* 554 */, 0x0BEBCD060EC79851LL /* 555 */, + 0xD58C6791183AB7F8LL /* 556 */, 0xD1187C5052F3EEE4LL /* 557 */, + 0xC95D1192E54E82FFLL /* 558 */, 0x86EEA14CB9AC6CA2LL /* 559 */, + 0x3485BEB153677D5DLL /* 560 */, 0xDD191D781F8C492ALL /* 561 */, + 0xF60866BAA784EBF9LL /* 562 */, 0x518F643BA2D08C74LL /* 563 */, + 0x8852E956E1087C22LL /* 564 */, 0xA768CB8DC410AE8DLL /* 565 */, + 0x38047726BFEC8E1ALL /* 566 */, 0xA67738B4CD3B45AALL /* 567 */, + 0xAD16691CEC0DDE19LL /* 568 */, 0xC6D4319380462E07LL /* 569 */, + 0xC5A5876D0BA61938LL /* 570 */, 0x16B9FA1FA58FD840LL /* 571 */, + 0x188AB1173CA74F18LL /* 572 */, 0xABDA2F98C99C021FLL /* 573 */, + 0x3E0580AB134AE816LL /* 574 */, 0x5F3B05B773645ABBLL /* 575 */, + 0x2501A2BE5575F2F6LL /* 576 */, 0x1B2F74004E7E8BA9LL /* 577 */, + 0x1CD7580371E8D953LL /* 578 */, 0x7F6ED89562764E30LL /* 579 */, + 0xB15926FF596F003DLL /* 580 */, 0x9F65293DA8C5D6B9LL /* 581 */, + 0x6ECEF04DD690F84CLL /* 582 */, 0x4782275FFF33AF88LL /* 583 */, + 0xE41433083F820801LL /* 584 */, 0xFD0DFE409A1AF9B5LL /* 585 */, + 0x4325A3342CDB396BLL /* 586 */, 0x8AE77E62B301B252LL /* 587 */, + 0xC36F9E9F6655615ALL /* 588 */, 0x85455A2D92D32C09LL /* 589 */, + 0xF2C7DEA949477485LL /* 590 */, 0x63CFB4C133A39EBALL /* 591 */, + 0x83B040CC6EBC5462LL /* 592 */, 0x3B9454C8FDB326B0LL /* 593 */, + 0x56F56A9E87FFD78CLL /* 594 */, 0x2DC2940D99F42BC6LL /* 595 */, + 0x98F7DF096B096E2DLL /* 596 */, 0x19A6E01E3AD852BFLL /* 597 */, + 0x42A99CCBDBD4B40BLL /* 598 */, 0xA59998AF45E9C559LL /* 599 */, + 0x366295E807D93186LL /* 600 */, 0x6B48181BFAA1F773LL /* 601 */, + 0x1FEC57E2157A0A1DLL /* 602 */, 0x4667446AF6201AD5LL /* 603 */, + 0xE615EBCACFB0F075LL /* 604 */, 0xB8F31F4F68290778LL /* 605 */, + 0x22713ED6CE22D11ELL /* 606 */, 0x3057C1A72EC3C93BLL /* 607 */, + 0xCB46ACC37C3F1F2FLL /* 608 */, 0xDBB893FD02AAF50ELL /* 609 */, + 0x331FD92E600B9FCFLL /* 610 */, 0xA498F96148EA3AD6LL /* 611 */, + 0xA8D8426E8B6A83EALL /* 612 */, 0xA089B274B7735CDCLL /* 613 */, + 0x87F6B3731E524A11LL /* 614 */, 0x118808E5CBC96749LL /* 615 */, + 0x9906E4C7B19BD394LL /* 616 */, 0xAFED7F7E9B24A20CLL /* 617 */, + 0x6509EADEEB3644A7LL /* 618 */, 0x6C1EF1D3E8EF0EDELL /* 619 */, + 0xB9C97D43E9798FB4LL /* 620 */, 0xA2F2D784740C28A3LL /* 621 */, + 0x7B8496476197566FLL /* 622 */, 0x7A5BE3E6B65F069DLL /* 623 */, + 0xF96330ED78BE6F10LL /* 624 */, 0xEEE60DE77A076A15LL /* 625 */, + 0x2B4BEE4AA08B9BD0LL /* 626 */, 0x6A56A63EC7B8894ELL /* 627 */, + 0x02121359BA34FEF4LL /* 628 */, 0x4CBF99F8283703FCLL /* 629 */, + 0x398071350CAF30C8LL /* 630 */, 0xD0A77A89F017687ALL /* 631 */, + 0xF1C1A9EB9E423569LL /* 632 */, 0x8C7976282DEE8199LL /* 633 */, + 0x5D1737A5DD1F7ABDLL /* 634 */, 0x4F53433C09A9FA80LL /* 635 */, + 0xFA8B0C53DF7CA1D9LL /* 636 */, 0x3FD9DCBC886CCB77LL /* 637 */, + 0xC040917CA91B4720LL /* 638 */, 0x7DD00142F9D1DCDFLL /* 639 */, + 0x8476FC1D4F387B58LL /* 640 */, 0x23F8E7C5F3316503LL /* 641 */, + 0x032A2244E7E37339LL /* 642 */, 0x5C87A5D750F5A74BLL /* 643 */, + 0x082B4CC43698992ELL /* 644 */, 0xDF917BECB858F63CLL /* 645 */, + 0x3270B8FC5BF86DDALL /* 646 */, 0x10AE72BB29B5DD76LL /* 647 */, + 0x576AC94E7700362BLL /* 648 */, 0x1AD112DAC61EFB8FLL /* 649 */, + 0x691BC30EC5FAA427LL /* 650 */, 0xFF246311CC327143LL /* 651 */, + 0x3142368E30E53206LL /* 652 */, 0x71380E31E02CA396LL /* 653 */, + 0x958D5C960AAD76F1LL /* 654 */, 0xF8D6F430C16DA536LL /* 655 */, + 0xC8FFD13F1BE7E1D2LL /* 656 */, 0x7578AE66004DDBE1LL /* 657 */, + 0x05833F01067BE646LL /* 658 */, 0xBB34B5AD3BFE586DLL /* 659 */, + 0x095F34C9A12B97F0LL /* 660 */, 0x247AB64525D60CA8LL /* 661 */, + 0xDCDBC6F3017477D1LL /* 662 */, 0x4A2E14D4DECAD24DLL /* 663 */, + 0xBDB5E6D9BE0A1EEBLL /* 664 */, 0x2A7E70F7794301ABLL /* 665 */, + 0xDEF42D8A270540FDLL /* 666 */, 0x01078EC0A34C22C1LL /* 667 */, + 0xE5DE511AF4C16387LL /* 668 */, 0x7EBB3A52BD9A330ALL /* 669 */, + 0x77697857AA7D6435LL /* 670 */, 0x004E831603AE4C32LL /* 671 */, + 0xE7A21020AD78E312LL /* 672 */, 0x9D41A70C6AB420F2LL /* 673 */, + 0x28E06C18EA1141E6LL /* 674 */, 0xD2B28CBD984F6B28LL /* 675 */, + 0x26B75F6C446E9D83LL /* 676 */, 0xBA47568C4D418D7FLL /* 677 */, + 0xD80BADBFE6183D8ELL /* 678 */, 0x0E206D7F5F166044LL /* 679 */, + 0xE258A43911CBCA3ELL /* 680 */, 0x723A1746B21DC0BCLL /* 681 */, + 0xC7CAA854F5D7CDD3LL /* 682 */, 0x7CAC32883D261D9CLL /* 683 */, + 0x7690C26423BA942CLL /* 684 */, 0x17E55524478042B8LL /* 685 */, + 0xE0BE477656A2389FLL /* 686 */, 0x4D289B5E67AB2DA0LL /* 687 */, + 0x44862B9C8FBBFD31LL /* 688 */, 0xB47CC8049D141365LL /* 689 */, + 0x822C1B362B91C793LL /* 690 */, 0x4EB14655FB13DFD8LL /* 691 */, + 0x1ECBBA0714E2A97BLL /* 692 */, 0x6143459D5CDE5F14LL /* 693 */, + 0x53A8FBF1D5F0AC89LL /* 694 */, 0x97EA04D81C5E5B00LL /* 695 */, + 0x622181A8D4FDB3F3LL /* 696 */, 0xE9BCD341572A1208LL /* 697 */, + 0x1411258643CCE58ALL /* 698 */, 0x9144C5FEA4C6E0A4LL /* 699 */, + 0x0D33D06565CF620FLL /* 700 */, 0x54A48D489F219CA1LL /* 701 */, + 0xC43E5EAC6D63C821LL /* 702 */, 0xA9728B3A72770DAFLL /* 703 */, + 0xD7934E7B20DF87EFLL /* 704 */, 0xE35503B61A3E86E5LL /* 705 */, + 0xCAE321FBC819D504LL /* 706 */, 0x129A50B3AC60BFA6LL /* 707 */, + 0xCD5E68EA7E9FB6C3LL /* 708 */, 0xB01C90199483B1C7LL /* 709 */, + 0x3DE93CD5C295376CLL /* 710 */, 0xAED52EDF2AB9AD13LL /* 711 */, + 0x2E60F512C0A07884LL /* 712 */, 0xBC3D86A3E36210C9LL /* 713 */, + 0x35269D9B163951CELL /* 714 */, 0x0C7D6E2AD0CDB5FALL /* 715 */, + 0x59E86297D87F5733LL /* 716 */, 0x298EF221898DB0E7LL /* 717 */, + 0x55000029D1A5AA7ELL /* 718 */, 0x8BC08AE1B5061B45LL /* 719 */, + 0xC2C31C2B6C92703ALL /* 720 */, 0x94CC596BAF25EF42LL /* 721 */, + 0x0A1D73DB22540456LL /* 722 */, 0x04B6A0F9D9C4179ALL /* 723 */, + 0xEFFDAFA2AE3D3C60LL /* 724 */, 0xF7C8075BB49496C4LL /* 725 */, + 0x9CC5C7141D1CD4E3LL /* 726 */, 0x78BD1638218E5534LL /* 727 */, + 0xB2F11568F850246ALL /* 728 */, 0xEDFABCFA9502BC29LL /* 729 */, + 0x796CE5F2DA23051BLL /* 730 */, 0xAAE128B0DC93537CLL /* 731 */, + 0x3A493DA0EE4B29AELL /* 732 */, 0xB5DF6B2C416895D7LL /* 733 */, + 0xFCABBD25122D7F37LL /* 734 */, 0x70810B58105DC4B1LL /* 735 */, + 0xE10FDD37F7882A90LL /* 736 */, 0x524DCAB5518A3F5CLL /* 737 */, + 0x3C9E85878451255BLL /* 738 */, 0x4029828119BD34E2LL /* 739 */, + 0x74A05B6F5D3CECCBLL /* 740 */, 0xB610021542E13ECALL /* 741 */, + 0x0FF979D12F59E2ACLL /* 742 */, 0x6037DA27E4F9CC50LL /* 743 */, + 0x5E92975A0DF1847DLL /* 744 */, 0xD66DE190D3E623FELL /* 745 */, + 0x5032D6B87B568048LL /* 746 */, 0x9A36B7CE8235216ELL /* 747 */, + 0x80272A7A24F64B4ALL /* 748 */, 0x93EFED8B8C6916F7LL /* 749 */, + 0x37DDBFF44CCE1555LL /* 750 */, 0x4B95DB5D4B99BD25LL /* 751 */, + 0x92D3FDA169812FC0LL /* 752 */, 0xFB1A4A9A90660BB6LL /* 753 */, + 0x730C196946A4B9B2LL /* 754 */, 0x81E289AA7F49DA68LL /* 755 */, + 0x64669A0F83B1A05FLL /* 756 */, 0x27B3FF7D9644F48BLL /* 757 */, + 0xCC6B615C8DB675B3LL /* 758 */, 0x674F20B9BCEBBE95LL /* 759 */, + 0x6F31238275655982LL /* 760 */, 0x5AE488713E45CF05LL /* 761 */, + 0xBF619F9954C21157LL /* 762 */, 0xEABAC46040A8EAE9LL /* 763 */, + 0x454C6FE9F2C0C1CDLL /* 764 */, 0x419CF6496412691CLL /* 765 */, + 0xD3DC3BEF265B0F70LL /* 766 */, 0x6D0E60F5C3578A9ELL /* 767 */, + 0x5B0E608526323C55LL /* 768 */, 0x1A46C1A9FA1B59F5LL /* 769 */, + 0xA9E245A17C4C8FFALL /* 770 */, 0x65CA5159DB2955D7LL /* 771 */, + 0x05DB0A76CE35AFC2LL /* 772 */, 0x81EAC77EA9113D45LL /* 773 */, + 0x528EF88AB6AC0A0DLL /* 774 */, 0xA09EA253597BE3FFLL /* 775 */, + 0x430DDFB3AC48CD56LL /* 776 */, 0xC4B3A67AF45CE46FLL /* 777 */, + 0x4ECECFD8FBE2D05ELL /* 778 */, 0x3EF56F10B39935F0LL /* 779 */, + 0x0B22D6829CD619C6LL /* 780 */, 0x17FD460A74DF2069LL /* 781 */, + 0x6CF8CC8E8510ED40LL /* 782 */, 0xD6C824BF3A6ECAA7LL /* 783 */, + 0x61243D581A817049LL /* 784 */, 0x048BACB6BBC163A2LL /* 785 */, + 0xD9A38AC27D44CC32LL /* 786 */, 0x7FDDFF5BAAF410ABLL /* 787 */, + 0xAD6D495AA804824BLL /* 788 */, 0xE1A6A74F2D8C9F94LL /* 789 */, + 0xD4F7851235DEE8E3LL /* 790 */, 0xFD4B7F886540D893LL /* 791 */, + 0x247C20042AA4BFDALL /* 792 */, 0x096EA1C517D1327CLL /* 793 */, + 0xD56966B4361A6685LL /* 794 */, 0x277DA5C31221057DLL /* 795 */, + 0x94D59893A43ACFF7LL /* 796 */, 0x64F0C51CCDC02281LL /* 797 */, + 0x3D33BCC4FF6189DBLL /* 798 */, 0xE005CB184CE66AF1LL /* 799 */, + 0xFF5CCD1D1DB99BEALL /* 800 */, 0xB0B854A7FE42980FLL /* 801 */, + 0x7BD46A6A718D4B9FLL /* 802 */, 0xD10FA8CC22A5FD8CLL /* 803 */, + 0xD31484952BE4BD31LL /* 804 */, 0xC7FA975FCB243847LL /* 805 */, + 0x4886ED1E5846C407LL /* 806 */, 0x28CDDB791EB70B04LL /* 807 */, + 0xC2B00BE2F573417FLL /* 808 */, 0x5C9590452180F877LL /* 809 */, + 0x7A6BDDFFF370EB00LL /* 810 */, 0xCE509E38D6D9D6A4LL /* 811 */, + 0xEBEB0F00647FA702LL /* 812 */, 0x1DCC06CF76606F06LL /* 813 */, + 0xE4D9F28BA286FF0ALL /* 814 */, 0xD85A305DC918C262LL /* 815 */, + 0x475B1D8732225F54LL /* 816 */, 0x2D4FB51668CCB5FELL /* 817 */, + 0xA679B9D9D72BBA20LL /* 818 */, 0x53841C0D912D43A5LL /* 819 */, + 0x3B7EAA48BF12A4E8LL /* 820 */, 0x781E0E47F22F1DDFLL /* 821 */, + 0xEFF20CE60AB50973LL /* 822 */, 0x20D261D19DFFB742LL /* 823 */, + 0x16A12B03062A2E39LL /* 824 */, 0x1960EB2239650495LL /* 825 */, + 0x251C16FED50EB8B8LL /* 826 */, 0x9AC0C330F826016ELL /* 827 */, + 0xED152665953E7671LL /* 828 */, 0x02D63194A6369570LL /* 829 */, + 0x5074F08394B1C987LL /* 830 */, 0x70BA598C90B25CE1LL /* 831 */, + 0x794A15810B9742F6LL /* 832 */, 0x0D5925E9FCAF8C6CLL /* 833 */, + 0x3067716CD868744ELL /* 834 */, 0x910AB077E8D7731BLL /* 835 */, + 0x6A61BBDB5AC42F61LL /* 836 */, 0x93513EFBF0851567LL /* 837 */, + 0xF494724B9E83E9D5LL /* 838 */, 0xE887E1985C09648DLL /* 839 */, + 0x34B1D3C675370CFDLL /* 840 */, 0xDC35E433BC0D255DLL /* 841 */, + 0xD0AAB84234131BE0LL /* 842 */, 0x08042A50B48B7EAFLL /* 843 */, + 0x9997C4EE44A3AB35LL /* 844 */, 0x829A7B49201799D0LL /* 845 */, + 0x263B8307B7C54441LL /* 846 */, 0x752F95F4FD6A6CA6LL /* 847 */, + 0x927217402C08C6E5LL /* 848 */, 0x2A8AB754A795D9EELL /* 849 */, + 0xA442F7552F72943DLL /* 850 */, 0x2C31334E19781208LL /* 851 */, + 0x4FA98D7CEAEE6291LL /* 852 */, 0x55C3862F665DB309LL /* 853 */, + 0xBD0610175D53B1F3LL /* 854 */, 0x46FE6CB840413F27LL /* 855 */, + 0x3FE03792DF0CFA59LL /* 856 */, 0xCFE700372EB85E8FLL /* 857 */, + 0xA7BE29E7ADBCE118LL /* 858 */, 0xE544EE5CDE8431DDLL /* 859 */, + 0x8A781B1B41F1873ELL /* 860 */, 0xA5C94C78A0D2F0E7LL /* 861 */, + 0x39412E2877B60728LL /* 862 */, 0xA1265EF3AFC9A62CLL /* 863 */, + 0xBCC2770C6A2506C5LL /* 864 */, 0x3AB66DD5DCE1CE12LL /* 865 */, + 0xE65499D04A675B37LL /* 866 */, 0x7D8F523481BFD216LL /* 867 */, + 0x0F6F64FCEC15F389LL /* 868 */, 0x74EFBE618B5B13C8LL /* 869 */, + 0xACDC82B714273E1DLL /* 870 */, 0xDD40BFE003199D17LL /* 871 */, + 0x37E99257E7E061F8LL /* 872 */, 0xFA52626904775AAALL /* 873 */, + 0x8BBBF63A463D56F9LL /* 874 */, 0xF0013F1543A26E64LL /* 875 */, + 0xA8307E9F879EC898LL /* 876 */, 0xCC4C27A4150177CCLL /* 877 */, + 0x1B432F2CCA1D3348LL /* 878 */, 0xDE1D1F8F9F6FA013LL /* 879 */, + 0x606602A047A7DDD6LL /* 880 */, 0xD237AB64CC1CB2C7LL /* 881 */, + 0x9B938E7225FCD1D3LL /* 882 */, 0xEC4E03708E0FF476LL /* 883 */, + 0xFEB2FBDA3D03C12DLL /* 884 */, 0xAE0BCED2EE43889ALL /* 885 */, + 0x22CB8923EBFB4F43LL /* 886 */, 0x69360D013CF7396DLL /* 887 */, + 0x855E3602D2D4E022LL /* 888 */, 0x073805BAD01F784CLL /* 889 */, + 0x33E17A133852F546LL /* 890 */, 0xDF4874058AC7B638LL /* 891 */, + 0xBA92B29C678AA14ALL /* 892 */, 0x0CE89FC76CFAADCDLL /* 893 */, + 0x5F9D4E0908339E34LL /* 894 */, 0xF1AFE9291F5923B9LL /* 895 */, + 0x6E3480F60F4A265FLL /* 896 */, 0xEEBF3A2AB29B841CLL /* 897 */, + 0xE21938A88F91B4ADLL /* 898 */, 0x57DFEFF845C6D3C3LL /* 899 */, + 0x2F006B0BF62CAAF2LL /* 900 */, 0x62F479EF6F75EE78LL /* 901 */, + 0x11A55AD41C8916A9LL /* 902 */, 0xF229D29084FED453LL /* 903 */, + 0x42F1C27B16B000E6LL /* 904 */, 0x2B1F76749823C074LL /* 905 */, + 0x4B76ECA3C2745360LL /* 906 */, 0x8C98F463B91691BDLL /* 907 */, + 0x14BCC93CF1ADE66ALL /* 908 */, 0x8885213E6D458397LL /* 909 */, + 0x8E177DF0274D4711LL /* 910 */, 0xB49B73B5503F2951LL /* 911 */, + 0x10168168C3F96B6BLL /* 912 */, 0x0E3D963B63CAB0AELL /* 913 */, + 0x8DFC4B5655A1DB14LL /* 914 */, 0xF789F1356E14DE5CLL /* 915 */, + 0x683E68AF4E51DAC1LL /* 916 */, 0xC9A84F9D8D4B0FD9LL /* 917 */, + 0x3691E03F52A0F9D1LL /* 918 */, 0x5ED86E46E1878E80LL /* 919 */, + 0x3C711A0E99D07150LL /* 920 */, 0x5A0865B20C4E9310LL /* 921 */, + 0x56FBFC1FE4F0682ELL /* 922 */, 0xEA8D5DE3105EDF9BLL /* 923 */, + 0x71ABFDB12379187ALL /* 924 */, 0x2EB99DE1BEE77B9CLL /* 925 */, + 0x21ECC0EA33CF4523LL /* 926 */, 0x59A4D7521805C7A1LL /* 927 */, + 0x3896F5EB56AE7C72LL /* 928 */, 0xAA638F3DB18F75DCLL /* 929 */, + 0x9F39358DABE9808ELL /* 930 */, 0xB7DEFA91C00B72ACLL /* 931 */, + 0x6B5541FD62492D92LL /* 932 */, 0x6DC6DEE8F92E4D5BLL /* 933 */, + 0x353F57ABC4BEEA7ELL /* 934 */, 0x735769D6DA5690CELL /* 935 */, + 0x0A234AA642391484LL /* 936 */, 0xF6F9508028F80D9DLL /* 937 */, + 0xB8E319A27AB3F215LL /* 938 */, 0x31AD9C1151341A4DLL /* 939 */, + 0x773C22A57BEF5805LL /* 940 */, 0x45C7561A07968633LL /* 941 */, + 0xF913DA9E249DBE36LL /* 942 */, 0xDA652D9B78A64C68LL /* 943 */, + 0x4C27A97F3BC334EFLL /* 944 */, 0x76621220E66B17F4LL /* 945 */, + 0x967743899ACD7D0BLL /* 946 */, 0xF3EE5BCAE0ED6782LL /* 947 */, + 0x409F753600C879FCLL /* 948 */, 0x06D09A39B5926DB6LL /* 949 */, + 0x6F83AEB0317AC588LL /* 950 */, 0x01E6CA4A86381F21LL /* 951 */, + 0x66FF3462D19F3025LL /* 952 */, 0x72207C24DDFD3BFBLL /* 953 */, + 0x4AF6B6D3E2ECE2EBLL /* 954 */, 0x9C994DBEC7EA08DELL /* 955 */, + 0x49ACE597B09A8BC4LL /* 956 */, 0xB38C4766CF0797BALL /* 957 */, + 0x131B9373C57C2A75LL /* 958 */, 0xB1822CCE61931E58LL /* 959 */, + 0x9D7555B909BA1C0CLL /* 960 */, 0x127FAFDD937D11D2LL /* 961 */, + 0x29DA3BADC66D92E4LL /* 962 */, 0xA2C1D57154C2ECBCLL /* 963 */, + 0x58C5134D82F6FE24LL /* 964 */, 0x1C3AE3515B62274FLL /* 965 */, + 0xE907C82E01CB8126LL /* 966 */, 0xF8ED091913E37FCBLL /* 967 */, + 0x3249D8F9C80046C9LL /* 968 */, 0x80CF9BEDE388FB63LL /* 969 */, + 0x1881539A116CF19ELL /* 970 */, 0x5103F3F76BD52457LL /* 971 */, + 0x15B7E6F5AE47F7A8LL /* 972 */, 0xDBD7C6DED47E9CCFLL /* 973 */, + 0x44E55C410228BB1ALL /* 974 */, 0xB647D4255EDB4E99LL /* 975 */, + 0x5D11882BB8AAFC30LL /* 976 */, 0xF5098BBB29D3212ALL /* 977 */, + 0x8FB5EA14E90296B3LL /* 978 */, 0x677B942157DD025ALL /* 979 */, + 0xFB58E7C0A390ACB5LL /* 980 */, 0x89D3674C83BD4A01LL /* 981 */, + 0x9E2DA4DF4BF3B93BLL /* 982 */, 0xFCC41E328CAB4829LL /* 983 */, + 0x03F38C96BA582C52LL /* 984 */, 0xCAD1BDBD7FD85DB2LL /* 985 */, + 0xBBB442C16082AE83LL /* 986 */, 0xB95FE86BA5DA9AB0LL /* 987 */, + 0xB22E04673771A93FLL /* 988 */, 0x845358C9493152D8LL /* 989 */, + 0xBE2A488697B4541ELL /* 990 */, 0x95A2DC2DD38E6966LL /* 991 */, + 0xC02C11AC923C852BLL /* 992 */, 0x2388B1990DF2A87BLL /* 993 */, + 0x7C8008FA1B4F37BELL /* 994 */, 0x1F70D0C84D54E503LL /* 995 */, + 0x5490ADEC7ECE57D4LL /* 996 */, 0x002B3C27D9063A3ALL /* 997 */, + 0x7EAEA3848030A2BFLL /* 998 */, 0xC602326DED2003C0LL /* 999 */, + 0x83A7287D69A94086LL /* 1000 */, 0xC57A5FCB30F57A8ALL /* 1001 */, + 0xB56844E479EBE779LL /* 1002 */, 0xA373B40F05DCBCE9LL /* 1003 */, + 0xD71A786E88570EE2LL /* 1004 */, 0x879CBACDBDE8F6A0LL /* 1005 */, + 0x976AD1BCC164A32FLL /* 1006 */, 0xAB21E25E9666D78BLL /* 1007 */, + 0x901063AAE5E5C33CLL /* 1008 */, 0x9818B34448698D90LL /* 1009 */, + 0xE36487AE3E1E8ABBLL /* 1010 */, 0xAFBDF931893BDCB4LL /* 1011 */, + 0x6345A0DC5FBBD519LL /* 1012 */, 0x8628FE269B9465CALL /* 1013 */, + 0x1E5D01603F9C51ECLL /* 1014 */, 0x4DE44006A15049B7LL /* 1015 */, + 0xBF6C70E5F776CBB1LL /* 1016 */, 0x411218F2EF552BEDLL /* 1017 */, + 0xCB0C0708705A36A3LL /* 1018 */, 0xE74D14754F986044LL /* 1019 */, + 0xCD56D9430EA8280ELL /* 1020 */, 0xC12591D7535F5065LL /* 1021 */, + 0xC83223F1720AEF96LL /* 1022 */, 0xC3A0396F7363A51FLL /* 1023 */ +}; + +/* The following macro denotes that an optimization */ +/* for Alpha is required. It is used only for */ +/* optimization of time. Otherwise it does nothing. */ +#ifdef _LP64 +#define OPTIMIZE_FOR_LP64 +#endif + +/* NOTE that this code is NOT FULLY OPTIMIZED for any */ +/* machine. Assembly code might be much faster on some */ +/* machines, especially if the code is compiled with */ +/* gcc. */ + +/* The number of passes of the hash function. */ +/* Three passes are recommended. */ +/* Use four passes when you need extra security. */ +/* Must be at least three. */ +#define PASSES 3 + +#define T1 (table) +#define T2 (table+256) +#define T3 (table+(256*2)) +#define T4 (table+(256*3)) + +#define SAVE_ABC do { \ + aa = a; \ + bb = b; \ + cc = c; \ +} while (/*CONSTCOND*/0) + +#ifdef OPTIMIZE_FOR_LP64 +/* This is the official definition of round */ +#define ROUND(a,b,c,x,mul) do { \ + c ^= x; \ + a -= T1[((c)>>(0*8))&0xFF] ^ T2[((c)>>(2*8))&0xFF] ^ \ + T3[((c)>>(4*8))&0xFF] ^ T4[((c)>>(6*8))&0xFF] ; \ + b += T4[((c)>>(1*8))&0xFF] ^ T3[((c)>>(3*8))&0xFF] ^ \ + T2[((c)>>(5*8))&0xFF] ^ T1[((c)>>(7*8))&0xFF] ; \ + b *= mul; \ +} while (/*CONSTCOND*/ 0) +#else +/* This code works faster when compiled on 32-bit machines */ +/* (but works slower on Alpha) */ +#define ROUND(a,b,c,x,mul) do { \ + c ^= x; \ + a -= T1[(uint8_t)(c)] ^ \ + T2[(const uint8_t)(((uint32_t)(c))>>(2*8))] ^ \ + T3[(const uint8_t)((c)>>(4*8))] ^ \ + T4[(const uint8_t)(((uint32_t)((c)>>(4*8)))>>(2*8))] ; \ + b += T4[(uint8_t)(((uint32_t)(c))>>(1*8))] ^ \ + T3[(const uint8_t)(((uint32_t)(c))>>(3*8))] ^ \ + T2[(const uint8_t)(((uint32_t)((c)>>(4*8)))>>(1*8))] ^ \ + T1[(const uint8_t)(((uint32_t)((c)>>(4*8)))>>(3*8))]; \ + b *= mul; \ +} while (/*CONSTCOND*/0) +#endif + +#define PASS(a,b,c,mul) do { \ + ROUND(a,b,c,x0,mul); \ + ROUND(b,c,a,x1,mul); \ + ROUND(c,a,b,x2,mul); \ + ROUND(a,b,c,x3,mul); \ + ROUND(b,c,a,x4,mul); \ + ROUND(c,a,b,x5,mul); \ + ROUND(a,b,c,x6,mul); \ + ROUND(b,c,a,x7,mul); \ +} while (/*CONSTCOND*/ 0) + +#define KEY_SCHEDULE do { \ + x0 -= x7 ^ (uint64_t)0xA5A5A5A5A5A5A5A5LL; \ + x1 ^= x0; \ + x2 += x1; \ + x3 -= x2 ^ ((~x1)<<19); \ + x4 ^= x3; \ + x5 += x4; \ + x6 -= x5 ^ ((~x4)>>23); \ + x7 ^= x6; \ + x0 += x7; \ + x1 -= x0 ^ ((~x7)<<19); \ + x2 ^= x1; \ + x3 += x2; \ + x4 -= x3 ^ ((~x2)>>23); \ + x5 ^= x4; \ + x6 += x5; \ + x7 -= x6 ^ (uint64_t)0x0123456789ABCDEFLL; \ +} while (/*CONSTCOND*/ 0) + +#define FEEDFORWARD do { \ + a ^= aa; \ + b -= bb; \ + c += cc; \ +} while (/*CONSTCOND*/ 0) + +#ifdef OPTIMIZE_FOR_LP64 +/* The loop is unrolled: works better on Alpha */ +#define COMPRESS do { \ + SAVE_ABC; \ + PASS(a,b,c,5); \ + KEY_SCHEDULE; \ + PASS(c,a,b,7); \ + KEY_SCHEDULE; \ + PASS(b,c,a,9); \ + for (pass_no = 3; pass_no < PASSES; pass_no++) { \ + KEY_SCHEDULE; \ + PASS(a,b,c,9); \ + tmpa = a; a = c; c = b; b = tmpa; \ + } \ + FEEDFORWARD; \ +} while (/*CONSTCOND*/ 0) +#else +/* loop: works better on PC and Sun (smaller cache?) */ +#define COMPRESS do { \ + SAVE_ABC; \ + for (pass_no = 0; pass_no < PASSES; pass_no++) { \ + if (pass_no != 0) { \ + KEY_SCHEDULE; \ + } \ + PASS(a,b,c,(pass_no==0?5:pass_no==1?7:9)); \ + tmpa = a; a = c; c = b; b = tmpa; \ + } \ + FEEDFORWARD; \ +} while (/*CONSTCOND*/0) +#endif + +#define TIGER_COMPRESS_MACRO(str, state) do { \ + uint64_t a, b, c, tmpa; \ + uint64_t aa, bb, cc; \ + uint64_t x0, x1, x2, x3, x4, x5, x6, x7; \ + int pass_no; \ + \ + a = state[0]; \ + b = state[1]; \ + c = state[2]; \ + \ + x0 = str[0]; x1 = str[1]; x2 = str[2]; x3 = str[3]; \ + x4 = str[4]; x5 = str[5]; x6 = str[6]; x7 = str[7]; \ + \ + COMPRESS; \ + \ + state[0] = a; \ + state[1] = b; \ + state[2] = c; \ +} while (/*CONSTCOND*/ 0) + +#ifdef OPTIMIZE_FOR_LP64 +/* The compress function is inlined: works better on Alpha. */ +/* Still leaves the function above in the code, in case some other */ +/* module calls it directly. */ +#define tiger_compress(str, state) \ + TIGER_COMPRESS_MACRO(((const uint64_t*)(const void *)str), ((uint64_t*)(void *)state)) +#else +/* The compress function is a function. Requires smaller cache? */ +static void +tiger_compress(const uint64_t *str, uint64_t state[3]) +{ + TIGER_COMPRESS_MACRO(((const uint64_t*)str), ((uint64_t*)state)); +} +#endif + +/* weird function to format 8 raw bytes to 16 formatted hex chars */ +static void +sprint_uint64(char *buf, uint64_t val) +{ + static const char hexdigits[] = "0123456789abcdef"; + int indian = 1; + int i; + + for (i = 0; i < 8; ++i) { + if (IS_LITTLE_ENDIAN(indian)) { + buf[2 * (7 - i)] = hexdigits[(val >> (56 - 8 * i + 4)) & 15]; + buf[(2 * (7 - i)) + 1] = hexdigits[(val >> (56 - 8 * i)) & 15]; + } else { + buf[2 * i] = hexdigits[(val >> (56 - 8 * i + 4)) & 15]; + buf[(2 * i) + 1] = hexdigits[(val >> (56 - 8 * i)) & 15]; + } + } +} + +/* common function to initialise context */ +static void +initcontext(TIGER_CTX *ctx, uint8_t pad) +{ + (void) memset(ctx, 0x0, sizeof(*ctx)); + ctx->ctx[0] = 0x0123456789ABCDEFLL; + ctx->ctx[1] = 0xFEDCBA9876543210LL; + ctx->ctx[2] = 0xF096A5B4C3B2E187LL; + ctx->init = 1; + ctx->pad = pad; +} + +/* set the version number (0 is same as 1 for Tiger) */ +static int +setversion(TIGER_CTX *ctx, int version) +{ + switch(version) { + case 0: + case 1: + initcontext(ctx, 0x01); + break; + case 2: + initcontext(ctx, 0x80); + break; + default: + (void) fprintf(stderr, "unknown version %d\n", version); + return 0; + } + return 1; +} + +/*****************************************************************************/ + +void +TIGER_Init(TIGER_CTX *ctx) +{ + if (ctx) { + initcontext(ctx, 0x01); + } +} + +void +TIGER2_Init(TIGER_CTX *ctx) +{ + if (ctx) { + initcontext(ctx, 0x80); + } +} + +void +TIGER_Update(TIGER_CTX *ctx, const void *data, size_t length) +{ + const uint64_t *str = (const uint64_t *)data; + uint64_t i; + uint64_t j; + union { + uint8_t temp8[64]; + uint64_t temp64[8]; + } u; + int indian = 1; + + if (ctx == NULL || data == NULL) { + return; + } + for(i = length; i >= 64; i -= 64) { + if (IS_BIG_ENDIAN(indian)) { + for (j = 0; j < 64; j++) { + u.temp8[j ^ 7] = ((const uint8_t *)(const void *)str)[j]; + } + tiger_compress(u.temp64, ctx->ctx); + } else { + tiger_compress(str, ctx->ctx); + } + str += 8; + } + if (IS_BIG_ENDIAN(indian)) { + for (j = 0; j < i; j++) { + u.temp8[j ^ 7] = ((const uint8_t*)(const void *)str)[j]; + } + u.temp8[j ^ 7] = ctx->pad; + for (j++; j&7; j++) { + u.temp8[j ^ 7] = 0; + } + } else { + for (j = 0; j < i; j++) { + u.temp8[j] = ((const uint8_t*)(const void *)str)[j]; + } + u.temp8[j++] = ctx->pad; + for (; j&7; j++) { + u.temp8[j] = 0; + } + } + if (j > 56) { + for (; j < 64; j++) { + u.temp8[j] = 0; + } + tiger_compress(u.temp64, ctx->ctx); + j = 0; + } + for (; j < 56; j++) { + u.temp8[j] = 0; + } + ((uint64_t *)(void *)(&(u.temp8[56])))[0] = ((uint64_t)length) << 3; + tiger_compress(u.temp64, ctx->ctx); +} + +void +TIGER_Final(uint8_t *digest, TIGER_CTX *ctx) +{ + uint64_t le[3]; + int indian = 1; + int i; + + if (digest == NULL || ctx == NULL) { + return; + } + if (!ctx->init) { + TIGER_Init(ctx); + TIGER_Update(ctx, NULL, 0); + } + if (IS_LITTLE_ENDIAN(indian)) { + for (i = 0; i < 3; ++i) { + le[i] = (uint64_t)BSWAP64(ctx->ctx[i]); + } + (void) memcpy(digest, le, 3 * sizeof(le[0])); + } else { + (void) memcpy(digest, ctx->ctx, 3 * sizeof(ctx->ctx[0])); + } +} + +char * +TIGER_End(TIGER_CTX *ctx, char *buf) +{ + int i; + + if (ctx == NULL) { + return NULL; + } + if (buf == NULL && (buf = calloc(1, 49)) == NULL) { + return NULL; + } + if (!ctx->init) { + TIGER_Init(ctx); + TIGER_Update(ctx, NULL, 0); + } + for (i = 0; i < 3; ++i) { + sprint_uint64(buf + i * 16, ctx->ctx[i]); + } + buf[16 * i] = 0x0; + return buf; +} + +char * +TIGER_File(char *filename, char *buf, int version) +{ + TIGER_CTX ctx; + uint8_t buffer[BUFSIZ]; + ssize_t num; + int fd; + int oerrno; + + if (filename == NULL || buf == NULL || !setversion(&ctx, version)) { + return NULL; + } + if ((fd = open(filename, O_RDONLY)) < 0) { + return NULL; + } + while ((num = read(fd, buffer, sizeof(buffer))) > 0) { + TIGER_Update(&ctx, buffer, (size_t)num); + } + oerrno = errno; + close(fd); + errno = oerrno; + return (num < 0) ? NULL : TIGER_End(&ctx, buf); +} + +char * +TIGER_Data(const uint8_t *data, size_t len, char *buf, int version) +{ + TIGER_CTX ctx; + + if (data == NULL || buf == NULL || !setversion(&ctx, version)) { + return NULL; + } + TIGER_Update(&ctx, data, len); + return TIGER_End(&ctx, buf); +} diff --git a/crypto/external/bsd/netpgp/dist/src/libdigest/tiger.h b/crypto/external/bsd/netpgp/dist/src/libdigest/tiger.h new file mode 100644 index 000000000000..ff25cf949d36 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libdigest/tiger.h @@ -0,0 +1,65 @@ +/*- + * Copyright (c) 2005-2011 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef TIGER_H_ +#define TIGER_H_ + +#include + +#include + +#ifndef __BEGIN_DECLS +# if defined(__cplusplus) +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +# else +# define __BEGIN_DECLS +# define __END_DECLS +# endif +#endif + +__BEGIN_DECLS + +#define TIGER_DIGEST_LENGTH 24 +#define TIGER_DIGEST_STRING_LENGTH ((TIGER_DIGEST_LENGTH * 2) + 1) + +typedef struct TIGER_CTX { + uint64_t ctx[3]; + int init; + uint8_t pad; +} TIGER_CTX; + +void TIGER_Init(TIGER_CTX *); +void TIGER2_Init(TIGER_CTX *); +void TIGER_Update(TIGER_CTX *, const void *, size_t); +void TIGER_Final(uint8_t *, TIGER_CTX *); + +char *TIGER_End(TIGER_CTX *, char *); + +char *TIGER_File(char *, char *, int); +char *TIGER_Data(const uint8_t *, size_t, char *, int); + +__END_DECLS + +#endif diff --git a/crypto/external/bsd/netpgp/dist/src/librsa/Makefile b/crypto/external/bsd/netpgp/dist/src/librsa/Makefile new file mode 100644 index 000000000000..a60ebfd462f8 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/librsa/Makefile @@ -0,0 +1,10 @@ +LIB=netrsa +SRCS=rsa.c stubs.c +MKMAN=no +WARNS=4 +CPPFLAGS+=-I${.CURDIR}/../bn + +INCS=rsa.h +INCSDIR=/usr/include/netpgp + +.include diff --git a/crypto/external/bsd/netpgp/dist/src/librsa/libnetpgprsa.3 b/crypto/external/bsd/netpgp/dist/src/librsa/libnetpgprsa.3 new file mode 100644 index 000000000000..e6f972816abb --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/librsa/libnetpgprsa.3 @@ -0,0 +1,114 @@ +.\" $NetBSD: libnetpgprsa.3,v 1.2 2012/11/20 05:26:25 agc Exp $ +.\" +.\" Copyright (c) 2012 Alistair Crooks +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd April 13, 2012 +.Dt LIBNETPGPRSA 3 +.Os +.Sh NAME +.Nm libnetpgprsa +.Nd BIGNUM library of multi-precision integers +.Sh LIBRARY +.Lb libnetpgprsa +.Sh SYNOPSIS +.In netpgp/rsa.h +.Ft RSA * +.Fo RSA_new +.Fa "void" +.Fc +.Ft int +.Fo RSA_size +.Fa "const RSA *rsa" +.Fc +.Ft void +.Fo RSA_free +.Fa "RSA *rsa" +.Fc +.Ft int +.Fo RSA_check_key +.Fa "RSA *rsa" +.Fc +.Ft RSA * +.Fo RSA_generate_key +.Fa "int num" "unsigned long e" "void (*callback)(int, int, void *)" "void *callbackarg" +.Fc +.Ft int +.Fo RSA_public_encrypt +.Fa "int siglen" "const uint8_t *signature" "uint8_t *to" "RSA *rsa" "int padding" +.Fc +.Ft int +.Fo RSA_private_encrypt +.Fa "int siglen" "const uint8_t *signature" "uint8_t *to" "RSA *rsa" "int padding" +.Fc +.Ft int +.Fo RSA_private_decrypt +.Fa "int siglen" "const uint8_t *signature" "uint8_t *to" "RSA *rsa" "int padding" +.Fc +.Pp +.Ft DSA * +.Fo DSA_new +.Fa "void" +.Fc +.Ft int +.Fo DSA_size +.Fa "const DSA *dsa" +.Fc +.Ft void +.Fo DSA_free +.Fa "DSA *dsa" +.Fc +.Ft DSA_SIG * +.Fo DSA_SIG_new +.Fa "void" +.Fc +.Ft void +.Fo DSA_SIG_free +.Fa "DSA_SIG *sig" +.Fc +.Ft int +.Fo DSA_do_verify +.Fa "const unsigned char *digest" "int digestlen" "DSA_SIG *sig" "DSA *dsa" +.Fc +.Ft int +.Fo DSA_do_sign +.Fa "const unsigned char *digest" "int digestlen" "DSA *dsa" +.Fc +.Sh DESCRIPTION +.Nm +is a small library which provides RSA signing, +encryption and decryption, and DSA signing. +RSA and DSA verification are provided by the +.Xr libnetpgpverify 3 +library. +.Pp +.Sh SEE ALSO +.Xr libnetpgpbn 3 +.Xr libnetpgpverify 3 +.Sh HISTORY +The +.Nm +library first appeared in +.Nx 7.0 . +.Sh AUTHORS +.An Alistair Crooks Aq agc@NetBSD.org diff --git a/crypto/external/bsd/netpgp/dist/src/librsa/rsa.c b/crypto/external/bsd/netpgp/dist/src/librsa/rsa.c new file mode 100644 index 000000000000..d25ebb2a2b9e --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/librsa/rsa.c @@ -0,0 +1,696 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include + +#ifdef _KERNEL +# include +# define logmessage log +#else +# include +# include +# include +# include +#endif + +#include "misc.h" +#include "digest.h" +#include "rsa.h" + +#ifndef USE_ARG +#define USE_ARG(x) /*LINTED*/(void)&(x) +#endif + +#define RSA_MAX_MODULUS_BITS 16384 +#define RSA_SMALL_MODULUS_BITS 3072 +#define RSA_MAX_PUBEXP_BITS 64 /* exponent limit enforced for "large" modulus only */ + +static int +rsa_padding_check_none(uint8_t *to, int tlen, const uint8_t *from, int flen, int num) +{ + USE_ARG(num); + if (flen > tlen) { + printf("r too large\n"); + return -1; + } + (void) memset(to, 0x0, tlen - flen); + (void) memcpy(to + tlen - flen, from, flen); + return tlen; +} + +static int +lowlevel_rsa_private_encrypt(int plainc, const unsigned char *plain, unsigned char *encbuf, RSA *rsa) +{ + BIGNUM *decbn; + BIGNUM *signedbn; + uint8_t *decbuf; + int nbytes; + int signc; + int signedbytes; + int r; + + decbuf = NULL; + r = -1; + decbn = BN_new(); + signedbn = BN_new(); + nbytes = BN_num_bytes(rsa->n); + decbuf = netpgp_allocate(1, nbytes); + /* add no padding */ + memcpy(decbuf, plain, plainc); + BN_bin2bn(decbuf, nbytes, decbn); + if (BN_cmp(decbn, rsa->n) >= 0) { + printf("decbn too big\n"); + goto err; + } + if (!BN_mod_exp(signedbn, decbn, rsa->d, rsa->n, NULL)) { + printf("bad mod_exp\n"); + goto err; + } + signedbytes = BN_num_bytes(signedbn); + signc = BN_bn2bin(signedbn, &encbuf[nbytes - signedbytes]); + memset(encbuf, 0x0, nbytes - signc); + r = nbytes; +err: + netpgp_deallocate(decbuf, nbytes); + BN_clear_free(decbn); + BN_clear_free(signedbn); + return r; +} + +static int +lowlevel_rsa_public_encrypt(int plainc, const unsigned char *plain, unsigned char *encbuf, RSA *rsa) +{ + BIGNUM *decbn; + BIGNUM *encbn; + uint8_t *decbuf; + int nbytes; + int encc; + int r; + int i; + + r = -1; + decbn = BN_new(); + encbn = BN_new(); + nbytes = BN_num_bytes(rsa->n); + decbuf = netpgp_allocate(1, nbytes); + (void) memcpy(decbuf, plain, plainc); + if (BN_bin2bn(decbuf, nbytes, decbn) == NULL) { + printf("bin2bn failed\n"); + goto err; + } + if (BN_cmp(decbn, rsa->n) >= 0) { + printf("BN_cmp failed\n"); + goto err; + } + if (!BN_mod_exp(encbn, decbn, rsa->e, rsa->n, NULL)) { + printf("BN_mod_exp failed\n"); + goto err; + } + encc = BN_num_bytes(encbn); + i = BN_bn2bin(encbn, &encbuf[nbytes - encc]); + (void) memset(encbuf, 0x0, nbytes - i); + r = nbytes; +err: + if (decbuf) { + memset(decbuf, 0x0, nbytes); + netpgp_deallocate(decbuf, nbytes); + } + BN_clear_free(decbn); + BN_clear_free(encbn); + return r; +} + +static int +lowlevel_rsa_private_decrypt(int enclen, const unsigned char *encbuf, unsigned char *to, RSA *rsa) +{ + BIGNUM *encbn; + BIGNUM *decbn; + uint8_t *buf; + int nbytes; + int j; + int r; + + r = -1; + decbn = encbn = NULL; + buf = NULL; + if (BN_num_bits(rsa->n) > RSA_MAX_MODULUS_BITS) { + return -1; + } + if (BN_cmp(rsa->n, rsa->e) <= 0) { + return -1; + } + encbn = BN_new(); + decbn = BN_new(); + nbytes = BN_num_bytes(rsa->n); + buf = netpgp_allocate(1, nbytes); + if (enclen > nbytes) { + printf("bad enclen\n"); + goto err; + } + BN_bin2bn(encbuf, enclen, encbn); + if (BN_cmp(encbn, rsa->n) >= 0) { + printf("bad encbn\n"); + goto err; + } + BN_mod_exp(decbn, encbn, rsa->d, rsa->n, NULL); + j = BN_bn2bin(decbn, buf); + r = rsa_padding_check_none(to, nbytes, buf, j, nbytes); +err: + BN_clear_free(encbn); + BN_clear_free(decbn); + netpgp_deallocate(buf, nbytes); + return r; +} + +static int +lowlevel_rsa_public_decrypt(const uint8_t *encbuf, int enclen, uint8_t *dec, const rsa_pubkey_t *rsa) +{ + uint8_t *decbuf; + BIGNUM *decbn; + BIGNUM *encbn; + int decbytes; + int nbytes; + int r; + + nbytes = 0; + r = -1; + decbuf = NULL; + decbn = encbn = NULL; + if (BN_num_bits(rsa->n) > RSA_MAX_MODULUS_BITS) { + printf("rsa r modulus too large\n"); + goto err; + } + if (BN_cmp(rsa->n, rsa->e) <= 0) { + printf("rsa r bad n value\n"); + goto err; + } + if (BN_num_bits(rsa->n) > RSA_SMALL_MODULUS_BITS && + BN_num_bits(rsa->e) > RSA_MAX_PUBEXP_BITS) { + printf("rsa r bad exponent limit\n"); + goto err; + } + if ((encbn = BN_new()) == NULL || + (decbn = BN_new()) == NULL || + (decbuf = netpgp_allocate(1, nbytes = BN_num_bytes(rsa->n))) == NULL) { + printf("allocation failure\n"); + goto err; + } + if (enclen > nbytes) { + printf("rsa r > mod len\n"); + goto err; + } + if (BN_bin2bn(encbuf, enclen, encbn) == NULL) { + printf("null encrypted BN\n"); + goto err; + } + if (BN_cmp(encbn, rsa->n) >= 0) { + printf("rsa r data too large for modulus\n"); + goto err; + } + if (BN_mod_exp(decbn, encbn, rsa->e, rsa->n, NULL) < 0) { + printf("BN_mod_exp < 0\n"); + goto err; + } + decbytes = BN_num_bytes(decbn); + (void) BN_bn2bin(decbn, decbuf); + if ((r = rsa_padding_check_none(dec, nbytes, decbuf, decbytes, 0)) < 0) { + printf("rsa r padding check failed\n"); + } +err: + BN_free(encbn); + BN_free(decbn); + if (decbuf != NULL) { + (void) memset(decbuf, 0x0, nbytes); + netpgp_deallocate(decbuf, nbytes); + } + return r; +} + +#if 0 +/** + @file rsa_make_key.c + RSA key generation, Tom St Denis +*/ + +/** + Create an RSA key + @param prng An active PRNG state + @param wprng The index of the PRNG desired + @param size The size of the modulus (key size) desired (octets) + @param e The "e" value (public key). e==65537 is a good choice + @param key [out] Destination of a newly created private key pair + @return CRYPT_OK if successful, upon error all allocated ram is freed +*/ +static int +rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key) +{ + void *p, *q, *tmp1, *tmp2, *tmp3; + int err; + + LTC_ARGCHK(ltc_mp.name != NULL); + LTC_ARGCHK(key != NULL); + + if ((size < (MIN_RSA_SIZE/8)) || (size > (MAX_RSA_SIZE/8))) { + return CRYPT_INVALID_KEYSIZE; + } + + if ((e < 3) || ((e & 1) == 0)) { + return CRYPT_INVALID_ARG; + } + + if ((err = prng_is_valid(wprng)) != CRYPT_OK) { + return err; + } + + if ((err = mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL)) != CRYPT_OK) { + return err; + } + + /* make primes p and q (optimization provided by Wayne Scott) */ + /* tmp3 = e */ + if ((err = mp_set_int(tmp3, e)) != CRYPT_OK) { + goto errkey; + } + + /* make prime "p" */ + do { + if ((err = rand_prime( p, size/2, prng, wprng)) != CRYPT_OK) { + goto errkey; + } + /* tmp1 = p-1 */ + if ((err = mp_sub_d( p, 1, tmp1)) != CRYPT_OK) { + goto errkey; + } + /* tmp2 = gcd(p-1, e) */ + if ((err = mp_gcd( tmp1, tmp3, tmp2)) != CRYPT_OK) { + goto errkey; + } + } while (mp_cmp_d( tmp2, 1) != 0); + /* while e divides p-1 */ + + /* make prime "q" */ + do { + if ((err = rand_prime( q, size/2, prng, wprng)) != CRYPT_OK) { + goto errkey; + } + /* tmp1 = q-1 */ + if ((err = mp_sub_d( q, 1, tmp1)) != CRYPT_OK) { + goto errkey; + } + /* tmp2 = gcd(q-1, e) */ + if ((err = mp_gcd( tmp1, tmp3, tmp2)) != CRYPT_OK) { + goto errkey; + } + } while (mp_cmp_d( tmp2, 1) != 0); + /* while e divides q-1 */ + + /* tmp1 = lcm(p-1, q-1) */ + /* tmp2 = p-1 */ + if ((err = mp_sub_d( p, 1, tmp2)) != CRYPT_OK) { + goto errkey; + } + /* tmp1 = q-1 (previous do/while loop) */ + /* tmp1 = lcm(p-1, q-1) */ + if ((err = mp_lcm( tmp1, tmp2, tmp1)) != CRYPT_OK) { + goto errkey; + } + + /* make key */ + if ((err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, NULL)) != CRYPT_OK) { + goto errkey; + } + + /* key->e = e */ + if ((err = mp_set_int( key->e, e)) != CRYPT_OK) { + goto errkey; + } + /* key->d = 1/e mod lcm(p-1,q-1) */ + if ((err = mp_invmod( key->e, tmp1, key->d)) != CRYPT_OK) { + goto errkey; + } + /* key->N = pq */ + if ((err = mp_mul( p, q, key->N)) != CRYPT_OK) { + goto errkey; + } + + /* optimize for CRT now */ + /* find d mod q-1 and d mod p-1 */ + /* tmp1 = q-1 */ + if ((err = mp_sub_d( p, 1, tmp1)) != CRYPT_OK) { + goto errkey; + } + /* tmp2 = p-1 */ + if ((err = mp_sub_d( q, 1, tmp2)) != CRYPT_OK) { + goto errkey; + } + /* dP = d mod p-1 */ + if ((err = mp_mod( key->d, tmp1, key->dP)) != CRYPT_OK) { + goto errkey; + } + /* dQ = d mod q-1 */ + if ((err = mp_mod( key->d, tmp2, key->dQ)) != CRYPT_OK) { + goto errkey; + } + /* qP = 1/q mod p */ + if ((err = mp_invmod( q, p, key->qP)) != CRYPT_OK) { + got oerrkey; + } + + if ((err = mp_copy( p, key->p)) != CRYPT_OK) { + goto errkey; + } + if ((err = mp_copy( q, key->q)) != CRYPT_OK) { + goto errkey; + } + + /* set key type (in this case it's CRT optimized) */ + key->type = PK_PRIVATE; + + /* return ok and free temps */ + err = CRYPT_OK; + goto cleanup; +errkey: + mp_clear_multi(key->d, key->e, key->N, key->dQ, key->dP, key->qP, key->p, key->q, NULL); +cleanup: + mp_clear_multi(tmp3, tmp2, tmp1, p, q, NULL); + return err; +} +#endif + +#define HASHBUF_LEN 512 + +#define DSA_MAX_MODULUS_BITS 10000 + +static int +dsa_do_verify(const unsigned char *calculated, int dgst_len, const dsasig_t *sig, mpi_dsa_t *dsa) +{ + BIGNUM *M; + BIGNUM *W; + BIGNUM *t1; + int ret = -1; + int qbits; + + if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL) { + return 0; + } + M = W = t1 = NULL; + qbits = BN_num_bits(dsa->q); + switch(qbits) { + case 160: + case 224: + case 256: + /* openssl sources say these are the valid values */ + /* according to FIPS 186-3 */ + break; + default: + printf("dsa: bad # of Q bits\n"); + return 0; + } + if (BN_num_bits(dsa->p) > DSA_MAX_MODULUS_BITS) { + printf("dsa: p too large\n"); + return 0; + } + /* no love for SHA512? */ + if (dgst_len > SHA256_DIGEST_LENGTH) { + printf("dsa: digest too long\n"); + return 0; + } + ret = 0; + if ((M = BN_new()) == NULL || + (W = BN_new()) == NULL || + (t1 = BN_new()) == NULL) { + goto err; + } + if (BN_is_zero(sig->r) || + BN_is_negative(sig->r) || + BN_cmp(sig->r, dsa->q) >= 0) { + goto err; + } + if (BN_is_zero(sig->s) || + BN_is_negative(sig->s) || + BN_cmp(sig->s, dsa->q) >= 0) { + goto err; + } + if (BN_mod_inverse(W, sig->s, dsa->q, NULL) != MP_OKAY) { + goto err; + } + if (dgst_len > qbits / 8) { + dgst_len = qbits / 8; + } + if (BN_bin2bn(calculated, dgst_len, M) == NULL) { + goto err; + } + if (!BN_mod_mul(M, M, W, dsa->q, NULL)) { + goto err; + } + if (!BN_mod_mul(W, sig->r, W, dsa->q, NULL)) { + goto err; + } + if (!BN_mod_exp(dsa->p, t1, dsa->g, M, NULL)) { + goto err; + } + if (!BN_div(NULL, M, t1, dsa->q, NULL)) { + goto err; + } + ret = (BN_cmp(M, sig->r) == 0); +err: + if (M) { + BN_free(M); + } + if (W) { + BN_free(W); + } + if (t1) { + BN_free(t1); + } + return ret; +} + +/*************************************************************************/ + +int +RSA_size(const RSA *rsa) +{ + return (rsa == NULL) ? 0 : BN_num_bits(rsa->n); +} + +int +DSA_size(const DSA *dsa) +{ + return (dsa == NULL) ? 0 : BN_num_bits(dsa->p); +} + +unsigned +dsa_verify(const signature_t *signature, const dsa_pubkey_t *pubdsa, const uint8_t *calculated, size_t hash_length) +{ + mpi_dsa_t odsa; + dsasig_t osig; + unsigned qlen; + int ret; + + if (signature == NULL || pubdsa == NULL || calculated == NULL) { + return -1; + } + (void) memset(&osig, 0x0, sizeof(osig)); + (void) memset(&odsa, 0x0, sizeof(odsa)); + BN_copy(osig.r, signature->dsa.r); + BN_copy(osig.s, signature->dsa.s); + odsa.p = pubdsa->p; + odsa.q = pubdsa->q; + odsa.g = pubdsa->g; + odsa.pub_key = pubdsa->y; + if ((qlen = BN_num_bytes(odsa.q)) < hash_length) { + hash_length = qlen; + } + ret = dsa_do_verify(calculated, (int)hash_length, &signature->dsa, &odsa); + if (ret < 0) { + return 0; + } + BN_free(odsa.p); + BN_free(odsa.q); + BN_free(odsa.g); + BN_free(odsa.pub_key); + odsa.p = odsa.q = odsa.g = odsa.pub_key = NULL; + BN_free(osig.r); + BN_free(osig.s); + osig.r = osig.s = NULL; + return (unsigned)ret; +} + +RSA * +RSA_new(void) +{ + return netpgp_allocate(1, sizeof(RSA)); +} + +void +RSA_free(RSA *rsa) +{ + if (rsa) { + netpgp_deallocate(rsa, sizeof(*rsa)); + } +} + +int +RSA_check_key(RSA *rsa) +{ + BIGNUM *calcn; + int ret; + + ret = 0; + if (rsa == NULL || rsa->p == NULL || rsa->q == NULL || rsa->n == NULL) { + return -1; + } + /* check that p and q are coprime, and that n = p*q. */ + if (!BN_is_prime(rsa->p, 1, NULL, NULL, NULL) || + !BN_is_prime(rsa->q, 1, NULL, NULL, NULL)) { + return 0; + } + calcn = BN_new(); + BN_mul(calcn, rsa->p, rsa->q, NULL); + if (BN_cmp(calcn, rsa->n) != 0) { + goto errout; + } + /* XXX - check that d*e = 1 mod (p-1*q-1) */ + ret = 1; +errout: + BN_clear_free(calcn); + return ret; +} + +RSA * +RSA_generate_key(int num, unsigned long e, void (*callback)(int,int,void *), void *cb_arg) +{ + /* STUBBED */ + USE_ARG(num); + USE_ARG(e); + USE_ARG(callback); + USE_ARG(cb_arg); + printf("RSA_generate_key stubbed\n"); + return RSA_new(); +} + +/* encrypt */ +int +RSA_public_encrypt(int plainc, const unsigned char *plain, unsigned char *encbuf, RSA *rsa, int padding) +{ + USE_ARG(padding); + if (plain == NULL || encbuf == NULL || rsa == NULL) { + return -1; + } + return lowlevel_rsa_public_encrypt(plainc, plain, encbuf, rsa); +} + +/* decrypt */ +int +RSA_private_decrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +{ + USE_ARG(padding); + if (from == NULL || to == NULL || rsa == NULL) { + return -1; + } + return lowlevel_rsa_private_decrypt(flen, from, to, rsa); +} + +/* sign */ +int +RSA_private_encrypt(int plainc, const unsigned char *plain, unsigned char *encbuf, RSA *rsa, int padding) +{ + USE_ARG(padding); + if (plain == NULL || encbuf == NULL || rsa == NULL) { + return -1; + } + return lowlevel_rsa_private_encrypt(plainc, plain, encbuf, rsa); +} + +/* verify */ +int +RSA_public_decrypt(int enclen, const unsigned char *enc, unsigned char *dec, RSA *rsa, int padding) +{ + rsa_pubkey_t pub; + int ret; + + if (enc == NULL || dec == NULL || rsa == NULL) { + return 0; + } + USE_ARG(padding); + (void) memset(&pub, 0x0, sizeof(pub)); + pub.n = BN_dup(rsa->n); + pub.e = BN_dup(rsa->e); + ret = lowlevel_rsa_public_decrypt(enc, enclen, dec, &pub); + BN_free(pub.n); + BN_free(pub.e); + return ret; +} + +/***********************************************************************/ + +DSA * +DSA_new(void) +{ + return netpgp_allocate(1, sizeof(DSA)); +} + +void +DSA_free(DSA *dsa) +{ + if (dsa) { + netpgp_deallocate(dsa, sizeof(*dsa)); + } +} + +DSA_SIG * +DSA_SIG_new(void) +{ + return netpgp_allocate(1, sizeof(DSA_SIG)); +} + +void +DSA_SIG_free(DSA_SIG *sig) +{ + if (sig) { + netpgp_deallocate(sig, sizeof(*sig)); + } +} + +DSA_SIG * +DSA_do_sign(const unsigned char *dgst, int dlen, DSA *dsa) +{ + /* STUBBED */ + USE_ARG(dgst); + USE_ARG(dlen); + USE_ARG(dsa); + printf("DSA_do_sign stubbed\n"); + return DSA_SIG_new(); +} + +int +DSA_do_verify(const unsigned char *dgst, int dgst_len, DSA_SIG *sig, DSA *dsa) +{ + if (dgst == NULL || dgst_len == 0 || sig == NULL || dsa == NULL) { + return -1; + } + return dsa_do_verify(dgst, dgst_len, sig, dsa); +} diff --git a/crypto/external/bsd/netpgp/dist/src/librsa/rsa.h b/crypto/external/bsd/netpgp/dist/src/librsa/rsa.h new file mode 100644 index 000000000000..739c9756df43 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/librsa/rsa.h @@ -0,0 +1,155 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef RSA_H_ +#define RSA_H_ 20120325 + +#include "bn.h" + +#ifndef __BEGIN_DECLS +# if defined(__cplusplus) +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +# else +# define __BEGIN_DECLS +# define __END_DECLS +# endif +#endif + +__BEGIN_DECLS + +typedef struct rsa_pubkey_t { + BIGNUM *n; /* RSA public modulus n */ + BIGNUM *e; /* RSA public encryption exponent e */ +} rsa_pubkey_t; + +typedef struct mpi_rsa_t { + int f1; /* openssl pad */ + long f2; /* openssl version */ + const void *f3; /* openssl method */ + void *f4; /* openssl engine */ + BIGNUM *n; + BIGNUM *e; + BIGNUM *d; + BIGNUM *p; + BIGNUM *q; + BIGNUM *dmp1; + BIGNUM *dmq1; + BIGNUM *iqmp; +} mpi_rsa_t; + +#define RSA mpi_rsa_t + +typedef struct dsa_pubkey_t { + BIGNUM *p; /* DSA public modulus n */ + BIGNUM *q; /* DSA public encryption exponent e */ + BIGNUM *g; + BIGNUM *y; +} dsa_pubkey_t; + +typedef struct mpi_dsa_t { + BIGNUM *p; + BIGNUM *q; + BIGNUM *g; + BIGNUM *y; + BIGNUM *x; + BIGNUM *pub_key; + BIGNUM *priv_key; +} mpi_dsa_t; + +#define DSA mpi_dsa_t + +typedef struct rsasig_t { + BIGNUM *sig; /* mpi which is actual signature */ +} rsasig_t; + +typedef struct dsasig_t { + BIGNUM *r; /* mpi which is actual signature */ + BIGNUM *s; /* mpi which is actual signature */ +} dsasig_t; + +#define DSA_SIG dsasig_t + +/* misc defs */ +#define RSA_NO_PADDING 3 + +#define SIGNETBSD_ID_SIZE 8 +#define SIGNETBSD_NAME_SIZE 128 + +#define RSA_PUBKEY_ALG 1 +#define DSA_PUBKEY_ALG 17 + +/* the public part of the key */ +typedef struct pubkey_t { + uint32_t version; /* key version - usually 4 */ + uint8_t id[SIGNETBSD_ID_SIZE]; /* binary id */ + char name[SIGNETBSD_NAME_SIZE]; /* name of identity - not necessary, but looks better */ + int64_t birthtime; /* time of creation of key */ + int64_t expiry; /* expiration time of the key */ + uint32_t validity; /* validity in days */ + uint32_t alg; /* pubkey algorithm - rsa/dss etc */ + rsa_pubkey_t rsa; /* specific RSA keys */ + dsa_pubkey_t dsa; /* specific DSA keys */ +} pubkey_t; + +/* signature details (for a specific file) */ +typedef struct signature_t { + uint32_t version; /* signature version number */ + uint32_t type; /* signature type value */ + int64_t birthtime; /* creation time of the signature */ + int64_t expiry; /* expiration time of the signature */ + uint8_t id[SIGNETBSD_ID_SIZE]; /* binary id */ + uint32_t key_alg; /* public key algorithm number */ + uint32_t hash_alg; /* hashing algorithm number */ + rsasig_t rsa; /* RSA signature */ + dsasig_t dsa; /* DSA signature */ + size_t v4_hashlen; /* length of hashed info */ + uint8_t *v4_hashed; /* hashed info */ + uint8_t hash2[2]; /* high 2 bytes of hashed value - for quick test */ + pubkey_t *signer; /* pubkey of signer */ +} signature_t; + +unsigned dsa_verify(const signature_t */*sig*/, const dsa_pubkey_t */*pubdsa*/, const uint8_t */*calc*/, size_t /*hashlen*/); + +RSA *RSA_new(void); +int RSA_size(const RSA */*rsa*/); +void RSA_free(RSA */*rsa*/); +int RSA_check_key(RSA */*rsa*/); +RSA *RSA_generate_key(int /*num*/, unsigned long /*e*/, void (*callback)(int,int,void *), void */*cb_arg*/); +int RSA_public_encrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding); +int RSA_private_decrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding); +int RSA_private_encrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding); +int RSA_public_decrypt(int flen, const uint8_t *from, uint8_t *to, RSA *rsa, int padding); + +DSA *DSA_new(void); +int DSA_size(const DSA */*rsa*/); +void DSA_free(DSA */*dsa*/); +DSA_SIG *DSA_SIG_new(void); +void DSA_SIG_free(DSA_SIG */*sig*/); +int DSA_do_verify(const unsigned char *dgst, int dgst_len, DSA_SIG *sig, DSA *dsa); +DSA_SIG *DSA_do_sign(const unsigned char *dgst, int dlen, DSA *dsa); + +__END_DECLS + +#endif diff --git a/crypto/external/bsd/netpgp/dist/src/librsa/rsastubs.c b/crypto/external/bsd/netpgp/dist/src/librsa/rsastubs.c new file mode 100644 index 000000000000..2c36c7dd5283 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/librsa/rsastubs.c @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include + +#include "rsa.h" +#include "rsastubs.h" + +#ifndef USE_ARG +#define USE_ARG(x) /*LINTED*/(void)&(x) +#endif + +static int +pass_cb(char *buf, int size, int rwflag, void *u) +{ + char *passphrase; + char prompt[128]; + + USE_ARG(rwflag); + snprintf(prompt, sizeof(prompt), "\"%s\" passphrase: ", (char *)u); + if ((passphrase = getpass(prompt)) == NULL) { + return -1; + } + (void) memcpy(buf, passphrase, (size_t)size); + return (int)strlen(passphrase); +} + +RSA * +PEM_read_RSAPrivateKey(FILE *fp, RSA **x, pem_password_cb *cb, void *u) +{ + char phrase[128 + 1]; + RSA *rsa; + int cc; + +fprintf(stderr, "Stubbed PEM_read_RSAPrivateKey\n"); + USE_ARG(u); + if (cb == NULL) { + cb = pass_cb; + } + cc = (*cb)(phrase, sizeof(phrase), 0, u); + rsa = *x = RSA_new(); + USE_ARG(fp); + return rsa; +} + +DSA * +PEM_read_DSAPrivateKey(FILE *fp, DSA **x, pem_password_cb *cb, void *u) +{ + DSA *dsa; + + USE_ARG(u); + if (cb == NULL) { + cb = pass_cb; + } + dsa = *x = DSA_new(); + USE_ARG(fp); + return dsa; +} diff --git a/crypto/external/bsd/netpgp/dist/src/librsa/rsastubs.h b/crypto/external/bsd/netpgp/dist/src/librsa/rsastubs.h new file mode 100644 index 000000000000..e6f999c903e7 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/librsa/rsastubs.h @@ -0,0 +1,25 @@ +#ifndef RSASTUBS_H_ +#define RSASTUBS_H_ 20120412 + +#include "rsa.h" + +#ifndef __BEGIN_DECLS +# if defined(__cplusplus) +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +# else +# define __BEGIN_DECLS +# define __END_DECLS +# endif +#endif + +__BEGIN_DECLS + +typedef int pem_password_cb(char */*buf*/, int /*size*/, int /*rwflag*/, void */*userdata*/); + +RSA *PEM_read_RSAPrivateKey(FILE *fp, RSA **x, pem_password_cb *cb, void *u); +DSA *PEM_read_DSAPrivateKey(FILE *fp, DSA **x, pem_password_cb *cb, void *u); + +__END_DECLS + +#endif diff --git a/crypto/external/bsd/netpgp/dist/src/libverify/Makefile b/crypto/external/bsd/netpgp/dist/src/libverify/Makefile new file mode 100644 index 000000000000..9122bc9b1c68 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libverify/Makefile @@ -0,0 +1,71 @@ +# $NetBSD: Makefile,v 1.2 2012/11/20 05:26:25 agc Exp $ + +PROG=netpgpv +SRCS=libverify.c b64.c pgpsum.c +SRCS+=digest.c tiger.c +SRCS+=bignum.c misc.c +SRCS+=rsaglue.c rsa.c +SRCS+=main.c +WARNS=5 +MKMAN=no +CPPFLAGS+=-I${.CURDIR}/../libbn +CPPFLAGS+=-I${.CURDIR}/../librsa +LDADD+=-lz +LDADD+=-lbz2 + +# XXX - debugging +#CPPFLAGS+=-g -O0 +#LDFLAGS+=-g -O0 +#CPPFLAGS+=-O3 +#LDFLAGS+=-O3 + +.PATH: ${.CURDIR} ${.CURDIR}/../libdigest ${.CURDIR}/../libverify ${.CURDIR}/../libbn ${.CURDIR}/../librsa + +.include + +t: ${PROG} + ./${PROG} -c verify b.gpg > output16 + diff expected16 output16 + rm -f output16 + ./${PROG} -c verify a.gpg > output17 + diff expected17 output17 + rm -f output17 + ./${PROG} -c verify gpgsigned-a.gpg > output18 + diff expected18 output18 + rm -f output18 + ./${PROG} -c verify NetBSD-6.0_RC2_hashes.asc > output19 + diff expected19 output19 + rm -f output19 + ./${PROG} -c cat jj.asc > output20 + diff expected20 output20 + rm -f output20 + ./${PROG} < a.gpg > output21 + diff expected21 output21 + rm -f output21 + ./${PROG} < jj.asc > output22 + diff expected22 output22 + rm -f output22 + ./${PROG} < NetBSD-6.0_RC2_hashes.asc > output23 + diff expected23 output23 + rm -f output23 + ./${PROG} < b.gpg > output24 + diff expected24 output24 + rm -f output24 + ./${PROG} NetBSD-6.0_RC1_hashes.gpg > output25 + diff expected25 output25 + rm -f output25 + ./${PROG} < NetBSD-6.0_RC1_hashes.gpg > output26 + diff expected26 output26 + rm -f output26 + ./${PROG} < NetBSD-6.0_hashes.asc > output27 + diff expected27 output27 + rm -f output27 + ./${PROG} NetBSD-6.0_hashes.asc > output28 + diff expected28 output28 + rm -f output28 + ./${PROG} NetBSD-6.0_RC1_hashes_ascii.gpg > output29 + diff expected29 output29 + rm -f output29 + ./${PROG} < NetBSD-6.0_RC1_hashes_ascii.gpg > output30 + diff expected30 output30 + rm -f output30 diff --git a/crypto/external/bsd/netpgp/dist/src/libverify/array.h b/crypto/external/bsd/netpgp/dist/src/libverify/array.h new file mode 100644 index 000000000000..d5c19a98d67e --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libverify/array.h @@ -0,0 +1,82 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef ARRAY_H_ +#define ARRAY_H_ 20120921 + +#ifndef PGPV_ARRAY +/* creates 2 unsigned vars called "name"c and "name"size in current scope */ +/* also creates an array called "name"s in current scope */ +#define PGPV_ARRAY(type, name) \ + unsigned name##c; unsigned name##vsize; type *name##s +#endif + +/* if this isn't part of a struct, need to specifically initialise things */ +#define ARRAY_INIT(name) do { \ + name##c = name##vsize = 0; \ + name##s = NULL; \ +} while(/*CONSTCOND*/0) + +/* check the array is big enough - if not, expand it by explicit amount */ +/* this is clunky, but there are bugs a-lurking */ +#define ARRAY_EXPAND_SIZED(name, mult, add) do { \ + if (name##c == name##vsize) { \ + void *_v; \ + char *_cv = NULL; \ + unsigned _ents; \ + _ents = (name##vsize * (mult)) + (add); \ + _cv = _v = realloc(name##s, _ents * sizeof(*name##s)); \ + if (_v == NULL) { \ + fprintf(stderr, "ARRAY_EXPAND - bad realloc\n"); \ + } else { \ + memset(&_cv[name##vsize * sizeof(*name##s)], \ + 0x0, (_ents - name##vsize) * sizeof(*name##s)); \ + name##s = _v; \ + name##vsize = _ents; \ + } \ + } \ +} while(/*CONSTCOND*/0) + +/* check the array is big enough - if not, expand it (size * 2) + 10 */ +#define ARRAY_EXPAND(name) ARRAY_EXPAND_SIZED(name, 2, 10) + +#define ARRAY_ELEMENT(name, num) name##s[num] +#define ARRAY_LAST(name) name##s[name##c - 1] +#define ARRAY_COUNT(name) name##c +#define ARRAY_SIZE(name) name##vsize +#define ARRAY_ARRAY(name) name##s + +#define ARRAY_APPEND(name, newel) do { \ + ARRAY_EXPAND(name); \ + ARRAY_COUNT(name) += 1; \ + ARRAY_LAST(name) = newel; \ +} while(/*CONSTCOND*/0) + +#define ARRAY_DELETE(name, num) do { \ + ARRAY_COUNT(name) -= 1; \ + memmove(&ARRAY_ELEMENT(name, num), &ARRAY_ELEMENT(name, num + 1), \ + (ARRAY_COUNT(name) - (num)) * sizeof(ARRAY_ELEMENT(name, 0))); \ +} while(/*CONSTCOND*/0) + +#endif diff --git a/crypto/external/bsd/netpgp/dist/src/libverify/b64.c b/crypto/external/bsd/netpgp/dist/src/libverify/b64.c new file mode 100644 index 000000000000..50412dece7d1 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libverify/b64.c @@ -0,0 +1,355 @@ +/*********************************************************************\ + +MODULE NAME: b64.c + +AUTHOR: Bob Trower 08/04/01 + +PROJECT: Crypt Data Packaging + +COPYRIGHT: Copyright (c) Trantor Standard Systems Inc., 2001 + +NOTE: This source code may be used as you wish, subject to + the MIT license. See the LICENCE section below. + +DESCRIPTION: + This little utility implements the Base64 + Content-Transfer-Encoding standard described in + RFC1113 (http://www.faqs.org/rfcs/rfc1113.html). + + This is the coding scheme used by MIME to allow + binary data to be transferred by SMTP mail. + + Groups of 3 bytes from a binary stream are coded as + groups of 4 bytes in a text stream. + + The input stream is 'padded' with zeros to create + an input that is an even multiple of 3. + + A special character ('=') is used to denote padding so + that the stream can be decoded back to its exact size. + + Encoded output is formatted in lines which should + be a maximum of 72 characters to conform to the + specification. This program defaults to 72 characters, + but will allow more or less through the use of a + switch. The program enforces a minimum line size + of 4 characters. + + Example encoding: + + The stream 'ABCD' is 32 bits long. It is mapped as + follows: + + ABCD + + A (65) B (66) C (67) D (68) (None) (None) + 01000001 01000010 01000011 01000100 + + 16 (Q) 20 (U) 9 (J) 3 (D) 17 (R) 0 (A) NA (=) NA (=) + 010000 010100 001001 000011 010001 000000 000000 000000 + + + QUJDRA== + + Decoding is the process in reverse. A 'decode' lookup + table has been created to avoid string scans. + +DESIGN GOALS: Specifically: + Code is a stand-alone utility to perform base64 + encoding/decoding. It should be genuinely useful + when the need arises and it meets a need that is + likely to occur for some users. + Code acts as sample code to show the author's + design and coding style. + + Generally: + This program is designed to survive: + Everything you need is in a single source file. + It compiles cleanly using a vanilla ANSI C compiler. + It does its job correctly with a minimum of fuss. + The code is not overly clever, not overly simplistic + and not overly verbose. + Access is 'cut and paste' from a web page. + Terms of use are reasonable. + +VALIDATION: Non-trivial code is never without errors. This + file likely has some problems, since it has only + been tested by the author. It is expected with most + source code that there is a period of 'burn-in' when + problems are identified and corrected. That being + said, it is possible to have 'reasonably correct' + code by following a regime of unit test that covers + the most likely cases and regression testing prior + to release. This has been done with this code and + it has a good probability of performing as expected. + + Unit Test Cases: + + case 0:empty file: + CASE0.DAT -> -> + (Zero length target file created + on both encode and decode.) + + case 1:One input character: + CASE1.DAT A -> QQ== -> A + + case 2:Two input characters: + CASE2.DAT AB -> QUJD -> AB + + case 3:Three input characters: + CASE3.DAT ABC -> QUJD -> ABC + + case 4:Four input characters: + case4.dat ABCD -> QUJDRA== -> ABCD + + case 5:All chars from 0 to ff, linesize set to 50: + + AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIj + JCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZH + SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWpr + bG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6P + kJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKz + tLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX + 2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7 + /P3+/w== + + case 6:Mime Block from e-mail: + (Data same as test case 5) + + case 7: Large files: + Tested 28 MB file in/out. + + case 8: Random Binary Integrity: + This binary program (b64.exe) was encoded to base64, + back to binary and then executed. + + case 9 Stress: + All files in a working directory encoded/decoded + and compared with file comparison utility to + ensure that multiple runs do not cause problems + such as exhausting file handles, tmp storage, etc. + + ------------- + + Syntax, operation and failure: + All options/switches tested. Performs as + expected. + + case 10: + No Args -- Shows Usage Screen + Return Code 1 (Invalid Syntax) + case 11: + One Arg (invalid) -- Shows Usage Screen + Return Code 1 (Invalid Syntax) + case 12: + One Arg Help (-?) -- Shows detailed Usage Screen. + Return Code 0 (Success -- help request is valid). + case 13: + One Arg Help (-h) -- Shows detailed Usage Screen. + Return Code 0 (Success -- help request is valid). + case 14: + One Arg (valid) -- Uses stdin/stdout (filter) + Return Code 0 (Sucess) + case 15: + Two Args (invalid file) -- shows system error. + Return Code 2 (File Error) + case 16: + Encode non-existent file -- shows system error. + Return Code 2 (File Error) + case 17: + Out of disk space -- shows system error. + Return Code 3 (File I/O Error) + + ------------- + + Compile/Regression test: + gcc compiled binary under Cygwin + Microsoft Visual Studio under Windows 2000 + Microsoft Version 6.0 C under Windows 2000 + +DEPENDENCIES: None + +LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated + documentation files (the "Software"), to deal in the + Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, + sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall + be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY + KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS + OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +VERSION HISTORY: + Bob Trower 08/04/01 -- Create Version 0.00.00B + +\******************************************************************* */ + +#include +#include +#include + +#include "b64.h" + +/* +** Translation Table as described in RFC1113 +*/ +static const char cb64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* +** Translation Table to decode (created by author) +*/ +static const char cd64[] = "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq"; + +/* +** encodeblock +** +** encode 3 8-bit binary bytes as 4 '6-bit' characters +*/ +static void +encodeblock(uint8_t *wordin, uint8_t *wordout, int wordlen) +{ + wordout[0] = cb64[(unsigned)wordin[0] >> 2]; + wordout[1] = cb64[((unsigned)(wordin[0] & 0x03) << 4) | ((unsigned)(wordin[1] & 0xf0) >> 4)]; + wordout[2] = (uint8_t)(wordlen > 1) ? + cb64[((unsigned)(wordin[1] & 0x0f) << 2) | ((unsigned)(wordin[2] & 0xc0) >> 6)] : '='; + wordout[3] = (uint8_t)(wordlen > 2) ? cb64[wordin[2] & 0x3f] : '='; +} + +/* +** encode +** +** base64 encode a stream adding padding and line breaks as per spec. +*/ +int +b64encode(const char *in, const size_t insize, void *vp, size_t outsize, int linesize) +{ + const char *inp; + unsigned i; + uint8_t wordout[4]; + uint8_t wordin[3]; + char *out = vp; + char *outp; + int blocksout; + int wordlen; + + if (in == NULL || vp == NULL) { + return 0; + } + wordlen = 0; + for (blocksout = 0, inp = in, outp = out; (size_t)(inp - in) < insize && (size_t)(outp - out) < outsize;) { + for (wordlen = 0, i = 0; i < sizeof(wordin); i++) { + wordin[i] = (uint8_t) *inp++; + if ((size_t)(inp - in) <= insize) { + wordlen++; + } else { + wordin[i] = 0x0; + } + } + if (wordlen > 0) { + encodeblock(wordin, wordout, wordlen); + for (i = 0; i < sizeof(wordout) ; i++) { + *outp++ = wordout[i]; + } + blocksout++; + } + if (linesize > 0) { + if (blocksout >= (int)(linesize / sizeof(wordout)) || + (size_t)(inp - in) >= insize) { + if (blocksout) { + *outp++ = '\r'; + *outp++ = '\n'; + } + blocksout = 0; + } + } + } + return (int)(outp - out); +} + +/* +** decodeblock +** +** decode 4 '6-bit' characters into 3 8-bit binary bytes +*/ +static void +decodeblock(uint8_t wordin[4], uint8_t wordout[3]) +{ + wordout[0] = (uint8_t) ((unsigned)wordin[0] << 2 | (unsigned)wordin[1] >> 4); + wordout[1] = (uint8_t) ((unsigned)wordin[1] << 4 | (unsigned)wordin[2] >> 2); + wordout[2] = (uint8_t) (((wordin[2] << 6) & 0xc0) | wordin[3]); +} + +/* +** decode +** +** decode a base64 encoded stream discarding padding, line breaks and noise +*/ +int +b64decode(const char *in, const size_t insize, void *vp, size_t outsize) +{ + const char *inp; + unsigned wordlen; + unsigned i; + uint8_t wordout[3]; + uint8_t wordin[4]; + uint8_t v; + char *out = vp; + char *outp; + + if (in == NULL || vp == NULL) { + return 0; + } + for (inp = in, outp = out ; (size_t)(inp - in) < insize && (size_t)(outp - out) < outsize ; ) { + for (wordlen = 0, i = 0 ; i < sizeof(wordin) && (size_t)(inp - in) < insize ; i++) { + /* get a single character */ + for (v = 0; (size_t)(inp - in) <= insize && v == 0 ; ) { + if (*inp == '\r' && *(inp + 1) == '\n') { + inp += 2; + } else { + v = (uint8_t) *inp++; + v = (uint8_t) ((v < 43 || v > 122) ? 0 : cd64[v - 43]); + if (v) { + v = (uint8_t) ((v == '$') ? 0 : v - 61); + } + } + } + /* perhaps 0x0 pad */ + if ((size_t)(inp - in) <= insize) { + wordlen += 1; + if (v) { + wordin[i] = (uint8_t) (v - 1); + } + } else { + wordin[i] = 0x0; + } + } + if (wordlen > 0) { + decodeblock(wordin, wordout); + for (i = 0; i < wordlen - 1 ; i++) { + *outp++ = wordout[i]; + } + } + } + return (int)(outp - out); +} + +/* return the encoded size for n bytes input */ +int +b64_encsize(unsigned n) +{ + return ((4 * n) / 3) + 4; +} diff --git a/crypto/external/bsd/netpgp/dist/src/libverify/b64.h b/crypto/external/bsd/netpgp/dist/src/libverify/b64.h new file mode 100644 index 000000000000..e939857cbdbf --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libverify/b64.h @@ -0,0 +1,32 @@ +/*- + * Copyright (c) 2010 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef B64_H_ +#define B64_H_ 20091223 + +int b64encode(const char */*in*/, const size_t /*insize*/, void */*vp*/, size_t /*outsize*/, int /*linesize*/); +int b64decode(const char */*in*/, const size_t /*insize*/, void */*vp*/, size_t /*outsize*/); +int b64_encsize(unsigned /*n*/); + +#endif diff --git a/crypto/external/bsd/netpgp/dist/src/libverify/dump.c b/crypto/external/bsd/netpgp/dist/src/libverify/dump.c new file mode 100644 index 000000000000..0c31b4b6b0d4 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libverify/dump.c @@ -0,0 +1,88 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include + +#ifndef isprint +#define isprint(x) ((x) >= ' ' && (x) <= '~') +#endif + +#define HEXDUMP_LINELEN 16 + +#ifndef PRIsize +#define PRIsize "z" +#endif + +/* show hexadecimal/ascii dump */ +static ssize_t +hexdump(const char *in, const size_t len, void *outvp, size_t size) +{ + size_t i; + char line[HEXDUMP_LINELEN + 1]; + char *out = (char *)outvp; + int o; + + for (i = 0, o = 0 ; i < len ; i++) { + if (i % HEXDUMP_LINELEN == 0) { + o += snprintf(&out[o], size - o, + "%.5" PRIsize "u | ", i); + } + o += snprintf(&out[o], size - o, "%.02x ", (uint8_t)in[i]); + line[i % HEXDUMP_LINELEN] = + (isprint((uint8_t)in[i])) ? in[i] : '.'; + if (i % HEXDUMP_LINELEN == HEXDUMP_LINELEN - 1) { + line[HEXDUMP_LINELEN] = 0x0; + o += snprintf(&out[o], size - o, " | %s\n", line); + } + } + if (i % HEXDUMP_LINELEN != 0) { + for ( ; i % HEXDUMP_LINELEN != 0 ; i++) { + o += snprintf(&out[o], size - o, " "); + line[i % HEXDUMP_LINELEN] = ' '; + } + line[HEXDUMP_LINELEN] = 0x0; + o += snprintf(&out[o], size - o, " | %s\n", line); + } + return (ssize_t)o; +} + +void dumpmem(void */*p*/, size_t /*size*/); + +/* just dump an area of memory to stdout */ +void +dumpmem(void *vp, size_t size) +{ + ssize_t cc; + uint8_t *p = (uint8_t *)vp; + char *buf; + + buf = calloc(1, size * 5); + cc = hexdump((const char *)p, size, buf, size * 5); + fprintf(stdout, "%.*s\n", (int)cc, buf); + free(buf); +} diff --git a/crypto/external/bsd/netpgp/dist/src/libverify/libnetpgpverify.3 b/crypto/external/bsd/netpgp/dist/src/libverify/libnetpgpverify.3 new file mode 100644 index 000000000000..5dd95116d1e8 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libverify/libnetpgpverify.3 @@ -0,0 +1,139 @@ +.\" $NetBSD: libnetpgpverify.3,v 1.2 2012/11/20 05:26:26 agc Exp $ +.\" +.\" Copyright (c) 2012 Alistair Crooks +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd October 21, 2012 +.Dt LIBNETPGPVERIFY 3 +.Os +.Sh NAME +.Nm libnetpgpverify +.Nd library to verify digital signatures +.Sh LIBRARY +.Lb libnetpgpverify +.Sh SYNOPSIS +.In netpgp/verify.h +.Ft int +.Fo pgpv_read_pubring +.Fa "pgpv_t *pgp" "const void *keyring" "ssize_t size" +.Fc +.Ft size_t +.Fo pgpv_verify +.Fa "pgpv_cursor_t *cursor" "pgpv_t *pgp" "const void *ptr" "ssize_t size" +.Fc +.Ft size_t +.Fo pgpv_get_verified +.Fa "pgpv_cursor_t *cursor" "size_t cookie " "char **ret" +.Fc +.Ft size_t +.Fo pgpv_get_entry +.Fa "pgpv_t *pgp" "unsigned ent" "char **ret" +.Fc +.Ft int +.Fo pgpv_close +.Fa "pgpv_t *pgp" +.Fc +.Sh DESCRIPTION +.Nm +is a small library which will verify a digital signature on a text or +binary document. +It has been kept deliberately small and only uses compression libraries +to function. +.Pp +PGP messages, including key rings, are made up of PGP packets, defined +in RFC 4880. +To match a digital signature, the public key of the signer must be +located in a public key ring. +This library has enough functionality to parse a pubkey keyring, +using +.Fn pgpv_read_pubring +to read the public keys of trusted identities, +and to read files or memory which has already been signed. +The +.Fn pgpv_verify +function is used to verify the signature, either on data, or on memory. +To signal to +.Fn pgpv_verify +to read a file and verify it, the +.Dv size +argument should be set to +.Dv -1 +whilst a positive size signals that the pointer value should be that +of signed memory. +.Fn pgpv_verify +returns a cookie if the ignature was verified, or 0 if it did not. +This cookie can subsequently be used to retrieve the data which +was verified. +.Pp +If the signature does match, then the file or memory can be considered as being +verified as being unmodified and unchanged, integrally sound. +.Pp +Signatures have validity dates on them, and it is possible for a signature to +have expired when it is being checked. +If for any reason the signature does not match, then the reason for not +verifying the signature will be stored in the +.Dv why +buffer in the +.Dv pgpv_cursor_t +structure. +.Pp +Occasionally, the memory or contents of the file which matched the signature +will be needed, rather than a boolean value of whether it was verified. +To do this, the +.Fn pgpv_get_verified +function is used. +Arguments to +.Fn pgpv_get_verified +are the cookie returned from the verification, and a buffer +allocated for the returned data and its size. +If an error occurs, or the signature is not verified, a zero value is returned +for the size. +.Nm +stores the starts of the data of all verified matches, and so the entry +number argument is the index of the occurrence of verification. +The first match will have an entry number of 0, the second 1, and so on. +.Pp +The +.Fn pgpv_close +function is used to clean up after all matching and verification has taken place. +It frees and de-allocates all resources used in the verification of the signature. +.Pp +The program used for signing may encode into base64 encoding, and it may also +use embedded compression to make the output smaller than it would otherwise be. +This is handled automatically by +.Nm +.Sh SEE ALSO +.Xr bn 3 , +.Xr zlib 3 , +.Xr bzlib2 3 +.Sh STANDARDS +The +.Nm +utility is designed to conform to IETF RFC 4880. +.Sh HISTORY +The +.Nm +library first appeared in +.Nx 7.0 . +.Sh AUTHORS +.An Alistair Crooks Aq agc@NetBSD.org diff --git a/crypto/external/bsd/netpgp/dist/src/libverify/libverify.c b/crypto/external/bsd/netpgp/dist/src/libverify/libverify.c new file mode 100644 index 000000000000..dc04863c6d39 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libverify/libverify.c @@ -0,0 +1,2366 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "array.h" +#include "bn.h" +#include "b64.h" +#include "digest.h" +#include "pgpsum.h" +#include "rsa.h" +#include "verify.h" + +#ifndef USE_ARG +#define USE_ARG(x) /*LINTED*/(void)&(x) +#endif + +#define BITS_TO_BYTES(b) (((b) + (CHAR_BIT - 1)) / CHAR_BIT) + +/* packet types */ +#define SIGNATURE_PKT 2 +#define ONEPASS_SIGNATURE_PKT 4 +#define PUBKEY_PKT 6 +#define COMPRESSED_DATA_PKT 8 +#define MARKER_PKT 10 +#define LITDATA_PKT 11 +#define TRUST_PKT 12 +#define USERID_PKT 13 +#define PUB_SUBKEY_PKT 14 +#define USER_ATTRIBUTE_PKT 17 + +/* only allow certain packets at certain times */ +#define PUBRING_ALLOWED "\002\006\014\015\016\021" +#define SIGNATURE_ALLOWED "\002\004\010\013" + +/* actions to do on close */ +#define FREE_MEM 0x01 +#define UNMAP_MEM 0x02 + +/* types of pubkey we encounter */ +#define PUBKEY_RSA_ENCRYPT_OR_SIGN 1 +#define PUBKEY_RSA_ENCRYPT 2 +#define PUBKEY_RSA_SIGN 3 +#define PUBKEY_ELGAMAL_ENCRYPT 16 +#define PUBKEY_DSA 17 +#define PUBKEY_ELLIPTIC_CURVE 18 +#define PUBKEY_ECDSA 19 +#define PUBKEY_ELGAMAL_ENCRYPT_OR_SIGN 20 + +/* hash algorithm definitions */ +#define PGPV_HASH_MD5 1 +#define PGPV_HASH_SHA1 2 +#define PGPV_HASH_RIPEMD 3 +#define PGPV_HASH_SHA256 8 +#define PGPV_HASH_SHA384 9 +#define PGPV_HASH_SHA512 10 + +/* pubkey defs for bignums */ +#define RSA_N 0 +#define RSA_E 1 +#define DSA_P 0 +#define DSA_Q 1 +#define DSA_G 2 +#define DSA_Y 3 +#define ELGAMAL_P 0 +#define ELGAMAL_G 1 +#define ELGAMAL_Y 2 + +/* sesskey indices */ +#define RSA_SESSKEY_ENCRYPTED_M 0 +#define RSA_SESSKEY_M 1 +#define ELGAMAL_SESSKEY_G_TO_K 0 +#define ELGAMAL_SESSKEY_ENCRYPTED_M 1 + +/* seckey indices */ +#define RSA_SECKEY_D 0 +#define RSA_SECKEY_P 1 +#define RSA_SECKEY_Q 2 +#define RSA_SECKEY_U 3 +#define DSA_SECKEY_X 0 +#define ELGAMAL_SECKEY_X 0 + +/* signature mpi indices in bignumber array */ +#define RSA_SIG 0 +#define DSA_R 0 +#define DSA_S 1 +#define ELGAMAL_SIG_R 0 +#define ELGAMAL_SIG_S 1 + +/* signature types */ +#define SIGTYPE_BINARY_DOC 0x00 /* Signature of a binary document */ +#define SIGTYPE_TEXT 0x01 /* Signature of a canonical text document */ +#define SIGTYPE_STANDALONE 0x02 /* Standalone signature */ + +#define SIGTYPE_GENERIC_USERID 0x10 /* Generic certification of a User ID and Public Key packet */ +#define SIGTYPE_PERSONA_USERID 0x11 /* Persona certification of a User ID and Public Key packet */ +#define SIGTYPE_CASUAL_USERID 0x12 /* Casual certification of a User ID and Public Key packet */ +#define SIGTYPE_POSITIVE_USERID 0x13 /* Positive certification of a User ID and Public Key packet */ + +#define SIGTYPE_SUBKEY_BINDING 0x18 /* Subkey Binding Signature */ +#define SIGTYPE_PRIMARY_KEY_BINDING 0x19 /* Primary Key Binding Signature */ +#define SIGTYPE_DIRECT_KEY 0x1f /* Signature directly on a key */ + +#define SIGTYPE_KEY_REVOCATION 0x20 /* Key revocation signature */ +#define SIGTYPE_SUBKEY_REVOCATION 0x28 /* Subkey revocation signature */ +#define SIGTYPE_CERT_REVOCATION 0x30 /* Certification revocation signature */ + +#define SIGTYPE_TIMESTAMP_SIG 0x40 /* Timestamp signature */ +#define SIGTYPE_3RDPARTY 0x50 /* Third-Party Confirmation signature */ + +/* Forward declarations */ +static int read_all_packets(pgpv_t */*pgp*/, pgpv_mem_t */*mem*/, const char */*op*/); +static int read_binary_file(pgpv_t */*pgp*/, const char */*op*/, const char */*fmt*/, ...); +static int read_binary_memory(pgpv_t */*pgp*/, const char */*op*/, const void */*memory*/, size_t /*size*/); +static int pgpv_find_keyid(pgpv_t */*pgp*/, const char */*strkeyid*/, uint8_t */*keyid*/); + +/* read a file into the pgpv_mem_t struct */ +static int +read_file(pgpv_t *pgp, const char *f) +{ + struct stat st; + pgpv_mem_t *mem; + + ARRAY_EXPAND(pgp->areas); + ARRAY_COUNT(pgp->areas) += 1; + mem = &ARRAY_LAST(pgp->areas); + memset(mem, 0x0, sizeof(*mem)); + if ((mem->fp = fopen(f, "r")) == NULL) { + warn("can't read '%s'", f); + return 0; + } + fstat(fileno(mem->fp), &st); + mem->size = (size_t)st.st_size; + mem->mem = mmap(NULL, mem->size, PROT_READ, MAP_SHARED, fileno(mem->fp), 0); + mem->dealloc = UNMAP_MEM; + return 1; +} + +/* DTRT and free resources */ +static int +closemem(pgpv_mem_t *mem) +{ + switch(mem->dealloc) { + case FREE_MEM: + free(mem->mem); + mem->size = 0; + break; + case UNMAP_MEM: + munmap(mem->mem, mem->size); + fclose(mem->fp); + break; + } + return 1; +} + +/* make a reference to a memory area, and its offset */ +static void +make_ref(pgpv_t *pgp, uint8_t mement, pgpv_ref_t *ref) +{ + ref->mem = mement; + ref->offset = ARRAY_ELEMENT(pgp->areas, ref->mem).cc; + ref->vp = pgp; +} + +/* return the pointer we wanted originally */ +static uint8_t * +get_ref(pgpv_ref_t *ref) +{ + pgpv_mem_t *mem; + pgpv_t *pgp = (pgpv_t *)ref->vp;; + + mem = &ARRAY_ELEMENT(pgp->areas, ref->mem); + return &mem->mem[ref->offset]; +} + +#define IS_PARTIAL(x) ((x) >= 224 && (x) < 255) +#define DECODE_PARTIAL(x) (1 << ((x) & 0x1f)) + +#define PKT_LENGTH(m, off) \ + ((m[off] < 192) ? (m[off]) : \ + (m[off] < 224) ? ((m[off] - 192) << 8) + (m[off + 1]) + 192 : \ + (m[off + 1] << 24) | ((m[off + 2]) << 16) | ((m[off + 3]) << 8) | (m[off + 4])) + +#define PKT_LENGTH_LENGTH(m, off) \ + ((m[off] < 192) ? 1 : (m[off] < 224) ? 2 : 5) + +/* fix up partial body lengths, return new size */ +static size_t +fixup_partials(pgpv_t *pgp, uint8_t *p, size_t totlen, size_t filesize, size_t *cc) +{ + pgpv_mem_t *mem; + size_t partial; + size_t newcc; + + if (totlen > filesize) { + printf("fixup_partial: filesize %zu is less than encoded size %zu\n", filesize, totlen); + return 0; + } + ARRAY_EXPAND(pgp->areas); + ARRAY_COUNT(pgp->areas) += 1; + mem = &ARRAY_LAST(pgp->areas); + mem->size = totlen; + if ((mem->mem = calloc(1, mem->size + 5)) == NULL) { + printf("fixup_partial: can't allocate %zu length\n", totlen); + return 0; + } + newcc = 0; + mem->dealloc = FREE_MEM; + for (*cc = 0 ; *cc < totlen ; newcc += partial, *cc += partial + 1) { + if (IS_PARTIAL(p[*cc])) { + partial = DECODE_PARTIAL(p[*cc]); + memcpy(&mem->mem[newcc], &p[*cc + 1], partial); + } else { + partial = PKT_LENGTH(p, *cc); + *cc += PKT_LENGTH_LENGTH(p, *cc); + memcpy(&mem->mem[newcc], &p[*cc], partial); + newcc += partial; + *cc += partial; + break; + } + } + return newcc; +} + +/* get the weirdo packet length */ +static size_t +get_pkt_len(uint8_t newfmt, uint8_t *p, size_t filesize, int isprimary) +{ + size_t lenbytes; + size_t len; + + if (newfmt) { + if (IS_PARTIAL(*p)) { + if (!isprimary) { + /* for sub-packets, only 1, 2 or 4 byte sizes allowed */ + return ((*p - 192) << 8) + *(p + 1) + 192; + } + lenbytes = 1; + for (len = DECODE_PARTIAL(*p) ; IS_PARTIAL(p[len + lenbytes]) ; lenbytes++) { + len += DECODE_PARTIAL(p[len + lenbytes]); + } + len += get_pkt_len(newfmt, &p[len + lenbytes], filesize, 1); + return len; + } + return PKT_LENGTH(p, 0); + } else { + switch(*--p & 0x3) { + case 0: + return *(p + 1); + case 1: + return (*(p + 1) << 8) | *(p + 2); + case 2: + return (*(p + 1) << 24) | (*(p + 2) << 16) | (*(p + 3) << 8) | *(p + 4); + default: + return filesize; + } + } +} + +/* get the length of the packet length field */ +static unsigned +get_pkt_len_len(uint8_t newfmt, uint8_t *p, int isprimary) +{ + if (newfmt) { + if (IS_PARTIAL(*p)) { + return (isprimary) ? 1 : 2; + } + return PKT_LENGTH_LENGTH(p, 0); + } else { + switch(*--p & 0x3) { + case 0: + return 1; + case 1: + return 2; + case 2: + return 4; + default: + return 0; + } + } +} + +/* copy the 32bit integer in memory in network order */ +static unsigned +fmt_32(uint8_t *p, uint32_t a) +{ + a = htonl(a); + memcpy(p, &a, sizeof(a)); + return sizeof(a); +} + +/* copy the 16bit integer in memory in network order */ +static unsigned +fmt_16(uint8_t *p, uint16_t a) +{ + a = htons(a); + memcpy(p, &a, sizeof(a)); + return sizeof(a); +} + +/* format a binary string in memory */ +static size_t +fmt_binary(char *s, size_t size, const uint8_t *bin, unsigned len) +{ + unsigned i; + size_t cc; + + for (cc = 0, i = 0 ; i < len && cc < size ; i++) { + cc += snprintf(&s[cc], size - cc, "%02x", bin[i]); + } + return cc; +} + +/* format an mpi into memory */ +static unsigned +fmt_binary_mpi(pgpv_bignum_t *mpi, uint8_t *p, size_t size) +{ + unsigned bytes; + BIGNUM *bn; + + bytes = BITS_TO_BYTES(mpi->bits); + if ((size_t)bytes + 2 + 1 > size) { + warn("truncated mpi"); + return 0; + } + bn = (BIGNUM *)mpi->bn; + if (bn == NULL || BN_is_zero(bn)) { + fmt_32(p, 0); + return 2 + 1; + } + fmt_16(p, mpi->bits); + BN_bn2bin(bn, &p[2]); + return bytes + 2; +} + +/* dump an mpi value onto stdout */ +static size_t +fmt_mpi(char *s, size_t size, pgpv_bignum_t *bn, const char *name, int pbits) +{ + size_t cc; + char *buf; + + cc = snprintf(s, size, "%s=", name); + if (pbits) { + cc += snprintf(&s[cc], size - cc, "[%u bits] ", bn->bits); + } + buf = BN_bn2hex(bn->bn); + cc += snprintf(&s[cc], size - cc, "%s\n", buf); + free(buf); + return cc; +} + +#define ALG_IS_RSA(alg) (((alg) == PUBKEY_RSA_ENCRYPT_OR_SIGN) || \ + ((alg) == PUBKEY_RSA_ENCRYPT) || \ + ((alg) == PUBKEY_RSA_SIGN)) + +#define ALG_IS_DSA(alg) ((alg) == PUBKEY_DSA) + +/* format key mpis into memory */ +static unsigned +fmt_key_mpis(pgpv_pubkey_t *pubkey, uint8_t *buf, size_t size) +{ + size_t cc; + + cc = 0; + buf[cc++] = pubkey->version; + cc += fmt_32(&buf[cc], (uint32_t)pubkey->birth); + buf[cc++] = pubkey->keyalg; + switch(pubkey->keyalg) { + case PUBKEY_RSA_ENCRYPT_OR_SIGN: + case PUBKEY_RSA_ENCRYPT: + case PUBKEY_RSA_SIGN: + cc += fmt_binary_mpi(&pubkey->bn[RSA_N], &buf[cc], size - cc); + cc += fmt_binary_mpi(&pubkey->bn[RSA_E], &buf[cc], size - cc); + break; + case PUBKEY_DSA: + cc += fmt_binary_mpi(&pubkey->bn[DSA_P], &buf[cc], size - cc); + cc += fmt_binary_mpi(&pubkey->bn[DSA_Q], &buf[cc], size - cc); + cc += fmt_binary_mpi(&pubkey->bn[DSA_G], &buf[cc], size - cc); + cc += fmt_binary_mpi(&pubkey->bn[DSA_Y], &buf[cc], size - cc); + break; + default: + cc += fmt_binary_mpi(&pubkey->bn[ELGAMAL_P], &buf[cc], size - cc); + cc += fmt_binary_mpi(&pubkey->bn[ELGAMAL_G], &buf[cc], size - cc); + cc += fmt_binary_mpi(&pubkey->bn[ELGAMAL_Y], &buf[cc], size - cc); + break; + } + return (unsigned)cc; +} + +/* calculate the fingerprint, RFC 4880, section 12.2 */ +static int +pgpv_calc_fingerprint(pgpv_fingerprint_t *fingerprint, pgpv_pubkey_t *pubkey) +{ + digest_t fphash; + uint16_t cc; + uint8_t ch = 0x99; + uint8_t buf[8192 + 2 + 1]; + uint8_t len[2]; + + memset(&fphash, 0x0, sizeof(fphash)); + if (pubkey->version == 4) { + /* v4 keys */ + fingerprint->hashalg = digest_get_alg("sha1"); + digest_init(&fphash, (unsigned)fingerprint->hashalg); + cc = fmt_key_mpis(pubkey, buf, sizeof(buf)); + digest_update(&fphash, &ch, 1); + fmt_16(len, cc); + digest_update(&fphash, len, 2); + digest_update(&fphash, buf, cc); + fingerprint->len = digest_final(fingerprint->v, &fphash); + return 1; + } + if (ALG_IS_RSA(pubkey->keyalg)) { + /* v3 keys are RSA */ + fingerprint->hashalg = digest_get_alg("md5"); + digest_init(&fphash, (unsigned)fingerprint->hashalg); + if (pubkey->bn[RSA_N].bn && pubkey->bn[RSA_E].bn) { + cc = fmt_binary_mpi(&pubkey->bn[RSA_N], buf, sizeof(buf)); + digest_update(&fphash, &buf[2], cc - 2); + cc = fmt_binary_mpi(&pubkey->bn[RSA_E], buf, sizeof(buf)); + digest_update(&fphash, &buf[2], cc - 2); + fingerprint->len = digest_final(fingerprint->v, &fphash); + return 1; + } + } + if (pubkey->bn[RSA_N].bn) { + if ((cc = fmt_binary_mpi(&pubkey->bn[RSA_N], buf, sizeof(buf))) >= PGPV_KEYID_LEN) { + memcpy(fingerprint->v, &buf[cc - PGPV_KEYID_LEN], PGPV_KEYID_LEN); + fingerprint->len = PGPV_KEYID_LEN; + return 1; + } + } + /* exhausted all avenues, really */ + memset(fingerprint->v, 0xff, fingerprint->len = PGPV_KEYID_LEN); + return 1; +} + +/* format a fingerprint into memory */ +static size_t +fmt_fingerprint(char *s, size_t size, pgpv_fingerprint_t *fingerprint, const char *name) +{ + unsigned i; + size_t cc; + + cc = snprintf(s, size, "%s ", name); + for (i = 0 ; i < fingerprint->len ; i++) { + cc += snprintf(&s[cc], size - cc, "%02hhx%s", + fingerprint->v[i], (i % 2 == 1) ? " " : ""); + } + cc += snprintf(&s[cc], size - cc, "\n"); + return cc; +} + +/* calculate keyid from a pubkey */ +static int +pgpv_calc_keyid(pgpv_pubkey_t *key) +{ + pgpv_calc_fingerprint(&key->fingerprint, key); + memcpy(key->keyid, &key->fingerprint.v[key->fingerprint.len - PGPV_KEYID_LEN], PGPV_KEYID_LEN); + return 1; +} + +/* convert a hex string to a 64bit key id (in big endian byte order */ +static void +str_to_keyid(const char *s, uint8_t *keyid) +{ + uint64_t u64; + + u64 = (uint64_t)strtoull(s, NULL, 16); + u64 = ((u64 & 0x00000000000000FFUL) << 56) | + ((u64 & 0x000000000000FF00UL) << 40) | + ((u64 & 0x0000000000FF0000UL) << 24) | + ((u64 & 0x00000000FF000000UL) << 8) | + ((u64 & 0x000000FF00000000UL) >> 8) | + ((u64 & 0x0000FF0000000000UL) >> 24) | + ((u64 & 0x00FF000000000000UL) >> 40) | + ((u64 & 0xFF00000000000000UL) >> 56); + memcpy(keyid, &u64, PGPV_KEYID_LEN); +} + +#define PKT_ALWAYS_ON 0x80 +#define PKT_NEWFMT_MASK 0x40 +#define PKT_NEWFMT_TAG_MASK 0x3f +#define PKT_OLDFMT_TAG_MASK 0x3c + +#define SUBPKT_CRITICAL_MASK 0x80 +#define SUBPKT_TAG_MASK 0x7f + +#define SUBPKT_SIG_BIRTH 2 +#define SUBPKT_SIG_EXPIRY 3 +#define SUBPKT_EXPORT_CERT 4 +#define SUBPKT_TRUST_SIG 5 +#define SUBPKT_REGEXP 6 +#define SUBPKT_REVOCABLE 7 +#define SUBPKT_KEY_EXPIRY 9 +#define SUBPKT_BWD_COMPAT 10 +#define SUBPKT_PREF_SYMMETRIC_ALG 11 +#define SUBPKT_REVOCATION_KEY 12 +#define SUBPKT_ISSUER 16 +#define SUBPKT_NOTATION 20 +#define SUBPKT_PREF_HASH_ALG 21 +#define SUBPKT_PREF_COMPRESS_ALG 22 +#define SUBPKT_KEY_SERVER_PREFS 23 +#define SUBPKT_PREF_KEY_SERVER 24 +#define SUBPKT_PRIMARY_USER_ID 25 +#define SUBPKT_POLICY_URI 26 +#define SUBPKT_KEY_FLAGS 27 +#define SUBPKT_SIGNER_ID 28 +#define SUBPKT_REVOCATION_REASON 29 +#define SUBPKT_FEATURES 30 +#define SUBPKT_SIGNATURE_TARGET 31 +#define SUBPKT_EMBEDDED_SIGNATURE 32 + +#define UNCOMPRESSED 0 +#define ZIP_COMPRESSION 1 +#define ZLIB_COMPRESSION 2 +#define BZIP2_COMPRESSION 3 + +/* get a 16 bit integer, in host order */ +static uint16_t +get_16(uint8_t *p) +{ + uint16_t u16; + + memcpy(&u16, p, sizeof(u16)); + return ntohs(u16); +} + +/* get a 32 bit integer, in host order */ +static uint32_t +get_32(uint8_t *p) +{ + uint32_t u32; + + memcpy(&u32, p, sizeof(u32)); + return ntohl(u32); +} + +#define HOURSECS (int64_t)(60 * 60) +#define DAYSECS (int64_t)(24 * 60 * 60) +#define MONSECS (int64_t)(30 * DAYSECS) +#define YEARSECS (int64_t)(365 * DAYSECS) + +/* format (human readable) time into memory */ +static size_t +fmt_time(char *s, size_t size, const char *header, int64_t n, const char *trailer, int relative) +{ + struct tm tm; + time_t elapsed; + time_t now; + time_t t; + size_t cc; + + t = (time_t)n; + now = time(NULL); + elapsed = now - t; + gmtime_r(&t, &tm); + cc = snprintf(s, size, "%s%04d-%02d-%02d", header, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + if (relative) { + cc += snprintf(&s[cc], size - cc, " (%lldy %lldm %lldd %lldh %s)", + llabs((long long)elapsed / YEARSECS), + llabs(((long long)elapsed % YEARSECS) / MONSECS), + llabs(((long long)elapsed % MONSECS) / DAYSECS), + llabs(((long long)elapsed % DAYSECS) / HOURSECS), + (now > t) ? "ago" : "ahead"); + } + cc += snprintf(&s[cc], size - cc, "%s", trailer); + return cc; +} + +/* dump key mpis to stdout */ +static void +print_key_mpis(pgpv_bignum_t *v, uint8_t keyalg) +{ + char s[8192]; + + switch(keyalg) { + case PUBKEY_RSA_ENCRYPT_OR_SIGN: + case PUBKEY_RSA_ENCRYPT: + case PUBKEY_RSA_SIGN: + fmt_mpi(s, sizeof(s), &v[RSA_N], "rsa.n", 1); + printf("%s", s); + fmt_mpi(s, sizeof(s), &v[RSA_E], "rsa.e", 1); + printf("%s", s); + break; + case PUBKEY_ELGAMAL_ENCRYPT: + fmt_mpi(s, sizeof(s), &v[ELGAMAL_P], "elgamal.p", 1); + printf("%s", s); + fmt_mpi(s, sizeof(s), &v[ELGAMAL_Y], "elgamal.y", 1); + printf("%s", s); + break; + case PUBKEY_DSA: + fmt_mpi(s, sizeof(s), &v[DSA_P], "dsa.p", 1); + printf("%s", s); + fmt_mpi(s, sizeof(s), &v[DSA_Q], "dsa.q", 1); + printf("%s", s); + fmt_mpi(s, sizeof(s), &v[DSA_G], "dsa.g", 1); + printf("%s", s); + fmt_mpi(s, sizeof(s), &v[DSA_Y], "dsa.y", 1); + printf("%s", s); + break; + default: + printf("hi, unusual keyalg %u\n", keyalg); + break; + } +} + +/* get an mpi, including 2 byte length */ +static int +get_mpi(pgpv_bignum_t *mpi, uint8_t *p, size_t pktlen, size_t *off) +{ + size_t bytes; + + mpi->bits = get_16(p); + if ((bytes = (size_t)BITS_TO_BYTES(mpi->bits)) > pktlen) { + return 0; + } + *off += sizeof(mpi->bits); + mpi->bn = BN_bin2bn(&p[sizeof(mpi->bits)], (int)bytes, NULL); + *off += bytes; + return 1; +} + +/* read mpis in signature */ +static int +read_signature_mpis(pgpv_sigpkt_t *sigpkt, uint8_t *p, size_t pktlen) +{ + size_t off; + + off = 0; + switch(sigpkt->sig.keyalg) { + case PUBKEY_RSA_ENCRYPT_OR_SIGN: + case PUBKEY_RSA_SIGN: + case PUBKEY_RSA_ENCRYPT: + if (!get_mpi(&sigpkt->sig.bn[RSA_SIG], p, pktlen, &off)) { + printf("sigpkt->version %d, rsa sig weird\n", sigpkt->sig.version); + return 0; + } + break; + case PUBKEY_DSA: + case PUBKEY_ECDSA: + case PUBKEY_ELGAMAL_ENCRYPT_OR_SIGN: /* deprecated */ + if (!get_mpi(&sigpkt->sig.bn[DSA_R], p, pktlen, &off) || + !get_mpi(&sigpkt->sig.bn[DSA_S], &p[off], pktlen, &off)) { + printf("sigpkt->version %d, dsa/elgamal sig weird\n", sigpkt->sig.version); + return 0; + } + break; + default: + printf("weird type of sig! %d\n", sigpkt->sig.keyalg); + return 0; + } + return 1; +} + +/* add the signature sub packet to the signature packet */ +static int +add_subpacket(pgpv_sigpkt_t *sigpkt, uint8_t tag, uint8_t *p, uint16_t len) +{ + pgpv_sigsubpkt_t subpkt; + + memset(&subpkt, 0x0, sizeof(subpkt)); + subpkt.s.size = len; + subpkt.critical = 0; + subpkt.tag = tag; + subpkt.s.data = p; + ARRAY_APPEND(sigpkt->subpkts, subpkt); + return 1; +} + +/* read the subpackets in the signature */ +static int +read_sig_subpackets(pgpv_sigpkt_t *sigpkt, uint8_t *p, size_t pktlen) +{ + pgpv_sigsubpkt_t subpkt; + const int is_subpkt = 0; + unsigned lenlen; + unsigned i; + uint8_t *start; + + start = p; + for (i = 0 ; (unsigned)(p - start) < sigpkt->subslen ; i++) { + memset(&subpkt, 0x0, sizeof(subpkt)); + subpkt.s.size = get_pkt_len(1, p, 0, is_subpkt); + lenlen = get_pkt_len_len(1, p, is_subpkt); + if (lenlen > pktlen) { + printf("weird lenlen %u\n", lenlen); + return 0; + } + p += lenlen; + subpkt.critical = (*p & SUBPKT_CRITICAL_MASK); + subpkt.tag = (*p & SUBPKT_TAG_MASK); + p += 1; + switch(subpkt.tag) { + case SUBPKT_SIG_BIRTH: + sigpkt->sig.birth = (int64_t)get_32(p); + break; + case SUBPKT_SIG_EXPIRY: + sigpkt->sig.expiry = (int64_t)get_32(p); + break; + case SUBPKT_KEY_EXPIRY: + sigpkt->sig.keyexpiry = (int64_t)get_32(p); + break; + case SUBPKT_ISSUER: + sigpkt->sig.signer = p; + break; + case SUBPKT_SIGNER_ID: + sigpkt->sig.signer = p; + break; + case SUBPKT_TRUST_SIG: + sigpkt->sig.trustsig = *p; + break; + case SUBPKT_REGEXP: + sigpkt->sig.regexp = (char *)(void *)p; + break; + case SUBPKT_REVOCABLE: + sigpkt->sig.revocable = *p; + break; + case SUBPKT_PREF_SYMMETRIC_ALG: + sigpkt->sig.pref_symm_alg = *p; + break; + case SUBPKT_REVOCATION_KEY: + sigpkt->sig.revoke_sensitive = (*p & 0x40); + sigpkt->sig.revoke_alg = p[1]; + sigpkt->sig.revoke_fingerprint = &p[2]; + break; + case SUBPKT_NOTATION: + sigpkt->sig.notation = *p; + break; + case SUBPKT_PREF_HASH_ALG: + sigpkt->sig.pref_hash_alg = *p; + break; + case SUBPKT_PREF_COMPRESS_ALG: + sigpkt->sig.pref_compress_alg = *p; + break; + case SUBPKT_PREF_KEY_SERVER: + sigpkt->sig.pref_key_server = (char *)(void *)p; + break; + case SUBPKT_KEY_SERVER_PREFS: + sigpkt->sig.key_server_modify = *p; + break; + case SUBPKT_KEY_FLAGS: + sigpkt->sig.type_key = *p; + break; + case SUBPKT_PRIMARY_USER_ID: + sigpkt->sig.primary_userid = *p; + break; + case SUBPKT_POLICY_URI: + sigpkt->sig.policy = (char *)(void *)p; + break; + case SUBPKT_FEATURES: + sigpkt->sig.features = (char *)(void *)p; + break; + case SUBPKT_REVOCATION_REASON: + sigpkt->sig.revoked = *p++ + 1; + sigpkt->sig.why_revoked = (char *)(void *)p; + break; + default: + printf("Ignoring unusual/reserved signature subpacket %d\n", subpkt.tag); + break; + } + subpkt.s.data = p; + p += subpkt.s.size - 1; + ARRAY_APPEND(sigpkt->subpkts, subpkt); + } + return 1; +} + +/* parse signature packet */ +static int +read_sigpkt(pgpv_t *pgp, uint8_t mement, pgpv_sigpkt_t *sigpkt, uint8_t *p, size_t pktlen) +{ + unsigned lenlen; + uint8_t *base; + + make_ref(pgp, mement, &sigpkt->sig.hashstart); + base = p; + switch(sigpkt->sig.version = *p++) { + case 2: + case 3: + if ((lenlen = *p++) != 5) { + printf("read_sigpkt: hashed length not 5\n"); + return 0; + } + sigpkt->sig.hashlen = lenlen; + /* put birthtime into a subpacket */ + sigpkt->sig.type = *p++; + add_subpacket(sigpkt, SUBPKT_SIG_BIRTH, p, sizeof(uint32_t)); + sigpkt->sig.birth = (int64_t)get_32(p); + p += sizeof(uint32_t); + sigpkt->sig.signer = p; + add_subpacket(sigpkt, SUBPKT_SIGNER_ID, p, PGPV_KEYID_LEN); + p += PGPV_KEYID_LEN; + sigpkt->sig.keyalg = *p++; + sigpkt->sig.hashalg = *p++; + sigpkt->sig.hash2 = p; + if (!read_signature_mpis(sigpkt, sigpkt->sig.mpi = p + 2, pktlen)) { + printf("read_sigpkt: can't read sigs v3\n"); + return 0; + } + break; + case 4: + sigpkt->sig.type = *p++; + sigpkt->sig.keyalg = *p++; + sigpkt->sig.hashalg = *p++; + sigpkt->subslen = get_16(p); + p += sizeof(sigpkt->subslen); + if (!read_sig_subpackets(sigpkt, p, pktlen)) { + printf("read_sigpkt: can't read sig subpackets, v4\n"); + return 0; + } + if (!sigpkt->sig.signer) { + sigpkt->sig.signer = get_ref(&sigpkt->sig.hashstart) + 16; + } + p += sigpkt->subslen; + sigpkt->sig.hashlen = (unsigned)(p - base); + sigpkt->unhashlen = get_16(p); + p += sizeof(sigpkt->unhashlen) + sigpkt->unhashlen; + sigpkt->sig.hash2 = p; + if (!read_signature_mpis(sigpkt, sigpkt->sig.mpi = p + 2, pktlen)) { + printf("read_sigpkt: can't read sigs, v4\n"); + return 0; + } + break; + default: + printf("read_sigpkt: unusual signature version (%u)\n", sigpkt->sig.version); + break; + } + return 1; +} + + +/* this parses compressed data, decompresses it, and calls the parser again */ +static int +read_compressed(pgpv_t *pgp, pgpv_compress_t *compressed, uint8_t *p, size_t len) +{ + pgpv_mem_t *unzmem; + bz_stream bz; + z_stream z; + int ok; + + compressed->compalg = *p; + compressed->s.size = len; + if ((compressed->s.data = calloc(1, len)) == NULL) { + printf("read_compressed: can't allocate %zu length\n", len); + return 0; + } + switch(compressed->compalg) { + case UNCOMPRESSED: + printf("not implemented %d compression yet\n", compressed->compalg); + return 0; + default: + break; + } + ARRAY_EXPAND(pgp->areas); + ARRAY_COUNT(pgp->areas) += 1; + unzmem = &ARRAY_LAST(pgp->areas); + unzmem->size = len * 10; + unzmem->dealloc = FREE_MEM; + if ((unzmem->mem = calloc(1, unzmem->size)) == NULL) { + printf("read_compressed: calloc failed!\n"); + return 0; + } + switch(compressed->compalg) { + case ZIP_COMPRESSION: + case ZLIB_COMPRESSION: + memset(&z, 0x0, sizeof(z)); + z.next_in = p + 1; + z.avail_in = (unsigned)(len - 1); + z.total_in = (unsigned)(len - 1); + z.next_out = unzmem->mem; + z.avail_out = (unsigned)unzmem->size; + z.total_out = (unsigned)unzmem->size; + break; + case BZIP2_COMPRESSION: + memset(&bz, 0x0, sizeof(bz)); + bz.avail_in = (unsigned)(len - 1); + bz.next_in = (char *)(void *)p + 1; + bz.next_out = (char *)(void *)unzmem->mem; + bz.avail_out = (unsigned)unzmem->size; + break; + } + switch(compressed->compalg) { + case ZIP_COMPRESSION: + ok = (inflateInit2(&z, -15) == Z_OK); + break; + case ZLIB_COMPRESSION: + ok = (inflateInit(&z) == Z_OK); + break; + case BZIP2_COMPRESSION: + ok = (BZ2_bzDecompressInit(&bz, 1, 0) == BZ_OK); + break; + } + if (!ok) { + printf("read_compressed: initialisation failed!\n"); + return 0; + } + switch(compressed->compalg) { + case ZIP_COMPRESSION: + case ZLIB_COMPRESSION: + ok = (inflate(&z, Z_FINISH) == Z_STREAM_END); + unzmem->size = z.total_out; + break; + case BZIP2_COMPRESSION: + ok = (BZ2_bzDecompress(&bz) == BZ_STREAM_END); + unzmem->size = ((size_t)bz.total_out_hi32 << 32) | bz.total_out_lo32; + break; + } + if (!ok) { + printf("read_compressed: inflate failed!\n"); + return 0; + } + return 1; +} + +/* parse one pass signature packet */ +static int +read_onepass_sig(pgpv_onepass_t *onepasspkt, uint8_t *mem) +{ + onepasspkt->version = mem[0]; + onepasspkt->type = mem[1]; + onepasspkt->hashalg = mem[2]; + onepasspkt->keyalg = mem[3]; + memcpy(onepasspkt->keyid, &mem[4], sizeof(onepasspkt->keyid)); + onepasspkt->nested = mem[12]; + return 1; +} + +/* parse public key packet */ +static int +read_pubkey(pgpv_pubkey_t *pubkey, uint8_t *mem, size_t pktlen, int pbn) +{ + size_t off; + + off = 0; + pubkey->version = mem[off++]; + pubkey->birth = get_32(&mem[off]); + off += 4; + if (pubkey->version == 2 || pubkey->version == 3) { + pubkey->expiry = get_16(&mem[off]) * DAYSECS; + off += 2; + } + if ((pubkey->keyalg = mem[off++]) == 0) { + pubkey->keyalg = PUBKEY_RSA_ENCRYPT_OR_SIGN; + printf("got unusual pubkey keyalg %u\n", mem[off - 1]); + } + switch(pubkey->keyalg) { + case PUBKEY_RSA_ENCRYPT_OR_SIGN: + case PUBKEY_RSA_ENCRYPT: + case PUBKEY_RSA_SIGN: + if (!get_mpi(&pubkey->bn[RSA_N], &mem[off], pktlen, &off) || + !get_mpi(&pubkey->bn[RSA_E], &mem[off], pktlen, &off)) { + return 0; + } + break; + case PUBKEY_ELGAMAL_ENCRYPT: + case PUBKEY_ELGAMAL_ENCRYPT_OR_SIGN: + if (!get_mpi(&pubkey->bn[ELGAMAL_P], &mem[off], pktlen, &off) || + !get_mpi(&pubkey->bn[ELGAMAL_Y], &mem[off], pktlen, &off)) { + return 0; + } + break; + case PUBKEY_DSA: + if (!get_mpi(&pubkey->bn[DSA_P], &mem[off], pktlen, &off) || + !get_mpi(&pubkey->bn[DSA_Q], &mem[off], pktlen, &off) || + !get_mpi(&pubkey->bn[DSA_G], &mem[off], pktlen, &off) || + !get_mpi(&pubkey->bn[DSA_Y], &mem[off], pktlen, &off)) { + return 0; + } + break; + default: + printf("hi, different type of pubkey here %u\n", pubkey->keyalg); + break; + } + if (pbn) { + print_key_mpis(pubkey->bn, pubkey->keyalg); + } + return 1; +} + +/* parse a user attribute */ +static int +read_userattr(pgpv_userattr_t *userattr, uint8_t *p, size_t pktlen) +{ + pgpv_string_t subattr; + const int is_subpkt = 0; + const int indian = 1; + unsigned lenlen; + uint16_t imagelen; + size_t cc; + + userattr->len = pktlen; + for (cc = 0 ; cc < pktlen ; cc += subattr.size + lenlen + 1) { + subattr.size = get_pkt_len(1, p, 0, is_subpkt); + lenlen = get_pkt_len_len(1, p, is_subpkt); + if (lenlen > pktlen) { + printf("weird lenlen %u\n", lenlen); + return 0; + } + p += lenlen; + if (*p++ != 1) { + printf("image type (%u) != 1. weird packet\n", *(p - 1)); + } + memcpy(&imagelen, p, sizeof(imagelen)); + if (!*(const char *)(const void *)&indian) { + /* big endian - byteswap length */ + imagelen = (((unsigned)imagelen & 0xff) << 8) | (((unsigned)imagelen >> 8) & 0xff); + } + subattr.data = p + 3; + p += subattr.size; + ARRAY_APPEND(userattr->subattrs, subattr); + } + return 1; +} + +#define LITDATA_BINARY 'b' +#define LITDATA_TEXT 't' +#define LITDATA_UTF8 'u' + +/* parse literal packet */ +static int +read_litdata(pgpv_t *pgp, pgpv_litdata_t *litdata, uint8_t *p, size_t size) +{ + size_t cc; + + cc = 0; + switch(litdata->format = p[cc++]) { + case LITDATA_BINARY: + case LITDATA_TEXT: + case LITDATA_UTF8: + litdata->namelen = 0; + break; + default: + printf("weird litdata format %u\n", litdata->format); + break; + } + litdata->namelen = p[cc++]; + litdata->filename = &p[cc]; + cc += litdata->namelen; + litdata->secs = get_32(&p[cc]); + cc += 4; + litdata->s.data = &p[cc]; + litdata->len = litdata->s.size = size - cc; + litdata->mem = ARRAY_COUNT(pgp->areas) - 1; + litdata->offset = cc; + return 1; +} + +/* parse a single packet */ +static int +read_pkt(pgpv_t *pgp, pgpv_mem_t *mem) +{ + const int isprimary = 1; + pgpv_pkt_t pkt; + pgpv_mem_t *newmem; + unsigned lenlen; + uint8_t ispartial; + size_t size; + + memset(&pkt, 0x0, sizeof(pkt)); + pkt.tag = mem->mem[mem->cc++]; + if (!(pkt.tag & PKT_ALWAYS_ON)) { + printf("BAD PACKET - bit 7 not 1, offset %zu!\n", mem->cc - 1); + } + pkt.newfmt = (pkt.tag & PKT_NEWFMT_MASK); + pkt.tag = (pkt.newfmt) ? + (pkt.tag & PKT_NEWFMT_TAG_MASK) : + (((unsigned)pkt.tag & PKT_OLDFMT_TAG_MASK) >> 2); + ispartial = (pkt.newfmt && IS_PARTIAL(mem->mem[mem->cc])); + pkt.s.size = get_pkt_len(pkt.newfmt, &mem->mem[mem->cc], mem->size - mem->cc, isprimary); + lenlen = get_pkt_len_len(pkt.newfmt, &mem->mem[mem->cc], isprimary); + pkt.offset = mem->cc; + mem->cc += lenlen; + pkt.mement = (uint8_t)(mem - ARRAY_ARRAY(pgp->areas)); + pkt.s.data = &mem->mem[mem->cc]; + if (strchr(mem->allowed, pkt.tag) == NULL) { + printf("packet %d not allowed for operation %s\n", pkt.tag, pgp->op); + return 0; + } + size = pkt.s.size; + if (ispartial) { + pkt.s.size = fixup_partials(pgp, &mem->mem[mem->cc - lenlen], pkt.s.size, mem->size, &size); + newmem = &ARRAY_LAST(pgp->areas); + pkt.mement = (uint8_t)(newmem - ARRAY_ARRAY(pgp->areas)); + pkt.s.data = newmem->mem; + size -= 1; + } + switch(pkt.tag) { + case SIGNATURE_PKT: + if (!read_sigpkt(pgp, pkt.mement, &pkt.u.sigpkt, pkt.s.data, pkt.s.size)) { + return 0; + } + break; + case ONEPASS_SIGNATURE_PKT: + read_onepass_sig(&pkt.u.onepass, pkt.s.data); + break; + case PUBKEY_PKT: + case PUB_SUBKEY_PKT: + break; + case LITDATA_PKT: + read_litdata(pgp, &pkt.u.litdata, pkt.s.data, pkt.s.size); + break; + case TRUST_PKT: + pkt.u.trust.level = pkt.s.data[0]; + pkt.u.trust.amount = pkt.s.data[1]; + break; + case USERID_PKT: + pkt.u.userid.size = pkt.s.size; + pkt.u.userid.data = pkt.s.data; + break; + case COMPRESSED_DATA_PKT: + read_compressed(pgp, &pkt.u.compressed, pkt.s.data, pkt.s.size); + ARRAY_APPEND(pgp->pkts, pkt); + read_all_packets(pgp, &ARRAY_LAST(pgp->areas), pgp->op); + break; + case USER_ATTRIBUTE_PKT: + read_userattr(&pkt.u.userattr, pkt.s.data, pkt.s.size); + break; + default: + printf("hi, need to implement %d, offset %zu\n", pkt.tag, mem->cc); + break; + } + mem->cc += size; + if (pkt.tag != COMPRESSED_DATA_PKT) { + /* compressed was added earlier to preserve pkt ordering */ + ARRAY_APPEND(pgp->pkts, pkt); + } + return 1; +} + +/* checks the tag type of a packet */ +static int +pkt_is(pgpv_t *pgp, int wanted) +{ + return (ARRAY_ELEMENT(pgp->pkts, pgp->pkt).tag == wanted); +} + +/* checks the packet is a signature packet, and the signature type is the expected one */ +static int +pkt_sigtype_is(pgpv_t *pgp, int wanted) +{ + if (!pkt_is(pgp, SIGNATURE_PKT)) { + return 0; + } + return (ARRAY_ELEMENT(pgp->pkts, pgp->pkt).u.sigpkt.sig.type == wanted); +} + +/* check for expected type of packet, and move to the next */ +static int +pkt_accept(pgpv_t *pgp, int expected) +{ + int got; + + if ((got = ARRAY_ELEMENT(pgp->pkts, pgp->pkt).tag) == expected) { + pgp->pkt += 1; + return 1; + } + printf("problem at token %zu, expcted %d, got %d\n", pgp->pkt, expected, got); + return 0; +} + +/* recognise signature (and trust) packet */ +static int +recog_signature(pgpv_t *pgp, pgpv_signature_t *signature) +{ + if (!pkt_is(pgp, SIGNATURE_PKT)) { + printf("recog_signature: not a signature packet\n"); + return 0; + } + memcpy(signature, &ARRAY_ELEMENT(pgp->pkts, pgp->pkt).u.sigpkt.sig, sizeof(*signature)); + pgp->pkt += 1; + if (pkt_is(pgp, TRUST_PKT)) { + pkt_accept(pgp, TRUST_PKT); + } + return 1; +} + +/* recognise user id packet */ +static int +recog_userid(pgpv_t *pgp, pgpv_signed_userid_t *userid) +{ + pgpv_signature_t signature; + pgpv_pkt_t *pkt; + + memset(userid, 0x0, sizeof(*userid)); + if (!pkt_is(pgp, USERID_PKT)) { + printf("recog_userid: not %d\n", USERID_PKT); + return 0; + } + pkt = &ARRAY_ELEMENT(pgp->pkts, pgp->pkt); + userid->userid.size = pkt->s.size; + userid->userid.data = pkt->s.data; + pgp->pkt += 1; + while (pkt_is(pgp, SIGNATURE_PKT)) { + if (!recog_signature(pgp, &signature)) { + printf("recog_userid: can't recognise signature/trust\n"); + return 0; + } + ARRAY_APPEND(userid->sigs, signature); + if (signature.primary_userid) { + userid->primary_userid = signature.primary_userid; + } + if (signature.revoked) { + userid->revoked = signature.revoked; + } + } + return 1; +} + +/* recognise user attributes packet */ +static int +recog_userattr(pgpv_t *pgp, pgpv_signed_userattr_t *userattr) +{ + pgpv_signature_t signature; + + memset(userattr, 0x0, sizeof(*userattr)); + if (!pkt_is(pgp, USER_ATTRIBUTE_PKT)) { + printf("recog_userattr: not %d\n", USER_ATTRIBUTE_PKT); + return 0; + } + userattr->userattr = ARRAY_ELEMENT(pgp->pkts, pgp->pkt).u.userattr; + pgp->pkt += 1; + while (pkt_is(pgp, SIGNATURE_PKT)) { + if (!recog_signature(pgp, &signature)) { + printf("recog_userattr: can't recognise signature/trust\n"); + return 0; + } + ARRAY_APPEND(userattr->sigs, signature); + if (signature.revoked) { + userattr->revoked = signature.revoked; + } + } + return 1; +} + +/* recognise a sub key */ +static int +recog_subkey(pgpv_t *pgp, pgpv_signed_subkey_t *subkey) +{ + pgpv_signature_t signature; + pgpv_pkt_t *pkt; + + pkt = &ARRAY_ELEMENT(pgp->pkts, pgp->pkt); + memset(subkey, 0x0, sizeof(*subkey)); + read_pubkey(&subkey->subkey, pkt->s.data, pkt->s.size, 0); + pgp->pkt += 1; + if (pkt_sigtype_is(pgp, SIGTYPE_KEY_REVOCATION) || + pkt_sigtype_is(pgp, SIGTYPE_SUBKEY_REVOCATION) || + pkt_sigtype_is(pgp, SIGTYPE_CERT_REVOCATION)) { + recog_signature(pgp, &signature); + subkey->revoc_self_sig = signature; + } + do { + if (!pkt_is(pgp, SIGNATURE_PKT)) { + printf("recog_subkey: not signature packet at %zu\n", pgp->pkt); + return 0; + } + if (!recog_signature(pgp, &signature)) { + printf("recog_subkey: bad signature/trust at %zu\n", pgp->pkt); + return 0; + } + ARRAY_APPEND(subkey->sigs, signature); + if (signature.keyexpiry) { + /* XXX - check it's a good key expiry */ + subkey->subkey.expiry = signature.keyexpiry; + } + } while (pkt_is(pgp, SIGNATURE_PKT)); + return 1; +} + +/* use a sparse map for the text strings here to save space */ +static const char *keyalgs[] = { + "[Unknown]", + "RSA (Encrypt or Sign)", + "RSA (Encrypt Only)", + "RSA (Sign Only)", + "Elgamal (Encrypt Only)", + "DSA", + "Elliptic Curve", + "ECDSA", + "Elgamal (Encrypt or Sign)" +}; + +#define MAX_KEYALG 21 + +static const char *keyalgmap = "\0\01\02\03\0\0\0\0\0\0\0\0\0\0\0\0\04\05\06\07\010\011"; + +/* return human readable name for key algorithm */ +static const char * +fmtkeyalg(uint8_t keyalg) +{ + return keyalgs[(uint8_t)keyalgmap[(keyalg >= MAX_KEYALG) ? 0 : keyalg]]; +} + +/* return the number of bits in the public key */ +static unsigned +numkeybits(const pgpv_pubkey_t *pubkey) +{ + switch(pubkey->keyalg) { + case PUBKEY_RSA_ENCRYPT_OR_SIGN: + case PUBKEY_RSA_ENCRYPT: + case PUBKEY_RSA_SIGN: + return pubkey->bn[RSA_N].bits; + case PUBKEY_DSA: + case PUBKEY_ECDSA: + return BITS_TO_BYTES(pubkey->bn[DSA_Q].bits) * 64; + case PUBKEY_ELGAMAL_ENCRYPT: + case PUBKEY_ELGAMAL_ENCRYPT_OR_SIGN: + return pubkey->bn[ELGAMAL_P].bits; + default: + return 0; + } +} + +/* print a public key */ +static size_t +fmt_pubkey(char *s, size_t size, pgpv_pubkey_t *pubkey, const char *leader) +{ + size_t cc; + + cc = snprintf(s, size, "%s %u/%s ", leader, numkeybits(pubkey), fmtkeyalg(pubkey->keyalg)); + cc += fmt_binary(&s[cc], size - cc, pubkey->keyid, PGPV_KEYID_LEN); + cc += fmt_time(&s[cc], size - cc, " ", pubkey->birth, "", 0); + if (pubkey->expiry) { + cc += fmt_time(&s[cc], size - cc, " [Expiry ", pubkey->birth + pubkey->expiry, "]", 0); + } + cc += snprintf(&s[cc], size - cc, "\n"); + cc += fmt_fingerprint(&s[cc], size - cc, &pubkey->fingerprint, "fingerprint: "); + return cc; +} + +/* we add 1 to revocation value to denote compromised */ +#define COMPROMISED (0x02 + 1) + +/* format a userid - used to order the userids when formatting */ +static size_t +fmt_userid(char *s, size_t size, pgpv_primarykey_t *primary, uint8_t u) +{ + pgpv_signed_userid_t *userid; + + userid = &ARRAY_ELEMENT(primary->signed_userids, u); + return snprintf(s, size, "uid %.*s%s\n", + (int)userid->userid.size, userid->userid.data, + (userid->revoked == COMPROMISED) ? " [COMPROMISED AND REVOKED]" : + (userid->revoked) ? " [REVOKED]" : ""); +} + +/* print a primary key, per RFC 4880 */ +static size_t +fmt_primary(char *s, size_t size, pgpv_primarykey_t *primary) +{ + unsigned i; + size_t cc; + + cc = fmt_pubkey(s, size, &primary->primary, "signature "); + cc += fmt_userid(&s[cc], size - cc, primary, primary->primary_userid); + for (i = 0 ; i < ARRAY_COUNT(primary->signed_userids) ; i++) { + if (i != primary->primary_userid) { + cc += fmt_userid(&s[cc], size - cc, primary, i); + } + } + for (i = 0 ; i < ARRAY_COUNT(primary->signed_subkeys) ; i++) { + cc += fmt_pubkey(&s[cc], size - cc, &ARRAY_ELEMENT(primary->signed_subkeys, i).subkey, "encryption"); + } + cc += snprintf(&s[cc], size - cc, "\n"); + return cc; +} + + +/* check the padding on the signature */ +static int +rsa_padding_check_none(uint8_t *to, int tlen, const uint8_t *from, int flen, int num) +{ + USE_ARG(num); + if (flen > tlen) { + printf("from length larger than to length\n"); + return -1; + } + (void) memset(to, 0x0, tlen - flen); + (void) memcpy(to + tlen - flen, from, flen); + return tlen; +} + +#define RSA_MAX_MODULUS_BITS 16384 +#define RSA_SMALL_MODULUS_BITS 3072 +#define RSA_MAX_PUBEXP_BITS 64 /* exponent limit enforced for "large" modulus only */ + +/* check against the exponent/moudulo operation */ +static int +lowlevel_rsa_public_check(const uint8_t *encbuf, int enclen, uint8_t *dec, const rsa_pubkey_t *rsa) +{ + uint8_t *decbuf; + BIGNUM *decbn; + BIGNUM *encbn; + int decbytes; + int nbytes; + int r; + + nbytes = 0; + r = -1; + decbuf = NULL; + decbn = encbn = NULL; + if (BN_num_bits(rsa->n) > RSA_MAX_MODULUS_BITS) { + printf("rsa r modulus too large\n"); + goto err; + } + if (BN_cmp(rsa->n, rsa->e) <= 0) { + printf("rsa r bad n value\n"); + goto err; + } + if (BN_num_bits(rsa->n) > RSA_SMALL_MODULUS_BITS && + BN_num_bits(rsa->e) > RSA_MAX_PUBEXP_BITS) { + printf("rsa r bad exponent limit\n"); + goto err; + } + if ((encbn = BN_new()) == NULL || + (decbn = BN_new()) == NULL || + (decbuf = calloc(1, nbytes = BN_num_bytes(rsa->n))) == NULL) { + printf("allocation failure\n"); + goto err; + } + if (enclen > nbytes) { + printf("rsa r > mod len\n"); + goto err; + } + if (BN_bin2bn(encbuf, enclen, encbn) == NULL) { + printf("null encrypted BN\n"); + goto err; + } + if (BN_cmp(encbn, rsa->n) >= 0) { + printf("rsa r data too large for modulus\n"); + goto err; + } + if (BN_mod_exp(decbn, encbn, rsa->e, rsa->n, NULL) < 0) { + printf("BN_mod_exp < 0\n"); + goto err; + } + decbytes = BN_num_bytes(decbn); + (void) BN_bn2bin(decbn, decbuf); + if ((r = rsa_padding_check_none(dec, nbytes, decbuf, decbytes, 0)) < 0) { + printf("rsa r padding check failed\n"); + } +err: + BN_free(encbn); + BN_free(decbn); + if (decbuf != NULL) { + (void) memset(decbuf, 0x0, nbytes); + free(decbuf); + } + return r; +} + +/* verify */ +static int +rsa_public_decrypt(int enclen, const unsigned char *enc, unsigned char *dec, RSA *rsa, int padding) +{ + rsa_pubkey_t pub; + int ret; + + if (enc == NULL || dec == NULL || rsa == NULL) { + return 0; + } + USE_ARG(padding); + (void) memset(&pub, 0x0, sizeof(pub)); + pub.n = BN_dup(rsa->n); + pub.e = BN_dup(rsa->e); + ret = lowlevel_rsa_public_check(enc, enclen, dec, &pub); + BN_free(pub.n); + BN_free(pub.e); + return ret; +} + +#define SUBKEY_LEN(x) (80 + 80) +#define SIG_LEN 80 +#define UID_LEN 80 + +/* return worst case number of bytes needed to format a primary key */ +static size_t +estimate_primarykey_size(pgpv_primarykey_t *primary) +{ + size_t cc; + + cc = SUBKEY_LEN("signature") + + (ARRAY_COUNT(primary->signed_userids) * UID_LEN) + + (ARRAY_COUNT(primary->signed_subkeys) * SUBKEY_LEN("encrypt uids")); + return cc; +} + +/* use public decrypt to verify a signature */ +static int +pgpv_rsa_public_decrypt(uint8_t *out, const uint8_t *in, size_t length, const pgpv_pubkey_t *pubkey) +{ + RSA *orsa; + int n; + + if ((orsa = calloc(1, sizeof(*orsa))) == NULL) { + return 0; + } + orsa->n = pubkey->bn[RSA_N].bn; + orsa->e = pubkey->bn[RSA_E].bn; + n = rsa_public_decrypt((int)length, in, out, orsa, RSA_NO_PADDING); + orsa->n = orsa->e = NULL; + free(orsa); + return n; +} + +/* verify rsa signature */ +static int +rsa_verify(uint8_t *calculated, unsigned calclen, uint8_t hashalg, pgpv_bignum_t *bn, pgpv_pubkey_t *pubkey) +{ + unsigned prefixlen; + unsigned decryptc; + unsigned i; + uint8_t decrypted[8192]; + uint8_t sigbn[8192]; + uint8_t prefix[64]; + size_t keysize; + + keysize = BITS_TO_BYTES(pubkey->bn[RSA_N].bits); + BN_bn2bin(bn[RSA_SIG].bn, sigbn); + decryptc = pgpv_rsa_public_decrypt(decrypted, sigbn, BITS_TO_BYTES(bn[RSA_SIG].bits), pubkey); + if (decryptc != keysize || (decrypted[0] != 0 || decrypted[1] != 1)) { + return 0; + } + if ((prefixlen = digest_get_prefix((unsigned)hashalg, prefix, sizeof(prefix))) == 0) { + printf("rsa_verify: unknown hash algorithm: %d\n", hashalg); + return 0; + } + for (i = 2 ; i < keysize - prefixlen - calclen - 1 ; i++) { + if (decrypted[i] != 0xff) { + return 0; + } + } + if (decrypted[i++] != 0x0) { + return 0; + } + if (memcmp(&decrypted[i], prefix, prefixlen) != 0) { + printf("rsa_verify: wrong hash algorithm\n"); + return 0; + } + return memcmp(&decrypted[i + prefixlen], calculated, calclen) == 0; +} + +/* return 1 if bn <= 0 */ +static int +bignum_is_bad(BIGNUM *bn) +{ + return BN_is_zero(bn) || BN_is_negative(bn); +} + +#define BAD_BIGNUM(s, k) \ + (bignum_is_bad((s)->bn) || BN_cmp((s)->bn, (k)->bn) >= 0) + +#ifndef DSA_MAX_MODULUS_BITS +#define DSA_MAX_MODULUS_BITS 10000 +#endif + +/* verify DSA signature */ +static int +verify_dsa_sig(uint8_t *calculated, unsigned calclen, pgpv_bignum_t *sig, pgpv_pubkey_t *pubkey) +{ + unsigned qbits; + uint8_t calcnum[128]; + uint8_t signum[128]; + BIGNUM *M; + BIGNUM *W; + BIGNUM *t1; + int ret; + + if (pubkey[DSA_P].bn == NULL || pubkey[DSA_Q].bn == NULL || pubkey[DSA_G].bn == NULL) { + return 0; + } + M = W = t1 = NULL; + qbits = pubkey->bn[DSA_Q].bits; + switch(qbits) { + case 160: + case 224: + case 256: + break; + default: + printf("dsa: bad # of Q bits\n"); + return 0; + } + if (pubkey->bn[DSA_P].bits > DSA_MAX_MODULUS_BITS) { + printf("dsa: p too large\n"); + return 0; + } + if (calclen > SHA256_DIGEST_LENGTH) { + printf("dsa: digest too long\n"); + return 0; + } + ret = 0; + if ((M = BN_new()) == NULL || (W = BN_new()) == NULL || (t1 = BN_new()) == NULL || + BAD_BIGNUM(&sig[DSA_R], &pubkey->bn[DSA_Q]) || + BAD_BIGNUM(&sig[DSA_S], &pubkey->bn[DSA_Q]) || + BN_mod_inverse(W, sig[DSA_S].bn, pubkey->bn[DSA_Q].bn, NULL) == NULL) { + goto done; + } + if (calclen > qbits / 8) { + calclen = qbits / 8; + } + if (BN_bin2bn(calculated, (int)calclen, M) == NULL || + !BN_mod_mul(M, M, W, pubkey->bn[DSA_Q].bn, NULL) || + !BN_mod_mul(W, sig[DSA_R].bn, W, pubkey->bn[DSA_Q].bn, NULL) || + !BN_mod_exp(t1, pubkey->bn[DSA_G].bn, M, pubkey->bn[DSA_P].bn, NULL) || + !BN_mod_exp(W, pubkey->bn[DSA_Y].bn, W, pubkey->bn[DSA_P].bn, NULL) || + !BN_mod_mul(t1, t1, W, pubkey->bn[DSA_P].bn, NULL) || + !BN_div(NULL, t1, t1, pubkey->bn[DSA_Q].bn, NULL)) { + goto done; + } + /* only compare the first q bits */ + BN_bn2bin(t1, calcnum); + BN_bn2bin(sig[DSA_R].bn, signum); + ret = memcmp(calcnum, signum, BITS_TO_BYTES(qbits)) == 0; +done: + if (M) { + BN_free(M); + } + if (W) { + BN_free(W); + } + if (t1) { + BN_free(t1); + } + return ret; +} + +#define TIME_SNPRINTF(_cc, _buf, _size, _fmt, _val) do { \ + time_t _t; \ + char *_s; \ + \ + _t = _val; \ + _s = ctime(&_t); \ + _cc += snprintf(_buf, _size, _fmt, _s); \ +} while(/*CONSTCOND*/0) + +/* check dates on signature and key are valid */ +static size_t +valid_dates(pgpv_signature_t *signature, pgpv_pubkey_t *pubkey, char *buf, size_t size) +{ + time_t now; + time_t t; + size_t cc; + + cc = 0; + if (signature->birth < pubkey->birth) { + TIME_SNPRINTF(cc, buf, size, "Signature time (%.24s) was before pubkey creation ", signature->birth); + TIME_SNPRINTF(cc, &buf[cc], size - cc, "(%s)\n", pubkey->birth); + return cc; + } + now = time(NULL); + if (signature->expiry != 0) { + if ((t = signature->birth + signature->expiry) < now) { + TIME_SNPRINTF(cc, buf, size, "Signature expired on %.24s\n", t); + return cc; + } + } + if (now < signature->birth) { + TIME_SNPRINTF(cc, buf, size, "Signature not valid before %.24s\n", signature->birth); + return cc; + } + return 0; +} + +/* check if the signing key has expired */ +static int +key_expired(pgpv_pubkey_t *pubkey, char *buf, size_t size) +{ + time_t now; + time_t t; + size_t cc; + + now = time(NULL); + cc = 0; + if (pubkey->expiry != 0) { + if ((t = pubkey->birth + pubkey->expiry) < now) { + TIME_SNPRINTF(cc, buf, size, "Pubkey expired on %.24s\n", t); + return (int)cc; + } + } + if (now < pubkey->birth) { + TIME_SNPRINTF(cc, buf, size, "Pubkey not valid before %.24s\n", pubkey->birth); + return (int)cc; + } + return 0; +} + +/* find the leading onepass packet */ +static size_t +find_onepass(pgpv_cursor_t *cursor, size_t datastart) +{ + size_t pkt; + + for (pkt = datastart ; pkt < ARRAY_COUNT(cursor->pgp->pkts) ; pkt++) { + if (ARRAY_ELEMENT(cursor->pgp->pkts, pkt).tag == ONEPASS_SIGNATURE_PKT) { + return pkt + 1; + } + } + snprintf(cursor->why, sizeof(cursor->why), "No signature to verify"); + return 0; +} + +static const char *armor_begins[] = { + "-----BEGIN PGP SIGNED MESSAGE-----\n", + "-----BEGIN PGP MESSAGE-----\n", + NULL +}; + +/* return non-zero if the buf introduces an armored message */ +static int +is_armored(const char *buf, size_t size) +{ + const char **arm; + const char *nl; + size_t n; + + if ((nl = memchr(buf, '\n', size)) == NULL) { + return 0; + } + n = (size_t)(nl - buf); + for (arm = armor_begins ; *arm ; arm++) { + if (strncmp(buf, *arm, n) == 0) { + return 1; + } + } + return 0; +} + +#define SIGSTART "-----BEGIN PGP SIGNATURE-----\n" +#define SIGEND "-----END PGP SIGNATURE-----\n" + +/* for ascii armor, we don't get a onepass packet - make one */ +static const char *cons_onepass = "\304\015\003\0\0\0\0\377\377\377\377\377\377\377\377\1"; + +/* read ascii armor */ +static int +read_ascii_armor(pgpv_cursor_t *cursor, pgpv_mem_t *mem, const char *filename) +{ + pgpv_onepass_t *onepass; + pgpv_sigpkt_t *sigpkt; + pgpv_pkt_t litdata; + uint8_t binsig[8192]; + uint8_t *datastart; + uint8_t *sigend; + uint8_t *p; + size_t binsigsize; + + /* cons up litdata pkt */ + memset(&litdata, 0x0, sizeof(litdata)); + litdata.u.litdata.mem = ARRAY_COUNT(cursor->pgp->areas) - 1; + p = mem->mem; + /* jump over signed message line */ + if ((p = memmem(mem->mem, mem->size, "\n\n", 2)) == NULL) { + snprintf(cursor->why, sizeof(cursor->why), "malformed armor at offset 0"); + return 0; + } + p += 2; + litdata.tag = LITDATA_PKT; + litdata.s.data = p; + litdata.u.litdata.offset = (size_t)(p - mem->mem); + litdata.u.litdata.filename = (uint8_t *)strdup(filename); + if ((p = memmem(datastart = p, mem->size - litdata.offset, SIGSTART, strlen(SIGSTART))) == NULL) { + snprintf(cursor->why, sizeof(cursor->why), + "malformed armor - no sig - at %zu", (size_t)(p - mem->mem)); + return 0; + } + litdata.u.litdata.len = litdata.s.size = (size_t)(p - datastart); + p += strlen(SIGSTART); + if ((p = memmem(p, mem->size, "\n\n", 2)) == NULL) { + snprintf(cursor->why, sizeof(cursor->why), + "malformed armed signature at %zu", (size_t)(p - mem->mem)); + return 0; + } + p += 2; + sigend = memmem(p, mem->size, SIGEND, strlen(SIGEND)); + binsigsize = b64decode((char *)p, (size_t)(sigend - p), binsig, sizeof(binsig)); + + read_binary_memory(cursor->pgp, "signature", cons_onepass, 15); + ARRAY_APPEND(cursor->pgp->pkts, litdata); + read_binary_memory(cursor->pgp, "signature", binsig, binsigsize - 3); + /* XXX - hardwired - 3 is format and length */ + + /* fix up packets in the packet array now we have them there */ + onepass = &ARRAY_ELEMENT(cursor->pgp->pkts, ARRAY_COUNT(cursor->pgp->pkts) - 1 - 2).u.onepass; + sigpkt = &ARRAY_LAST(cursor->pgp->pkts).u.sigpkt; + memcpy(onepass->keyid, sigpkt->sig.signer, sizeof(onepass->keyid)); + onepass->hashalg = sigpkt->sig.hashalg; + onepass->keyalg = sigpkt->sig.keyalg; + return 1; +} + +/* read ascii armor from a file */ +static int +read_ascii_armor_file(pgpv_cursor_t *cursor, const char *filename) +{ + /* cons up litdata pkt */ + read_file(cursor->pgp, filename); + return read_ascii_armor(cursor, &ARRAY_LAST(cursor->pgp->areas), filename); +} + +/* read ascii armor from memory */ +static int +read_ascii_armor_memory(pgpv_cursor_t *cursor, const void *p, size_t size) +{ + pgpv_mem_t *mem; + + /* cons up litdata pkt */ + ARRAY_EXPAND(cursor->pgp->areas); + ARRAY_COUNT(cursor->pgp->areas) += 1; + mem = &ARRAY_LAST(cursor->pgp->areas); + memset(mem, 0x0, sizeof(*mem)); + mem->size = size; + mem->mem = __UNCONST(p); + mem->dealloc = 0; + return read_ascii_armor(cursor, mem, "[stdin]"); +} + +/* set up the data to verify */ +static int +setup_data(pgpv_cursor_t *cursor, pgpv_t *pgp, const void *p, ssize_t size) +{ + FILE *fp; + char buf[BUFSIZ]; + + if (cursor == NULL || pgp == NULL || p == NULL) { + return 0; + } + memset(cursor, 0x0, sizeof(*cursor)); + ARRAY_APPEND(pgp->datastarts, pgp->pkt); + cursor->pgp = pgp; + if (size < 0) { + /* we have a file name in p */ + if ((fp = fopen(p, "r")) == NULL) { + snprintf(cursor->why, sizeof(cursor->why), "No such file '%s'", (const char *)p); + return 0; + } + if (fgets(buf, (int)sizeof(buf), fp) == NULL) { + fclose(fp); + snprintf(cursor->why, sizeof(cursor->why), "can't read file '%s'", (const char *)p); + return 0; + } + if (is_armored(buf, sizeof(buf))) { + read_ascii_armor_file(cursor, p); + } else { + read_binary_file(pgp, "signature", "%s", p); + } + fclose(fp); + } else { + if (is_armored(p, (size_t)size)) { + read_ascii_armor_memory(cursor, p, (size_t)size); + } else { + read_binary_memory(pgp, "signature", p, (size_t)size); + } + } + return 1; +} + +/* get the data and size from litdata packet */ +static uint8_t * +get_literal_data(pgpv_cursor_t *cursor, pgpv_litdata_t *litdata, size_t *size) +{ + pgpv_mem_t *mem; + + if (litdata->s.data == NULL && litdata->s.size == 0) { + mem = &ARRAY_ELEMENT(cursor->pgp->areas, litdata->mem); + *size = litdata->len; + return &mem->mem[litdata->offset]; + } + *size = litdata->s.size; + return litdata->s.data; +} + +/* +RFC 4880 describes the structure of v4 keys as: + + Primary-Key + [Revocation Self Signature] + [Direct Key Signature...] + User ID [Signature ...] + [User ID [Signature ...] ...] + [User Attribute [Signature ...] ...] + [[Subkey [Binding-Signature-Revocation] + Primary-Key-Binding-Signature] ...] + +and that's implemented below as a recursive descent parser. +It has had to be modified, though: see the comment + + some keys out there have user ids where they shouldn't + +to look like: + + Primary-Key + [Revocation Self Signature] + [Direct Key Signature...] + [User ID [Signature ...] + [User ID [Signature ...] ...] + [User Attribute [Signature ...] ...] + [Subkey [Binding-Signature-Revocation] + Primary-Key-Binding-Signature] ...] + +to accommodate keyrings set up by gpg +*/ + +/* recognise a primary key */ +static int +recog_primary_key(pgpv_t *pgp, pgpv_primarykey_t *primary) +{ + pgpv_signed_userattr_t userattr; + pgpv_signed_userid_t userid; + pgpv_signed_subkey_t subkey; + pgpv_signature_t signature; + pgpv_pkt_t *pkt; + + pkt = &ARRAY_ELEMENT(pgp->pkts, pgp->pkt); + memset(primary, 0x0, sizeof(*primary)); + read_pubkey(&primary->primary, pkt->s.data, pkt->s.size, 0); + pgp->pkt += 1; + if (pkt_sigtype_is(pgp, SIGTYPE_KEY_REVOCATION)) { + if (!recog_signature(pgp, &primary->revoc_self_sig)) { + printf("recog_primary_key: no signature/trust at PGPV_SIGTYPE_KEY_REVOCATION\n"); + return 0; + } + } + while (pkt_sigtype_is(pgp, SIGTYPE_DIRECT_KEY)) { + if (!recog_signature(pgp, &signature)) { + printf("recog_primary_key: no signature/trust at PGPV_SIGTYPE_DIRECT_KEY\n"); + return 0; + } + if (signature.keyexpiry) { + /* XXX - check it's a good key expiry */ + primary->primary.expiry = signature.keyexpiry; + } + ARRAY_APPEND(primary->direct_sigs, signature); + } + /* some keys out there have user ids where they shouldn't */ + do { + if (!recog_userid(pgp, &userid)) { + printf("recog_primary_key: not userid\n"); + return 0; + } + ARRAY_APPEND(primary->signed_userids, userid); + if (userid.primary_userid) { + primary->primary_userid = ARRAY_COUNT(primary->signed_userids) - 1; + } + while (pkt_is(pgp, USERID_PKT)) { + if (!recog_userid(pgp, &userid)) { + printf("recog_primary_key: not signed secondary userid\n"); + return 0; + } + ARRAY_APPEND(primary->signed_userids, userid); + if (userid.primary_userid) { + primary->primary_userid = ARRAY_COUNT(primary->signed_userids) - 1; + } + } + while (pkt_is(pgp, USER_ATTRIBUTE_PKT)) { + if (!recog_userattr(pgp, &userattr)) { + printf("recog_primary_key: not signed user attribute\n"); + return 0; + } + ARRAY_APPEND(primary->signed_userattrs, userattr); + } + while (pkt_is(pgp, PUB_SUBKEY_PKT)) { + if (!recog_subkey(pgp, &subkey)) { + printf("recog_primary_key: not signed public subkey\n"); + return 0; + } + pgpv_calc_keyid(&subkey.subkey); + ARRAY_APPEND(primary->signed_subkeys, subkey); + } + } while (pgp->pkt < ARRAY_COUNT(pgp->pkts) && pkt_is(pgp, USERID_PKT)); + primary->fmtsize = estimate_primarykey_size(primary); + return 1; +} + +/* parse all of the packets for a given operation */ +static int +read_all_packets(pgpv_t *pgp, pgpv_mem_t *mem, const char *op) +{ + pgpv_primarykey_t primary; + + if (op == NULL) { + return 0; + } + if (strcmp(pgp->op = op, "pubring") == 0) { + mem->allowed = PUBRING_ALLOWED; + /* pubrings have thousands of small packets */ + ARRAY_EXPAND_SIZED(pgp->pkts, 0, 5000); + } else if (strcmp(op, "signature") == 0) { + mem->allowed = SIGNATURE_ALLOWED; + } else { + mem->allowed = ""; + } + for (mem->cc = 0; mem->cc < mem->size ; ) { + if (!read_pkt(pgp, mem)) { + return 0; + } + } + if (strcmp(op, "pubring") == 0) { + for (pgp->pkt = 0; pgp->pkt < ARRAY_COUNT(pgp->pkts) && recog_primary_key(pgp, &primary) ; ) { + pgpv_calc_keyid(&primary.primary); + ARRAY_APPEND(pgp->primaries, primary); + } + if (pgp->pkt < ARRAY_COUNT(pgp->pkts)) { + printf("short pubring recognition???\n"); + } + } + pgp->pkt = ARRAY_COUNT(pgp->pkts); + return 1; +} + +/* create a filename, read it, and then parse according to "op" */ +static int +read_binary_file(pgpv_t *pgp, const char *op, const char *fmt, ...) +{ + va_list args; + char buf[1024]; + + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + if (!read_file(pgp, buf)) { + return 0; + } + return read_all_packets(pgp, &ARRAY_LAST(pgp->areas), op); +} + +/* parse memory according to "op" */ +static int +read_binary_memory(pgpv_t *pgp, const char *op, const void *memory, size_t size) +{ + pgpv_mem_t *mem; + + ARRAY_EXPAND(pgp->areas); + ARRAY_COUNT(pgp->areas) += 1; + mem = &ARRAY_LAST(pgp->areas); + memset(mem, 0x0, sizeof(*mem)); + mem->size = size; + mem->mem = __UNCONST(memory); + mem->dealloc = 0; + return read_all_packets(pgp, mem, op); +} + +/* fixup the detached signature packets */ +static int +fixup_detached(pgpv_cursor_t *cursor, const char *f) +{ + pgpv_onepass_t *onepass; + const char *dot; + pgpv_pkt_t sigpkt; + pgpv_pkt_t litdata; + pgpv_mem_t *mem; + size_t el; + char original[MAXPATHLEN]; + + /* cons up litdata pkt */ + if ((dot = strrchr(f, '.')) == NULL || strcasecmp(dot, ".sig") != 0) { + printf("weird filename '%s'\n", f); + return 0; + } + /* hold sigpkt in a temp var while we insert onepass and litdata */ + el = ARRAY_COUNT(cursor->pgp->pkts) - 1; + sigpkt = ARRAY_ELEMENT(cursor->pgp->pkts, el); + ARRAY_DELETE(cursor->pgp->pkts, el); + ARRAY_EXPAND(cursor->pgp->pkts); + /* get onepass packet, append to packets */ + read_binary_memory(cursor->pgp, "signature", cons_onepass, 15); + onepass = &ARRAY_ELEMENT(cursor->pgp->pkts, el).u.onepass; + /* read the original file into litdata */ + snprintf(original, sizeof(original), "%.*s", (int)(dot - f), f); + if (!read_file(cursor->pgp, original)) { + printf("can't read file '%s'\n", original); + return 0; + } + memset(&litdata, 0x0, sizeof(litdata)); + mem = &ARRAY_LAST(cursor->pgp->areas); + litdata.tag = LITDATA_PKT; + litdata.s.data = mem->mem; + litdata.u.litdata.format = LITDATA_BINARY; + litdata.u.litdata.offset = 0; + litdata.u.litdata.filename = (uint8_t *)strdup(original); + litdata.u.litdata.mem = ARRAY_COUNT(cursor->pgp->areas) - 1; + litdata.u.litdata.len = litdata.s.size = mem->size; + ARRAY_APPEND(cursor->pgp->pkts, litdata); + ARRAY_APPEND(cursor->pgp->pkts, sigpkt); + memcpy(onepass->keyid, sigpkt.u.sigpkt.sig.signer, sizeof(onepass->keyid)); + onepass->hashalg = sigpkt.u.sigpkt.sig.hashalg; + onepass->keyalg = sigpkt.u.sigpkt.sig.keyalg; + return 1; +} + +/* match the calculated signature against the oen in the signature packet */ +static int +match_sig(pgpv_cursor_t *cursor, pgpv_signature_t *signature, pgpv_pubkey_t *pubkey, uint8_t *data, size_t size) +{ + unsigned calclen; + uint8_t calculated[64]; + int match; + + calclen = pgpv_digest_memory(calculated, sizeof(calculated), + data, size, + get_ref(&signature->hashstart), signature->hashlen, + (signature->type == SIGTYPE_TEXT) ? 't' : 'b'); + if (ALG_IS_RSA(signature->keyalg)) { + match = rsa_verify(calculated, calclen, signature->hashalg, signature->bn, pubkey); + } else if (ALG_IS_DSA(signature->keyalg)) { + match = verify_dsa_sig(calculated, calclen, signature->bn, pubkey); + } else { + snprintf(cursor->why, sizeof(cursor->why), "Signature type %u not recognised", signature->keyalg); + return 0; + } + if (!match && signature->type == SIGTYPE_TEXT) { + /* second try for cleartext data, ignoring trailing whitespace */ + calclen = pgpv_digest_memory(calculated, sizeof(calculated), + data, size, + get_ref(&signature->hashstart), signature->hashlen, 'w'); + if (ALG_IS_RSA(signature->keyalg)) { + match = rsa_verify(calculated, calclen, signature->hashalg, signature->bn, pubkey); + } else if (ALG_IS_DSA(signature->keyalg)) { + match = verify_dsa_sig(calculated, calclen, signature->bn, pubkey); + } + } + if (!match) { + snprintf(cursor->why, sizeof(cursor->why), "Signature on data did not match"); + return 0; + } + if (valid_dates(signature, pubkey, cursor->why, sizeof(cursor->why)) > 0) { + return 0; + } + if (key_expired(pubkey, cursor->why, sizeof(cursor->why))) { + return 0; + } + if (signature->revoked) { + snprintf(cursor->why, sizeof(cursor->why), "Signature was revoked"); + return 0; + } + return 1; +} + +/* check return value from getenv */ +static const char * +nonnull_getenv(const char *key) +{ + char *value; + + return ((value = getenv(key)) == NULL) ? "" : value; +} + +/************************************************************************/ +/* start of exported functions */ +/************************************************************************/ + +/* close all stuff */ +int +pgpv_close(pgpv_t *pgp) +{ + unsigned i; + + if (pgp == NULL) { + return 0; + } + for (i = 0 ; i < ARRAY_COUNT(pgp->areas) ; i++) { + if (ARRAY_ELEMENT(pgp->areas, i).size > 0) { + closemem(&ARRAY_ELEMENT(pgp->areas, i)); + } + } + return 1; +} + +/* return the formatted entry for the primary key desired */ +size_t +pgpv_get_entry(pgpv_t *pgp, unsigned ent, char **ret) +{ + size_t cc; + + if (ret == NULL || pgp == NULL || ent >= ARRAY_COUNT(pgp->primaries)) { + return 0; + } + *ret = NULL; + cc = ARRAY_ELEMENT(pgp->primaries, ent).fmtsize; + if ((*ret = calloc(1, cc)) == NULL) { + return 0; + } + return fmt_primary(*ret, cc, &ARRAY_ELEMENT(pgp->primaries, ent)); +} + +/* find key id */ +int +pgpv_find_keyid(pgpv_t *pgp, const char *strkeyid, uint8_t *keyid) +{ + unsigned i; + uint8_t binkeyid[PGPV_KEYID_LEN]; + size_t off; + size_t cmp; + + if (strkeyid == NULL && keyid == NULL) { + return 0; + } + if (strkeyid) { + str_to_keyid(strkeyid, binkeyid); + cmp = strlen(strkeyid) / 2; + } else { + memcpy(binkeyid, keyid, sizeof(binkeyid)); + cmp = PGPV_KEYID_LEN; + } + off = PGPV_KEYID_LEN - cmp; + for (i = 0 ; i < ARRAY_COUNT(pgp->primaries) ; i++) { + if (memcmp(&ARRAY_ELEMENT(pgp->primaries, i).primary.keyid[off], &binkeyid[off], cmp) == 0) { + return i; + } + } + return -1; +} + +/* verify the signed packets we have */ +size_t +pgpv_verify(pgpv_cursor_t *cursor, pgpv_t *pgp, const void *p, ssize_t size) +{ + pgpv_signature_t *signature; + pgpv_onepass_t *onepass; + pgpv_litdata_t *litdata; + pgpv_pubkey_t *pubkey; + unsigned primary; + uint8_t *data; + size_t pkt; + size_t insize; + char strkeyid[PGPV_STR_KEYID_LEN]; + int j; + + if (cursor == NULL || pgp == NULL || p == NULL) { + return 0; + } + if (!setup_data(cursor, pgp, p, size)) { + snprintf(cursor->why, sizeof(cursor->why), "No input data"); + return 0; + } + if (ARRAY_COUNT(cursor->pgp->pkts) == ARRAY_LAST(cursor->pgp->datastarts) + 1) { + /* got detached signature here */ + if (!fixup_detached(cursor, p)) { + snprintf(cursor->why, sizeof(cursor->why), "Can't read signed file '%s'", (const char *)p); + return 0; + } + } + if ((pkt = find_onepass(cursor, ARRAY_LAST(cursor->pgp->datastarts))) == 0) { + snprintf(cursor->why, sizeof(cursor->why), "No signature found"); + return 0; + } + pkt -= 1; + onepass = &ARRAY_ELEMENT(cursor->pgp->pkts, pkt).u.onepass; + litdata = &ARRAY_ELEMENT(cursor->pgp->pkts, pkt + 1).u.litdata; + signature = &ARRAY_ELEMENT(cursor->pgp->pkts, pkt + 2).u.sigpkt.sig; + /* sanity check values in signature and onepass agree */ + if (signature->birth == 0) { + fmt_time(cursor->why, sizeof(cursor->why), "Signature creation time [", + signature->birth, "] out of range", 0); + return 0; + } + if (memcmp(onepass->keyid, signature->signer, PGPV_KEYID_LEN) != 0) { + fmt_binary(strkeyid, sizeof(strkeyid), onepass->keyid, (unsigned)sizeof(onepass->keyid)); + snprintf(cursor->why, sizeof(cursor->why), "Signature key id %s does not match onepass keyid", + strkeyid); + return 0; + } + if (onepass->hashalg != signature->hashalg) { + snprintf(cursor->why, sizeof(cursor->why), "Signature hashalg %u does not match onepass hashalg %u", + signature->hashalg, onepass->hashalg); + return 0; + } + if (onepass->keyalg != signature->keyalg) { + snprintf(cursor->why, sizeof(cursor->why), "Signature keyalg %u does not match onepass keyalg %u", + signature->keyalg, onepass->keyalg); + return 0; + } + if ((j = pgpv_find_keyid(cursor->pgp, NULL, onepass->keyid)) < 0) { + fmt_binary(strkeyid, sizeof(strkeyid), onepass->keyid, (unsigned)sizeof(onepass->keyid)); + snprintf(cursor->why, sizeof(cursor->why), "Signature key id %s not found ", strkeyid); + return 0; + } + primary = (unsigned)j; + pubkey = &ARRAY_ELEMENT(cursor->pgp->primaries, primary).primary; + cursor->sigtime = signature->birth; + /* calc hash on data packet */ + data = get_literal_data(cursor, litdata, &insize); + if (!match_sig(cursor, signature, pubkey, data, insize)) { + return 0; + } + ARRAY_APPEND(cursor->datacookies, pkt); + ARRAY_APPEND(cursor->found, primary); + return pkt + 1; +} + +/* set up the pubkey keyring */ +int +pgpv_read_pubring(pgpv_t *pgp, const void *keyring, ssize_t size) +{ + if (pgp == NULL) { + return 0; + } + if (keyring) { + return (size > 0) ? + read_binary_memory(pgp, "pubring", keyring, (size_t)size) : + read_binary_file(pgp, "pubring", "%s", keyring); + } + return read_binary_file(pgp, "pubring", "%s/%s", nonnull_getenv("HOME"), ".gnupg/pubring.gpg"); +} + +/* get verified data as a string, return its size */ +size_t +pgpv_get_verified(pgpv_cursor_t *cursor, size_t cookie, char **ret) +{ + pgpv_litdata_t *litdata; + uint8_t *data; + size_t size; + size_t pkt; + + if (ret == NULL || cursor == NULL || cookie == 0) { + return 0; + } + *ret = NULL; + if ((pkt = find_onepass(cursor, cookie - 1)) == 0) { + return 0; + } + litdata = &ARRAY_ELEMENT(cursor->pgp->pkts, pkt).u.litdata; + data = get_literal_data(cursor, litdata, &size); + if ((*ret = calloc(1, size)) == NULL) { + return 0; + } + memcpy(*ret, data, size); + return size; +} diff --git a/crypto/external/bsd/netpgp/dist/src/libverify/pgpsum.c b/crypto/external/bsd/netpgp/dist/src/libverify/pgpsum.c new file mode 100644 index 000000000000..fedfaaeb5912 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libverify/pgpsum.c @@ -0,0 +1,187 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "digest.h" +#include "pgpsum.h" + +/* add the ascii armor line endings (except for last line) */ +static size_t +don_armor(digest_t *hash, uint8_t *in, size_t insize, int doarmor) +{ + uint8_t *from; + uint8_t *newp; + uint8_t *p; + uint8_t dos_line_end[2]; + + dos_line_end[0] = '\r'; + dos_line_end[1] = '\n'; + for (from = in ; (p = memchr(from, '\n', insize - (size_t)(from - in))) != NULL ; from = p + 1) { + for (newp = p ; doarmor == 'w' && newp > from ; --newp) { + if (*(newp - 1) != ' ' && *(newp - 1) != '\t') { + break; + } + } + digest_update(hash, from, (size_t)(newp - from)); + digest_update(hash, dos_line_end, sizeof(dos_line_end)); + } + digest_update(hash, from, insize - (size_t)(from - in)); + return 1; +} + +#ifdef NETPGPV_DEBUG +/* just for giggles, write what we're about to checksum */ +static int +writefile(uint8_t *mem, size_t insize) +{ + size_t cc; + size_t wc; + char template[256]; + int fd; + + snprintf(template, sizeof(template), "netpgpvmd.XXXXXX"); + if ((fd = mkstemp(template)) < 0) { + fprintf(stderr, "can't mkstemp %s\n", template); + return 0; + } + for (cc = 0 ; cc < insize ; cc += wc) { + if ((wc = write(fd, &mem[cc], insize - cc)) <= 0) { + fprintf(stderr, "short write\n"); + break; + } + } + close(fd); + return 1; +} +#endif + +/* return non-zero if this is actually an armored piece already */ +static int +already_armored(uint8_t *in, size_t insize) +{ + uint8_t *from; + uint8_t *p; + + for (from = in ; (p = memchr(from, '\n', insize - (size_t)(from - in))) != NULL ; from = p + 1) { + if (*(p - 1) != '\r') { + return 0; + } + } + return 1; +} + +/* calculate the checksum for the data we have */ +static int +calcsum(uint8_t *out, size_t size, const char *name, uint8_t *mem, size_t cc, const uint8_t *hashed, size_t hashsize, int doarmor) +{ + digest_t hash; + uint32_t len32; + uint16_t len16; + uint8_t hashalg; + uint8_t trailer[6]; + + /* hashed data is non-null (previously checked) */ + hashalg = hashed[3]; + memcpy(&len16, &hashed[4], sizeof(len16)); + len32 = ntohs(len16) + 6; + len32 = htonl(len32); + trailer[0] = 0x04; + trailer[1] = 0xff; + memcpy(&trailer[2], &len32, sizeof(len32)); +#ifdef NETPGPV_DEBUG + writefile(mem, cc); +#endif + digest_init(&hash, hashalg); + if (strchr("tw", doarmor) != NULL && !already_armored(mem, cc)) { + /* this took me ages to find - something causes gpg to truncate its input */ + don_armor(&hash, mem, cc - 1, doarmor); + } else { + digest_update(&hash, mem, cc); + } + if (hashed) { + digest_update(&hash, hashed, hashsize); + } + digest_update(&hash, trailer, sizeof(trailer)); + return digest_final(out, &hash); +} + +/* open the file, mmap it, and then get the checksum on that */ +int +pgpv_digest_file(uint8_t *data, size_t size, const char *name, const uint8_t *hashed, size_t hashsize, int doarmor) +{ + struct stat st; + uint8_t *mem; + size_t cc; + FILE *fp; + int ret; + + if (hashed == NULL || data == NULL || name == NULL) { + fprintf(stderr, "no hashed data provided\n"); + return 0; + } + ret = 0; + mem = NULL; + cc = 0; + if ((fp = fopen(name, "r")) == NULL) { + warn("%s - not found", name); + return 0; + } + if (fstat(fileno(fp), &st) < 0) { + warn("%s - can't stat", name); + goto done; + } + cc = (size_t)(st.st_size); + if ((mem = mmap(NULL, cc, PROT_READ, MAP_SHARED, fileno(fp), 0)) == MAP_FAILED) { + warn("%s - can't mmap", name); + goto done; + } + ret = calcsum(data, size, name, mem, cc, hashed, hashsize, doarmor); +done: + if (data) { + munmap(mem, cc); + } + fclose(fp); + return ret; +} + +/* calculate the digest over memory too */ +int +pgpv_digest_memory(uint8_t *data, size_t size, void *mem, size_t cc, const uint8_t *hashed, size_t hashsize, int doarmor) +{ + if (hashed == NULL || data == NULL || mem == NULL) { + fprintf(stderr, "no hashed data provided\n"); + return 0; + } + return calcsum(data, size, "[memory]", mem, cc, hashed, hashsize, doarmor); +} diff --git a/crypto/external/bsd/netpgp/dist/src/libverify/pgpsum.h b/crypto/external/bsd/netpgp/dist/src/libverify/pgpsum.h new file mode 100644 index 000000000000..75eb22762488 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libverify/pgpsum.h @@ -0,0 +1,35 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef PGPSUM_H_ +#define PGPSUM_H_ 20121003 + +#include + +#include + +int pgpv_digest_file(uint8_t */*buf*/, size_t /*size*/, const char */*name*/, const uint8_t */*hashed*/, size_t /*hashsize*/, int /*doarmor*/); +int pgpv_digest_memory(uint8_t */*buf*/, size_t /*size*/, void */*memory*/, size_t /*cc*/, const uint8_t */*hashed*/, size_t /*hashsize*/, int /*doarmor*/); + +#endif diff --git a/crypto/external/bsd/netpgp/dist/src/libverify/verify.h b/crypto/external/bsd/netpgp/dist/src/libverify/verify.h new file mode 100644 index 000000000000..36ffaacab5b6 --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/libverify/verify.h @@ -0,0 +1,292 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef NETPGP_VERIFY_H_ +#define NETPGP_VERIFY_H_ 20120928 + +#include + +#include + +#ifndef PGPV_ARRAY +/* creates 2 unsigned vars called "name"c and "name"size in current scope */ +/* also creates an array called "name"s in current scope */ +#define PGPV_ARRAY(type, name) \ + unsigned name##c; unsigned name##vsize; type *name##s +#endif + +/* 64bit key ids */ +#define PGPV_KEYID_LEN 8 +#define PGPV_STR_KEYID_LEN (PGPV_KEYID_LEN + PGPV_KEYID_LEN + 1) + +/* bignum structure */ +typedef struct pgpv_bignum_t { + void *bn; /* hide the implementation details */ + uint16_t bits; /* cached number of bits */ +} pgpv_bignum_t; + +/* right now, our max binary digest length is 20 bytes */ +#define PGPV_MAX_HASH_LEN 20 + +/* fingerprint */ +typedef struct pgpv_fingerprint_t { + uint8_t hashalg; /* algorithm for digest */ + uint8_t v[PGPV_MAX_HASH_LEN]; /* the digest */ + uint32_t len; /* its length */ +} pgpv_fingerprint_t; + +/* specify size for array of bignums */ +#define PGPV_MAX_PUBKEY_BN 4 + +/* public key */ +typedef struct pgpv_pubkey_t { + pgpv_fingerprint_t fingerprint; /* key fingerprint i.e. digest */ + uint8_t keyid[PGPV_KEYID_LEN]; /* last 8 bytes of v4 keys */ + int64_t birth; /* creation time */ + int64_t expiry; /* expiry time */ + pgpv_bignum_t bn[PGPV_MAX_PUBKEY_BN]; /* bignums */ + uint8_t keyalg; /* key algorithm */ + uint8_t hashalg; /* hash algorithm */ + uint8_t version; /* key version */ +} pgpv_pubkey_t; + +#define PGPV_MAX_SESSKEY_BN 2 + +/* a (size, byte array) string */ +typedef struct pgpv_string_t { + size_t size; + uint8_t *data; +} pgpv_string_t; + +typedef struct pgpv_ref_t { + void *vp; + size_t offset; + unsigned mem; +} pgpv_ref_t; + +#define PGPV_MAX_SECKEY_BN 4 + +typedef struct pgpv_compress_t { + pgpv_string_t s; + uint8_t compalg; +} pgpv_compress_t; + +/* a packet dealing with trust */ +typedef struct pgpv_trust_t { + uint8_t level; + uint8_t amount; +} pgpv_trust_t; + +/* a signature sub packet */ +typedef struct pgpv_sigsubpkt_t { + pgpv_string_t s; + uint8_t tag; + uint8_t critical; +} pgpv_sigsubpkt_t; + +#define PGPV_MAX_SIG_BN 2 + +typedef struct pgpv_signature_t { + uint8_t *signer; /* key id of signer */ + pgpv_ref_t hashstart; + uint8_t *hash2; + uint8_t *mpi; + int64_t birth; + int64_t keyexpiry; + int64_t expiry; + uint32_t hashlen; + uint8_t version; + uint8_t type; + uint8_t keyalg; + uint8_t hashalg; + uint8_t trustlevel; + uint8_t trustamount; + pgpv_bignum_t bn[PGPV_MAX_SIG_BN]; + char *regexp; + char *pref_key_server; + char *policy; + char *features; + char *why_revoked; + uint8_t *revoke_fingerprint; + uint8_t revoke_alg; + uint8_t revoke_sensitive; + uint8_t trustsig; + uint8_t revocable; + uint8_t pref_symm_alg; + uint8_t pref_hash_alg; + uint8_t pref_compress_alg; + uint8_t key_server_modify; + uint8_t notation; + uint8_t type_key; + uint8_t primary_userid; + uint8_t revoked; /* subtract 1 to get real reason, 0 == not revoked */ +} pgpv_signature_t; + +/* a signature packet */ +typedef struct pgpv_sigpkt_t { + pgpv_signature_t sig; + uint16_t subslen; + uint16_t unhashlen; + PGPV_ARRAY(pgpv_sigsubpkt_t, subpkts); +} pgpv_sigpkt_t; + +/* a one-pass signature packet */ +typedef struct pgpv_onepass_t { + uint8_t keyid[PGPV_KEYID_LEN]; + uint8_t version; + uint8_t type; + uint8_t hashalg; + uint8_t keyalg; + uint8_t nested; +} pgpv_onepass_t; + +/* a literal data packet */ +typedef struct pgpv_litdata_t { + uint8_t *filename; + pgpv_string_t s; + uint32_t secs; + uint8_t namelen; + char format; + unsigned mem; + size_t offset; + size_t len; +} pgpv_litdata_t; + +/* user attributes - images */ +typedef struct pgpv_userattr_t { + size_t len; + PGPV_ARRAY(pgpv_string_t, subattrs); +} pgpv_userattr_t; + +/* a general PGP packet */ +typedef struct pgpv_pkt_t { + uint8_t tag; + uint8_t newfmt; + uint8_t allocated; + uint8_t mement; + size_t offset; + pgpv_string_t s; + union { + pgpv_sigpkt_t sigpkt; + pgpv_onepass_t onepass; + pgpv_litdata_t litdata; + pgpv_compress_t compressed; + pgpv_trust_t trust; + pgpv_pubkey_t pubkey; + pgpv_string_t userid; + pgpv_userattr_t userattr; + } u; +} pgpv_pkt_t; + +/* a memory structure */ +typedef struct pgpv_mem_t { + size_t size; + size_t cc; + uint8_t *mem; + FILE *fp; + uint8_t dealloc; + const char *allowed; /* the types of packet that are allowed */ +} pgpv_mem_t; + +/* packet parser */ + +typedef struct pgpv_signed_userid_t { + pgpv_string_t userid; + PGPV_ARRAY(pgpv_signature_t, sigs); + uint8_t primary_userid; + uint8_t revoked; +} pgpv_signed_userid_t; + +typedef struct pgpv_signed_userattr_t { + pgpv_userattr_t userattr; + PGPV_ARRAY(pgpv_signature_t, sigs); + uint8_t revoked; +} pgpv_signed_userattr_t; + +typedef struct pgpv_signed_subkey_t { + pgpv_pubkey_t subkey; + pgpv_signature_t revoc_self_sig; + PGPV_ARRAY(pgpv_signature_t, sigs); +} pgpv_signed_subkey_t; + +typedef struct pgpv_primarykey_t { + pgpv_pubkey_t primary; + pgpv_signature_t revoc_self_sig; + PGPV_ARRAY(pgpv_signature_t, direct_sigs); + PGPV_ARRAY(pgpv_signed_userid_t, signed_userids); + PGPV_ARRAY(pgpv_signed_userattr_t, signed_userattrs); + PGPV_ARRAY(pgpv_signed_subkey_t, signed_subkeys); + size_t fmtsize; + uint8_t primary_userid; +} pgpv_primarykey_t; + +/* everything stems from this structure */ +typedef struct pgpv_t { + PGPV_ARRAY(pgpv_pkt_t, pkts); /* packet array */ + PGPV_ARRAY(pgpv_primarykey_t, primaries); /* array of primary keys */ + PGPV_ARRAY(pgpv_mem_t, areas); /* areas we read packets from */ + PGPV_ARRAY(size_t, datastarts); /* starts of data packets */ + size_t pkt; /* when parsing, current pkt number */ + const char *op; /* the operation we're doing */ +} pgpv_t; + +#define PGPV_REASON_LEN 128 + +/* when searching, we define a cursor, and fill in an array of subscripts */ +typedef struct pgpv_cursor_t { + pgpv_t *pgp; /* pointer to pgp tree */ + char *field; /* field we're searching on */ + char *op; /* operation we're doing */ + char *value; /* value we're searching for */ + void *ptr; /* for regexps etc */ + PGPV_ARRAY(uint32_t, found); /* array of matched subscripts */ + PGPV_ARRAY(size_t, datacookies); /* cookies to retrieve matched data */ + int64_t sigtime; /* time of signature */ + char why[PGPV_REASON_LEN]; /* reason for bad signature */ +} pgpv_cursor_t; + +#ifndef __BEGIN_DECLS +# if defined(__cplusplus) +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +# else +# define __BEGIN_DECLS +# define __END_DECLS +# endif +#endif + +__BEGIN_DECLS + +int pgpv_read_pubring(pgpv_t */*pgp*/, const void */*keyringfile/mem*/, ssize_t /*size*/); + +size_t pgpv_verify(pgpv_cursor_t */*cursor*/, pgpv_t */*pgp*/, const void */*mem/file*/, ssize_t /*size*/); +size_t pgpv_get_verified(pgpv_cursor_t */*cursor*/, size_t /*cookie*/, char **/*ret*/); + +size_t pgpv_get_entry(pgpv_t */*pgp*/, unsigned /*ent*/, char **/*ret*/); + +int pgpv_close(pgpv_t */*pgp*/); + +__END_DECLS + +#endif diff --git a/crypto/external/bsd/netpgp/dist/src/netpgpverify/main.c b/crypto/external/bsd/netpgp/dist/src/netpgpverify/main.c new file mode 100644 index 000000000000..0564c3f3eb5d --- /dev/null +++ b/crypto/external/bsd/netpgp/dist/src/netpgpverify/main.c @@ -0,0 +1,165 @@ +/*- + * Copyright (c) 2012 Alistair Crooks + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "verify.h" + +#include "array.h" + +/* print the time nicely */ +static void +ptime(int64_t secs) +{ + time_t t; + + t = (time_t)secs; + printf("%s", ctime(&t)); +} + +/* print entry n */ +static void +pentry(pgpv_t *pgp, int n) +{ + char *s; + + pgpv_get_entry(pgp, (unsigned)n, &s); + printf("%s", s); + free(s); +} + +#define MB(x) ((x) * 1024 * 1024) + +/* get stdin into memory so we can verify it */ +static char * +getstdin(ssize_t *cc, size_t *size) +{ + size_t newsize; + char *newin; + char *in; + int rc; + + *cc = 0; + *size = 0; + in = NULL; + do { + newsize = *size + MB(1); + if ((newin = realloc(in, newsize)) == NULL) { + break; + } + in = newin; + *size = newsize; + if ((rc = read(STDIN_FILENO, &in[*cc], newsize - *cc)) > 0) { + *cc += rc; + } + } while (rc > 0); + return in; +} + +/* verify memory or file */ +static int +verify_data(pgpv_t *pgp, const char *cmd, const char *inname, char *in, ssize_t cc) +{ + pgpv_cursor_t cursor; + size_t size; + size_t cookie; + char *data; + + memset(&cursor, 0x0, sizeof(cursor)); + if (strcasecmp(cmd, "cat") == 0) { + if ((cookie = pgpv_verify(&cursor, pgp, in, cc)) != 0) { + if ((size = pgpv_get_verified(&cursor, cookie, &data)) > 0) { + printf("%.*s", (int)size, data); + } + return 1; + } + } else if (strcasecmp(cmd, "verify") == 0) { + if (pgpv_verify(&cursor, pgp, in, cc)) { + printf("Good signature for %s made ", inname); + ptime(cursor.sigtime); + pentry(pgp, ARRAY_ELEMENT(cursor.found, 0)); + return 1; + } + warnx("Signature did not match contents -- %s", cursor.why); + } else { + warnx("unrecognised command \"%s\"", cmd); + } + return 0; +} + +int +main(int argc, char **argv) +{ + const char *keyring; + const char *cmd; + ssize_t cc; + size_t size; + pgpv_t pgp; + char *in; + int ok; + int i; + + memset(&pgp, 0x0, sizeof(pgp)); + cmd = NULL; + keyring = NULL; + ok = 1; + while ((i = getopt(argc, argv, "c:k:")) != -1) { + switch(i) { + case 'c': + cmd = optarg; + break; + case 'k': + keyring = optarg; + break; + default: + break; + } + } + if (cmd == NULL) { + cmd = "verify"; + } + if (!pgpv_read_pubring(&pgp, keyring, -1)) { + errx(EXIT_FAILURE, "can't read keyring"); + } + if (optind == argc) { + in = getstdin(&cc, &size); + ok = verify_data(&pgp, cmd, "[stdin]", in, cc); + } else { + for (ok = 1, i = optind ; i < argc ; i++) { + if (!verify_data(&pgp, cmd, argv[i], argv[i], -1)) { + ok = 0; + } + } + } + pgpv_close(&pgp); + exit((ok) ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/crypto/external/bsd/netpgp/lib/verify/Makefile b/crypto/external/bsd/netpgp/lib/verify/Makefile new file mode 100644 index 000000000000..7e1db37df00a --- /dev/null +++ b/crypto/external/bsd/netpgp/lib/verify/Makefile @@ -0,0 +1,19 @@ +# $NetBSD: Makefile,v 1.2 2012/11/20 05:26:26 agc Exp $ + +LIB=netpgpverify +SRCS=libverify.c b64.c pgpsum.c +SRCS+=digest.c tiger.c +SRCS+=bignum.c misc.c +CPPFLAGS+=-I${EXTDIST}/src/libbn +CPPFLAGS+=-I${EXTDIST}/src/libdigest +CPPFLAGS+=-I${EXTDIST}/src/librsa +MAN=libnetpgpverify.3 +WARNS=5 + +EXTDIST=${.CURDIR}/../../dist +.PATH: ${EXTDIST}/src/libverify ${EXTDIST}/src/libdigest ${EXTDIST}/src/libbn ${EXTDIST}/src/librsa + +INCS=verify.h +INCSDIR=/usr/include/netpgp + +.include diff --git a/crypto/external/bsd/netpgp/lib/verify/shlib_version b/crypto/external/bsd/netpgp/lib/verify/shlib_version new file mode 100644 index 000000000000..d9961ea9feff --- /dev/null +++ b/crypto/external/bsd/netpgp/lib/verify/shlib_version @@ -0,0 +1,2 @@ +major=4 +minor=0