diff options
author | René Schümann <white06tiger@gmail.com> | 2015-03-20 12:32:29 +0000 |
---|---|---|
committer | René Schümann <white06tiger@gmail.com> | 2015-03-20 12:32:29 +0000 |
commit | 539705d58fc39a28388ff18c695dd406f4ffd1d9 (patch) | |
tree | 51db7a37a66c09f41734ba5573d972aae9f30d71 /plugins/MirOTR/Libgcrypt/cipher | |
parent | 90171f125f36488dc08f5cfe0b0d4b78d995f08d (diff) |
MirOTR: Libgcrypt and Libgpg-error update
Libgcrypt 1.4.6 => 1.6.3
Libgpg-error 1.9 => 1.18
git-svn-id: http://svn.miranda-ng.org/main/trunk@12449 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/MirOTR/Libgcrypt/cipher')
74 files changed, 26279 insertions, 14328 deletions
diff --git a/plugins/MirOTR/Libgcrypt/cipher/ac.c b/plugins/MirOTR/Libgcrypt/cipher/ac.c deleted file mode 100644 index ee9498b23d..0000000000 --- a/plugins/MirOTR/Libgcrypt/cipher/ac.c +++ /dev/null @@ -1,3301 +0,0 @@ -/* ac.c - Alternative interface for asymmetric cryptography. - Copyright (C) 2003, 2004, 2005, 2006 - 2007, 2008 Free Software Foundation, Inc. - - This file is part of Libgcrypt. - - Libgcrypt is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser general Public License as - published by the Free Software Foundation; either version 2.1 of - the License, or (at your option) any later version. - - Libgcrypt is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include <config.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <stddef.h> - -#include "g10lib.h" -#include "cipher.h" -#include "mpi.h" - - - -/* At the moment the ac interface is a wrapper around the pk - interface, but this might change somewhen in the future, depending - on how many people prefer the ac interface. */ - -/* Mapping of flag numbers to the according strings as it is expected - for S-expressions. */ -static struct number_string -{ - int number; - const char *string; -} ac_flags[] = - { - { GCRY_AC_FLAG_NO_BLINDING, "no-blinding" }, - }; - -/* The positions in this list correspond to the values contained in - the gcry_ac_key_type_t enumeration list. */ -static const char *ac_key_identifiers[] = - { - "private-key", - "public-key" - }; - -/* These specifications are needed for key-pair generation; the caller - is allowed to pass additional, algorithm-specific `specs' to - gcry_ac_key_pair_generate. This list is used for decoding the - provided values according to the selected algorithm. */ -struct gcry_ac_key_generate_spec -{ - int algorithm; /* Algorithm for which this flag is - relevant. */ - const char *name; /* Name of this flag. */ - size_t offset; /* Offset in the cipher-specific spec - structure at which the MPI value - associated with this flag is to be - found. */ -} ac_key_generate_specs[] = - { - { GCRY_AC_RSA, "rsa-use-e", offsetof (gcry_ac_key_spec_rsa_t, e) }, - { 0 } - }; - -/* Handle structure. */ -struct gcry_ac_handle -{ - int algorithm; /* Algorithm ID associated with this - handle. */ - const char *algorithm_name; /* Name of the algorithm. */ - unsigned int flags; /* Flags, not used yet. */ - gcry_module_t module; /* Reference to the algorithm - module. */ -}; - -/* A named MPI value. */ -typedef struct gcry_ac_mpi -{ - char *name; /* Self-maintained copy of name. */ - gcry_mpi_t mpi; /* MPI value. */ - unsigned int flags; /* Flags. */ -} gcry_ac_mpi_t; - -/* A data set, that is simply a list of named MPI values. */ -struct gcry_ac_data -{ - gcry_ac_mpi_t *data; /* List of named values. */ - unsigned int data_n; /* Number of values in DATA. */ -}; - -/* A single key. */ -struct gcry_ac_key -{ - gcry_ac_data_t data; /* Data in native ac structure. */ - gcry_ac_key_type_t type; /* Type of the key. */ -}; - -/* A key pair. */ -struct gcry_ac_key_pair -{ - gcry_ac_key_t public; - gcry_ac_key_t secret; -}; - - - -/* - * Functions for working with data sets. - */ - -/* Creates a new, empty data set and store it in DATA. */ -gcry_error_t -_gcry_ac_data_new (gcry_ac_data_t *data) -{ - gcry_ac_data_t data_new; - gcry_error_t err; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - data_new = gcry_malloc (sizeof (*data_new)); - if (! data_new) - { - err = gcry_error_from_errno (errno); - goto out; - } - - data_new->data = NULL; - data_new->data_n = 0; - *data = data_new; - err = 0; - - out: - - return err; -} - -/* Destroys all the entries in DATA, but not DATA itself. */ -static void -ac_data_values_destroy (gcry_ac_data_t data) -{ - unsigned int i; - - for (i = 0; i < data->data_n; i++) - if (data->data[i].flags & GCRY_AC_FLAG_DEALLOC) - { - gcry_mpi_release (data->data[i].mpi); - gcry_free (data->data[i].name); - } -} - -/* Destroys the data set DATA. */ -void -_gcry_ac_data_destroy (gcry_ac_data_t data) -{ - if (data) - { - ac_data_values_destroy (data); - gcry_free (data->data); - gcry_free (data); - } -} - -/* This function creates a copy of the array of named MPIs DATA_MPIS, - which is of length DATA_MPIS_N; the copy is stored in - DATA_MPIS_CP. */ -static gcry_error_t -ac_data_mpi_copy (gcry_ac_mpi_t *data_mpis, unsigned int data_mpis_n, - gcry_ac_mpi_t **data_mpis_cp) -{ - gcry_ac_mpi_t *data_mpis_new; - gcry_error_t err; - unsigned int i; - gcry_mpi_t mpi; - char *label; - - data_mpis_new = gcry_malloc (sizeof (*data_mpis_new) * data_mpis_n); - if (! data_mpis_new) - { - err = gcry_error_from_errno (errno); - goto out; - } - memset (data_mpis_new, 0, sizeof (*data_mpis_new) * data_mpis_n); - - err = 0; - for (i = 0; i < data_mpis_n; i++) - { - /* Copy values. */ - - label = gcry_strdup (data_mpis[i].name); - mpi = gcry_mpi_copy (data_mpis[i].mpi); - if (! (label && mpi)) - { - err = gcry_error_from_errno (errno); - gcry_mpi_release (mpi); - gcry_free (label); - break; - } - - data_mpis_new[i].flags = GCRY_AC_FLAG_DEALLOC; - data_mpis_new[i].name = label; - data_mpis_new[i].mpi = mpi; - } - if (err) - goto out; - - *data_mpis_cp = data_mpis_new; - err = 0; - - out: - - if (err) - if (data_mpis_new) - { - for (i = 0; i < data_mpis_n; i++) - { - gcry_mpi_release (data_mpis_new[i].mpi); - gcry_free (data_mpis_new[i].name); - } - gcry_free (data_mpis_new); - } - - return err; -} - -/* Create a copy of the data set DATA and store it in DATA_CP. */ -gcry_error_t -_gcry_ac_data_copy (gcry_ac_data_t *data_cp, gcry_ac_data_t data) -{ - gcry_ac_mpi_t *data_mpis = NULL; - gcry_ac_data_t data_new; - gcry_error_t err; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - /* Allocate data set. */ - data_new = gcry_malloc (sizeof (*data_new)); - if (! data_new) - { - err = gcry_error_from_errno (errno); - goto out; - } - - err = ac_data_mpi_copy (data->data, data->data_n, &data_mpis); - if (err) - goto out; - - data_new->data_n = data->data_n; - data_new->data = data_mpis; - *data_cp = data_new; - - out: - - if (err) - gcry_free (data_new); - - return err; -} - -/* Returns the number of named MPI values inside of the data set - DATA. */ -unsigned int -_gcry_ac_data_length (gcry_ac_data_t data) -{ - return data->data_n; -} - - -/* Add the value MPI to DATA with the label NAME. If FLAGS contains - GCRY_AC_FLAG_COPY, the data set will contain copies of NAME - and MPI. If FLAGS contains GCRY_AC_FLAG_DEALLOC or - GCRY_AC_FLAG_COPY, the values contained in the data set will - be deallocated when they are to be removed from the data set. */ -gcry_error_t -_gcry_ac_data_set (gcry_ac_data_t data, unsigned int flags, - const char *name, gcry_mpi_t mpi) -{ - gcry_error_t err; - gcry_mpi_t mpi_cp; - char *name_cp; - unsigned int i; - - name_cp = NULL; - mpi_cp = NULL; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - if (flags & ~(GCRY_AC_FLAG_DEALLOC | GCRY_AC_FLAG_COPY)) - { - err = gcry_error (GPG_ERR_INV_ARG); - goto out; - } - - if (flags & GCRY_AC_FLAG_COPY) - { - /* Create copies. */ - - flags |= GCRY_AC_FLAG_DEALLOC; - name_cp = gcry_strdup (name); - mpi_cp = gcry_mpi_copy (mpi); - if (! (name_cp && mpi_cp)) - { - err = gcry_error_from_errno (errno); - goto out; - } - } - - /* Search for existing entry. */ - for (i = 0; i < data->data_n; i++) - if (! strcmp (name, data->data[i].name)) - break; - if (i < data->data_n) - { - /* An entry for NAME does already exist. */ - if (data->data[i].flags & GCRY_AC_FLAG_DEALLOC) - { - gcry_mpi_release (data->data[i].mpi); - gcry_free (data->data[i].name); - } - } - else - { - /* Create a new entry. */ - - gcry_ac_mpi_t *ac_mpis; - - ac_mpis = gcry_realloc (data->data, - sizeof (*data->data) * (data->data_n + 1)); - if (! ac_mpis) - { - err = gcry_error_from_errno (errno); - goto out; - } - - if (data->data != ac_mpis) - data->data = ac_mpis; - data->data_n++; - } - - data->data[i].name = name_cp ? name_cp : ((char *) name); - data->data[i].mpi = mpi_cp ? mpi_cp : mpi; - data->data[i].flags = flags; - err = 0; - - out: - - if (err) - { - gcry_mpi_release (mpi_cp); - gcry_free (name_cp); - } - - return err; -} - -/* Stores the value labelled with NAME found in the data set DATA in - MPI. The returned MPI value will be released in case - gcry_ac_data_set is used to associate the label NAME with a - different MPI value. */ -gcry_error_t -_gcry_ac_data_get_name (gcry_ac_data_t data, unsigned int flags, - const char *name, gcry_mpi_t *mpi) -{ - gcry_mpi_t mpi_return; - gcry_error_t err; - unsigned int i; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - if (flags & ~(GCRY_AC_FLAG_COPY)) - { - err = gcry_error (GPG_ERR_INV_ARG); - goto out; - } - - for (i = 0; i < data->data_n; i++) - if (! strcmp (name, data->data[i].name)) - break; - if (i == data->data_n) - { - err = gcry_error (GPG_ERR_NOT_FOUND); - goto out; - } - - if (flags & GCRY_AC_FLAG_COPY) - { - mpi_return = gcry_mpi_copy (data->data[i].mpi); - if (! mpi_return) - { - err = gcry_error_from_errno (errno); /* FIXME? */ - goto out; - } - } - else - mpi_return = data->data[i].mpi; - - *mpi = mpi_return; - err = 0; - - out: - - return err; -} - -/* Stores in NAME and MPI the named MPI value contained in the data - set DATA with the index IDX. NAME or MPI may be NULL. The - returned MPI value will be released in case gcry_ac_data_set is - used to associate the label NAME with a different MPI value. */ -gcry_error_t -_gcry_ac_data_get_index (gcry_ac_data_t data, unsigned int flags, - unsigned int idx, - const char **name, gcry_mpi_t *mpi) -{ - gcry_error_t err; - gcry_mpi_t mpi_cp; - char *name_cp; - - name_cp = NULL; - mpi_cp = NULL; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - if (flags & ~(GCRY_AC_FLAG_COPY)) - { - err = gcry_error (GPG_ERR_INV_ARG); - goto out; - } - - if (idx >= data->data_n) - { - err = gcry_error (GPG_ERR_INV_ARG); - goto out; - } - - if (flags & GCRY_AC_FLAG_COPY) - { - /* Return copies to the user. */ - if (name) - { - name_cp = gcry_strdup (data->data[idx].name); - if (! name_cp) - { - err = gcry_error_from_errno (errno); - goto out; - } - } - if (mpi) - { - mpi_cp = gcry_mpi_copy (data->data[idx].mpi); - if (! mpi_cp) - { - err = gcry_error_from_errno (errno); - goto out; - } - } - } - - if (name) - *name = name_cp ? name_cp : data->data[idx].name; - if (mpi) - *mpi = mpi_cp ? mpi_cp : data->data[idx].mpi; - err = 0; - - out: - - if (err) - { - gcry_mpi_release (mpi_cp); - gcry_free (name_cp); - } - - return err; -} - -/* Convert the data set DATA into a new S-Expression, which is to be - stored in SEXP, according to the identifiers contained in - IDENTIFIERS. */ -gcry_error_t -_gcry_ac_data_to_sexp (gcry_ac_data_t data, gcry_sexp_t *sexp, - const char **identifiers) -{ - gcry_sexp_t sexp_new; - gcry_error_t err; - char *sexp_buffer; - size_t sexp_buffer_n; - size_t identifiers_n; - const char *label; - gcry_mpi_t mpi; - void **arg_list; - size_t data_n; - unsigned int i; - - sexp_buffer_n = 1; - sexp_buffer = NULL; - arg_list = NULL; - err = 0; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - /* Calculate size of S-expression representation. */ - - i = 0; - if (identifiers) - while (identifiers[i]) - { - /* For each identifier, we add "(<IDENTIFIER>)". */ - sexp_buffer_n += 1 + strlen (identifiers[i]) + 1; - i++; - } - identifiers_n = i; - - if (! identifiers_n) - /* If there are NO identifiers, we still add surrounding braces so - that we have a list of named MPI value lists. Otherwise it - wouldn't be too much fun to process these lists. */ - sexp_buffer_n += 2; - - data_n = _gcry_ac_data_length (data); - for (i = 0; i < data_n; i++) - { - err = gcry_ac_data_get_index (data, 0, i, &label, NULL); - if (err) - break; - /* For each MPI we add "(<LABEL> %m)". */ - sexp_buffer_n += 1 + strlen (label) + 4; - } - if (err) - goto out; - - /* Allocate buffer. */ - - sexp_buffer = gcry_malloc (sexp_buffer_n); - if (! sexp_buffer) - { - err = gcry_error_from_errno (errno); - goto out; - } - - /* Fill buffer. */ - - *sexp_buffer = 0; - sexp_buffer_n = 0; - - /* Add identifiers: (<IDENTIFIER0>(<IDENTIFIER1>...)). */ - if (identifiers_n) - { - /* Add nested identifier lists as usual. */ - for (i = 0; i < identifiers_n; i++) - sexp_buffer_n += sprintf (sexp_buffer + sexp_buffer_n, "(%s", - identifiers[i]); - } - else - { - /* Add special list. */ - sexp_buffer_n += sprintf (sexp_buffer + sexp_buffer_n, "("); - } - - /* Add MPI list. */ - arg_list = gcry_malloc (sizeof (*arg_list) * (data_n + 1)); - if (! arg_list) - { - err = gcry_error_from_errno (errno); - goto out; - } - for (i = 0; i < data_n; i++) - { - err = gcry_ac_data_get_index (data, 0, i, &label, &mpi); - if (err) - break; - sexp_buffer_n += sprintf (sexp_buffer + sexp_buffer_n, - "(%s %%m)", label); - arg_list[i] = &data->data[i].mpi; - } - if (err) - goto out; - - if (identifiers_n) - { - /* Add closing braces for identifier lists as usual. */ - for (i = 0; i < identifiers_n; i++) - sexp_buffer_n += sprintf (sexp_buffer + sexp_buffer_n, ")"); - } - else - { - /* Add closing braces for special list. */ - sexp_buffer_n += sprintf (sexp_buffer + sexp_buffer_n, ")"); - } - - /* Construct. */ - err = gcry_sexp_build_array (&sexp_new, NULL, sexp_buffer, arg_list); - if (err) - goto out; - - *sexp = sexp_new; - - out: - - gcry_free (sexp_buffer); - gcry_free (arg_list); - - return err; -} - -/* Create a new data set, which is to be stored in DATA_SET, from the - S-Expression SEXP, according to the identifiers contained in - IDENTIFIERS. */ -gcry_error_t -_gcry_ac_data_from_sexp (gcry_ac_data_t *data_set, gcry_sexp_t sexp, - const char **identifiers) -{ - gcry_ac_data_t data_set_new; - gcry_error_t err; - gcry_sexp_t sexp_cur; - gcry_sexp_t sexp_tmp; - gcry_mpi_t mpi; - char *string; - const char *data; - size_t data_n; - size_t sexp_n; - unsigned int i; - int skip_name; - - data_set_new = NULL; - sexp_cur = sexp; - sexp_tmp = NULL; - string = NULL; - mpi = NULL; - err = 0; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - /* Process S-expression/identifiers. */ - - if (identifiers) - { - for (i = 0; identifiers[i]; i++) - { - /* Next identifier. Extract first data item from - SEXP_CUR. */ - data = gcry_sexp_nth_data (sexp_cur, 0, &data_n); - - if (! ((data_n == strlen (identifiers[i])) - && (! strncmp (data, identifiers[i], data_n)))) - { - /* Identifier mismatch -> error. */ - err = gcry_error (GPG_ERR_INV_SEXP); - break; - } - - /* Identifier matches. Now we have to distinguish two - cases: - - (i) we are at the last identifier: - leave loop - - (ii) we are not at the last identifier: - extract next element, which is supposed to be a - sublist. */ - - if (! identifiers[i + 1]) - /* Last identifier. */ - break; - else - { - /* Not the last identifier, extract next sublist. */ - - sexp_tmp = gcry_sexp_nth (sexp_cur, 1); - if (! sexp_tmp) - { - /* Missing sublist. */ - err = gcry_error (GPG_ERR_INV_SEXP); - break; - } - - /* Release old SEXP_CUR, in case it is not equal to the - original SEXP. */ - if (sexp_cur != sexp) - gcry_sexp_release (sexp_cur); - - /* Make SEXP_CUR point to the new current sublist. */ - sexp_cur = sexp_tmp; - sexp_tmp = NULL; - } - } - if (err) - goto out; - - if (i) - { - /* We have at least one identifier in the list, this means - the the list of named MPI values is prefixed, this means - that we need to skip the first item (the list name), when - processing the MPI values. */ - skip_name = 1; - } - else - { - /* Since there is no identifiers list, the list of named MPI - values is not prefixed with a list name, therefore the - offset to use is zero. */ - skip_name = 0; - } - } - else - /* Since there is no identifiers list, the list of named MPI - values is not prefixed with a list name, therefore the offset - to use is zero. */ - skip_name = 0; - - /* Create data set from S-expression data. */ - - err = gcry_ac_data_new (&data_set_new); - if (err) - goto out; - - /* Figure out amount of named MPIs in SEXP_CUR. */ - if (sexp_cur) - sexp_n = gcry_sexp_length (sexp_cur) - skip_name; - else - sexp_n = 0; - - /* Extracte the named MPIs sequentially. */ - for (i = 0; i < sexp_n; i++) - { - /* Store next S-Expression pair, which is supposed to consist of - a name and an MPI value, in SEXP_TMP. */ - - sexp_tmp = gcry_sexp_nth (sexp_cur, i + skip_name); - if (! sexp_tmp) - { - err = gcry_error (GPG_ERR_INV_SEXP); - break; - } - - /* Extract name from current S-Expression pair. */ - data = gcry_sexp_nth_data (sexp_tmp, 0, &data_n); - string = gcry_malloc (data_n + 1); - if (! string) - { - err = gcry_error_from_errno (errno); - break; - } - memcpy (string, data, data_n); - string[data_n] = 0; - - /* Extract MPI value. */ - mpi = gcry_sexp_nth_mpi (sexp_tmp, 1, 0); - if (! mpi) - { - err = gcry_error (GPG_ERR_INV_SEXP); /* FIXME? */ - break; - } - - /* Store named MPI in data_set_new. */ - err = gcry_ac_data_set (data_set_new, GCRY_AC_FLAG_DEALLOC, string, mpi); - if (err) - break; - -/* gcry_free (string); */ - string = NULL; -/* gcry_mpi_release (mpi); */ - mpi = NULL; - - gcry_sexp_release (sexp_tmp); - sexp_tmp = NULL; - } - if (err) - goto out; - - *data_set = data_set_new; - - out: - - if (sexp_cur != sexp) - gcry_sexp_release (sexp_cur); - gcry_sexp_release (sexp_tmp); - gcry_mpi_release (mpi); - gcry_free (string); - - if (err) - gcry_ac_data_destroy (data_set_new); - - return err; -} - - -static void -_gcry_ac_data_dump (const char *prefix, gcry_ac_data_t data) -{ - unsigned char *mpi_buffer; - size_t mpi_buffer_n; - unsigned int data_n; - gcry_error_t err; - const char *name; - gcry_mpi_t mpi; - unsigned int i; - - if (! data) - return; - - if (fips_mode ()) - return; - - mpi_buffer = NULL; - - data_n = _gcry_ac_data_length (data); - for (i = 0; i < data_n; i++) - { - err = gcry_ac_data_get_index (data, 0, i, &name, &mpi); - if (err) - { - log_error ("failed to dump data set"); - break; - } - - err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, &mpi_buffer, &mpi_buffer_n, mpi); - if (err) - { - log_error ("failed to dump data set"); - break; - } - - log_printf ("%s%s%s: %s\n", - prefix ? prefix : "", - prefix ? ": " : "" - , name, mpi_buffer); - - gcry_free (mpi_buffer); - mpi_buffer = NULL; - } - - gcry_free (mpi_buffer); -} - -/* Dump the named MPI values contained in the data set DATA to - Libgcrypt's logging stream. */ -void -gcry_ac_data_dump (const char *prefix, gcry_ac_data_t data) -{ - _gcry_ac_data_dump (prefix, data); -} - -/* Destroys any values contained in the data set DATA. */ -void -_gcry_ac_data_clear (gcry_ac_data_t data) -{ - ac_data_values_destroy (data); - gcry_free (data->data); - data->data = NULL; - data->data_n = 0; -} - - - -/* - * Implementation of `ac io' objects. - */ - -/* Initialize AC_IO according to MODE, TYPE and the variable list of - arguments AP. The list of variable arguments to specify depends on - the given TYPE. */ -void -_gcry_ac_io_init_va (gcry_ac_io_t *ac_io, - gcry_ac_io_mode_t mode, gcry_ac_io_type_t type, va_list ap) -{ - memset (ac_io, 0, sizeof (*ac_io)); - - if (fips_mode ()) - return; - - gcry_assert ((mode == GCRY_AC_IO_READABLE) || (mode == GCRY_AC_IO_WRITABLE)); - gcry_assert ((type == GCRY_AC_IO_STRING) || (type == GCRY_AC_IO_STRING)); - - ac_io->mode = mode; - ac_io->type = type; - - switch (mode) - { - case GCRY_AC_IO_READABLE: - switch (type) - { - case GCRY_AC_IO_STRING: - ac_io->io.readable.string.data = va_arg (ap, unsigned char *); - ac_io->io.readable.string.data_n = va_arg (ap, size_t); - break; - - case GCRY_AC_IO_CALLBACK: - ac_io->io.readable.callback.cb = va_arg (ap, gcry_ac_data_read_cb_t); - ac_io->io.readable.callback.opaque = va_arg (ap, void *); - break; - } - break; - case GCRY_AC_IO_WRITABLE: - switch (type) - { - case GCRY_AC_IO_STRING: - ac_io->io.writable.string.data = va_arg (ap, unsigned char **); - ac_io->io.writable.string.data_n = va_arg (ap, size_t *); - break; - - case GCRY_AC_IO_CALLBACK: - ac_io->io.writable.callback.cb = va_arg (ap, gcry_ac_data_write_cb_t); - ac_io->io.writable.callback.opaque = va_arg (ap, void *); - break; - } - break; - } -} - -/* Initialize AC_IO according to MODE, TYPE and the variable list of - arguments. The list of variable arguments to specify depends on - the given TYPE. */ -void -_gcry_ac_io_init (gcry_ac_io_t *ac_io, - gcry_ac_io_mode_t mode, gcry_ac_io_type_t type, ...) -{ - va_list ap; - - va_start (ap, type); - _gcry_ac_io_init_va (ac_io, mode, type, ap); - va_end (ap); -} - - -/* Write to the IO object AC_IO BUFFER_N bytes from BUFFER. Return - zero on success or error code. */ -static gcry_error_t -_gcry_ac_io_write (gcry_ac_io_t *ac_io, unsigned char *buffer, size_t buffer_n) -{ - gcry_error_t err; - - gcry_assert (ac_io->mode == GCRY_AC_IO_WRITABLE); - err = 0; - - switch (ac_io->type) - { - case GCRY_AC_IO_STRING: - { - unsigned char *p; - - if (*ac_io->io.writable.string.data) - { - p = gcry_realloc (*ac_io->io.writable.string.data, - *ac_io->io.writable.string.data_n + buffer_n); - if (! p) - err = gcry_error_from_errno (errno); - else - { - if (*ac_io->io.writable.string.data != p) - *ac_io->io.writable.string.data = p; - memcpy (p + *ac_io->io.writable.string.data_n, buffer, buffer_n); - *ac_io->io.writable.string.data_n += buffer_n; - } - } - else - { - if (gcry_is_secure (buffer)) - p = gcry_malloc_secure (buffer_n); - else - p = gcry_malloc (buffer_n); - if (! p) - err = gcry_error_from_errno (errno); - else - { - memcpy (p, buffer, buffer_n); - *ac_io->io.writable.string.data = p; - *ac_io->io.writable.string.data_n = buffer_n; - } - } - } - break; - - case GCRY_AC_IO_CALLBACK: - err = (*ac_io->io.writable.callback.cb) (ac_io->io.writable.callback.opaque, - buffer, buffer_n); - break; - } - - return err; -} - -/* Read *BUFFER_N bytes from the IO object AC_IO into BUFFER; NREAD - bytes have already been read from the object; on success, store the - amount of bytes read in *BUFFER_N; zero bytes read means EOF. - Return zero on success or error code. */ -static gcry_error_t -_gcry_ac_io_read (gcry_ac_io_t *ac_io, - unsigned int nread, unsigned char *buffer, size_t *buffer_n) -{ - gcry_error_t err; - - gcry_assert (ac_io->mode == GCRY_AC_IO_READABLE); - err = 0; - - switch (ac_io->type) - { - case GCRY_AC_IO_STRING: - { - size_t bytes_available; - size_t bytes_to_read; - size_t bytes_wanted; - - bytes_available = ac_io->io.readable.string.data_n - nread; - bytes_wanted = *buffer_n; - - if (bytes_wanted > bytes_available) - bytes_to_read = bytes_available; - else - bytes_to_read = bytes_wanted; - - memcpy (buffer, ac_io->io.readable.string.data + nread, bytes_to_read); - *buffer_n = bytes_to_read; - err = 0; - break; - } - - case GCRY_AC_IO_CALLBACK: - err = (*ac_io->io.readable.callback.cb) - (ac_io->io.readable.callback.opaque, buffer, buffer_n); - break; - } - - return err; -} - -/* Read all data available from the IO object AC_IO into newly - allocated memory, storing an appropriate pointer in *BUFFER and the - amount of bytes read in *BUFFER_N. Return zero on success or error - code. */ -static gcry_error_t -_gcry_ac_io_read_all (gcry_ac_io_t *ac_io, unsigned char **buffer, size_t *buffer_n) -{ - unsigned char *buffer_new; - size_t buffer_new_n; - unsigned char buf[BUFSIZ]; - size_t buf_n; - unsigned char *p; - gcry_error_t err; - - buffer_new = NULL; - buffer_new_n = 0; - - while (1) - { - buf_n = sizeof (buf); - err = _gcry_ac_io_read (ac_io, buffer_new_n, buf, &buf_n); - if (err) - break; - - if (buf_n) - { - p = gcry_realloc (buffer_new, buffer_new_n + buf_n); - if (! p) - { - err = gcry_error_from_errno (errno); - break; - } - - if (buffer_new != p) - buffer_new = p; - - memcpy (buffer_new + buffer_new_n, buf, buf_n); - buffer_new_n += buf_n; - } - else - break; - } - if (err) - goto out; - - *buffer_n = buffer_new_n; - *buffer = buffer_new; - - out: - - if (err) - gcry_free (buffer_new); - - return err; -} - -/* Read data chunks from the IO object AC_IO until EOF, feeding them - to the callback function CB. Return zero on success or error - code. */ -static gcry_error_t -_gcry_ac_io_process (gcry_ac_io_t *ac_io, - gcry_ac_data_write_cb_t cb, void *opaque) -{ - unsigned char buffer[BUFSIZ]; - unsigned int nread; - size_t buffer_n; - gcry_error_t err; - - nread = 0; - - while (1) - { - buffer_n = sizeof (buffer); - err = _gcry_ac_io_read (ac_io, nread, buffer, &buffer_n); - if (err) - break; - if (buffer_n) - { - err = (*cb) (opaque, buffer, buffer_n); - if (err) - break; - nread += buffer_n; - } - else - break; - } - - return err; -} - - - -/* - * Functions for converting data between the native ac and the - * S-expression structure used by the pk interface. - */ - -/* Extract the S-Expression DATA_SEXP into DATA under the control of - TYPE and NAME. This function assumes that S-Expressions are of the - following structure: - - (IDENTIFIER [...] - (ALGORITHM <list of named MPI values>)) */ -static gcry_error_t -ac_data_extract (const char *identifier, const char *algorithm, - gcry_sexp_t sexp, gcry_ac_data_t *data) -{ - gcry_error_t err; - gcry_sexp_t value_sexp; - gcry_sexp_t data_sexp; - size_t data_sexp_n; - gcry_mpi_t value_mpi; - char *value_name; - const char *data_raw; - size_t data_raw_n; - gcry_ac_data_t data_new; - unsigned int i; - - value_sexp = NULL; - data_sexp = NULL; - value_name = NULL; - value_mpi = NULL; - data_new = NULL; - - /* Verify that the S-expression contains the correct identifier. */ - data_raw = gcry_sexp_nth_data (sexp, 0, &data_raw_n); - if ((! data_raw) || strncmp (identifier, data_raw, data_raw_n)) - { - err = gcry_error (GPG_ERR_INV_SEXP); - goto out; - } - - /* Extract inner S-expression. */ - data_sexp = gcry_sexp_find_token (sexp, algorithm, 0); - if (! data_sexp) - { - err = gcry_error (GPG_ERR_INV_SEXP); - goto out; - } - - /* Count data elements. */ - data_sexp_n = gcry_sexp_length (data_sexp); - data_sexp_n--; - - /* Allocate new data set. */ - err = _gcry_ac_data_new (&data_new); - if (err) - goto out; - - /* Iterate through list of data elements and add them to the data - set. */ - for (i = 0; i < data_sexp_n; i++) - { - /* Get the S-expression of the named MPI, that contains the name - and the MPI value. */ - value_sexp = gcry_sexp_nth (data_sexp, i + 1); - if (! value_sexp) - { - err = gcry_error (GPG_ERR_INV_SEXP); - break; - } - - /* Extract the name. */ - data_raw = gcry_sexp_nth_data (value_sexp, 0, &data_raw_n); - if (! data_raw) - { - err = gcry_error (GPG_ERR_INV_SEXP); - break; - } - - /* Extract the MPI value. */ - value_mpi = gcry_sexp_nth_mpi (value_sexp, 1, GCRYMPI_FMT_USG); - if (! value_mpi) - { - err = gcry_error (GPG_ERR_INTERNAL); /* FIXME? */ - break; - } - - /* Duplicate the name. */ - value_name = gcry_malloc (data_raw_n + 1); - if (! value_name) - { - err = gcry_error_from_errno (errno); - break; - } - strncpy (value_name, data_raw, data_raw_n); - value_name[data_raw_n] = 0; - - err = _gcry_ac_data_set (data_new, GCRY_AC_FLAG_DEALLOC, value_name, value_mpi); - if (err) - break; - - gcry_sexp_release (value_sexp); - value_sexp = NULL; - value_name = NULL; - value_mpi = NULL; - } - if (err) - goto out; - - /* Copy out. */ - *data = data_new; - - out: - - /* Deallocate resources. */ - if (err) - { - _gcry_ac_data_destroy (data_new); - gcry_mpi_release (value_mpi); - gcry_free (value_name); - gcry_sexp_release (value_sexp); - } - gcry_sexp_release (data_sexp); - - return err; -} - -/* Construct an S-expression from the DATA and store it in - DATA_SEXP. The S-expression will be of the following structure: - - (IDENTIFIER [(flags [...])] - (ALGORITHM <list of named MPI values>)) */ -static gcry_error_t -ac_data_construct (const char *identifier, int include_flags, - unsigned int flags, const char *algorithm, - gcry_ac_data_t data, gcry_sexp_t *sexp) -{ - unsigned int data_length; - gcry_sexp_t sexp_new; - gcry_error_t err; - size_t sexp_format_n; - char *sexp_format; - void **arg_list; - unsigned int i; - - arg_list = NULL; - sexp_new = NULL; - sexp_format = NULL; - - /* We build a list of arguments to pass to - gcry_sexp_build_array(). */ - data_length = _gcry_ac_data_length (data); - arg_list = gcry_malloc (sizeof (*arg_list) * (data_length * 2)); - if (! arg_list) - { - err = gcry_error_from_errno (errno); - goto out; - } - - /* Fill list with MPIs. */ - for (i = 0; i < data_length; i++) - { - char **nameaddr = &data->data[i].name; - - arg_list[(i * 2) + 0] = nameaddr; - arg_list[(i * 2) + 1] = &data->data[i].mpi; - } - - /* Calculate size of format string. */ - sexp_format_n = (3 - + (include_flags ? 7 : 0) - + (algorithm ? (2 + strlen (algorithm)) : 0) - + strlen (identifier)); - - for (i = 0; i < data_length; i++) - /* Per-element sizes. */ - sexp_format_n += 6; - - if (include_flags) - /* Add flags. */ - for (i = 0; i < DIM (ac_flags); i++) - if (flags & ac_flags[i].number) - sexp_format_n += strlen (ac_flags[i].string) + 1; - - /* Done. */ - sexp_format = gcry_malloc (sexp_format_n); - if (! sexp_format) - { - err = gcry_error_from_errno (errno); - goto out; - } - - /* Construct the format string. */ - - *sexp_format = 0; - strcat (sexp_format, "("); - strcat (sexp_format, identifier); - if (include_flags) - { - strcat (sexp_format, "(flags"); - for (i = 0; i < DIM (ac_flags); i++) - if (flags & ac_flags[i].number) - { - strcat (sexp_format, " "); - strcat (sexp_format, ac_flags[i].string); - } - strcat (sexp_format, ")"); - } - if (algorithm) - { - strcat (sexp_format, "("); - strcat (sexp_format, algorithm); - } - for (i = 0; i < data_length; i++) - strcat (sexp_format, "(%s%m)"); - if (algorithm) - strcat (sexp_format, ")"); - strcat (sexp_format, ")"); - - /* Create final S-expression. */ - err = gcry_sexp_build_array (&sexp_new, NULL, sexp_format, arg_list); - if (err) - goto out; - - *sexp = sexp_new; - - out: - - /* Deallocate resources. */ - gcry_free (sexp_format); - gcry_free (arg_list); - if (err) - gcry_sexp_release (sexp_new); - - return err; -} - - - -/* - * Handle management. - */ - -/* Creates a new handle for the algorithm ALGORITHM and stores it in - HANDLE. FLAGS is not used yet. */ -gcry_error_t -_gcry_ac_open (gcry_ac_handle_t *handle, - gcry_ac_id_t algorithm, unsigned int flags) -{ - gcry_ac_handle_t handle_new; - const char *algorithm_name; - gcry_module_t module; - gcry_error_t err; - - *handle = NULL; - module = NULL; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - /* Get name. */ - algorithm_name = _gcry_pk_aliased_algo_name (algorithm); - if (! algorithm_name) - { - err = gcry_error (GPG_ERR_PUBKEY_ALGO); - goto out; - } - - /* Acquire reference to the pubkey module. */ - err = _gcry_pk_module_lookup (algorithm, &module); - if (err) - goto out; - - /* Allocate. */ - handle_new = gcry_malloc (sizeof (*handle_new)); - if (! handle_new) - { - err = gcry_error_from_errno (errno); - goto out; - } - - /* Done. */ - handle_new->algorithm = algorithm; - handle_new->algorithm_name = algorithm_name; - handle_new->flags = flags; - handle_new->module = module; - *handle = handle_new; - - out: - - /* Deallocate resources. */ - if (err) - _gcry_pk_module_release (module); - - return err; -} - - -/* Destroys the handle HANDLE. */ -void -_gcry_ac_close (gcry_ac_handle_t handle) -{ - /* Release reference to pubkey module. */ - if (handle) - { - _gcry_pk_module_release (handle->module); - gcry_free (handle); - } -} - - - -/* - * Key management. - */ - -/* Initialize a key from a given data set. */ -/* FIXME/Damn: the argument HANDLE is not only unnecessary, it is - completely WRONG here. */ -gcry_error_t -_gcry_ac_key_init (gcry_ac_key_t *key, gcry_ac_handle_t handle, - gcry_ac_key_type_t type, gcry_ac_data_t data) -{ - gcry_ac_data_t data_new; - gcry_ac_key_t key_new; - gcry_error_t err; - - (void)handle; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - /* Allocate. */ - key_new = gcry_malloc (sizeof (*key_new)); - if (! key_new) - { - err = gcry_error_from_errno (errno); - goto out; - } - - /* Copy data set. */ - err = _gcry_ac_data_copy (&data_new, data); - if (err) - goto out; - - /* Done. */ - key_new->data = data_new; - key_new->type = type; - *key = key_new; - - out: - - if (err) - /* Deallocate resources. */ - gcry_free (key_new); - - return err; -} - - -/* Generates a new key pair via the handle HANDLE of NBITS bits and - stores it in KEY_PAIR. In case non-standard settings are wanted, a - pointer to a structure of type gcry_ac_key_spec_<algorithm>_t, - matching the selected algorithm, can be given as KEY_SPEC. - MISC_DATA is not used yet. */ -gcry_error_t -_gcry_ac_key_pair_generate (gcry_ac_handle_t handle, unsigned int nbits, - void *key_spec, - gcry_ac_key_pair_t *key_pair, - gcry_mpi_t **misc_data) -{ - gcry_sexp_t genkey_sexp_request; - gcry_sexp_t genkey_sexp_reply; - gcry_ac_data_t key_data_secret; - gcry_ac_data_t key_data_public; - gcry_ac_key_pair_t key_pair_new; - gcry_ac_key_t key_secret; - gcry_ac_key_t key_public; - gcry_sexp_t key_sexp; - gcry_error_t err; - char *genkey_format; - size_t genkey_format_n; - void **arg_list; - size_t arg_list_n; - unsigned int i; - unsigned int j; - - (void)misc_data; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - key_data_secret = NULL; - key_data_public = NULL; - key_secret = NULL; - key_public = NULL; - genkey_format = NULL; - arg_list = NULL; - genkey_sexp_request = NULL; - genkey_sexp_reply = NULL; - key_sexp = NULL; - - /* Allocate key pair. */ - key_pair_new = gcry_malloc (sizeof (struct gcry_ac_key_pair)); - if (! key_pair_new) - { - err = gcry_error_from_errno (errno); - goto out; - } - - /* Allocate keys. */ - key_secret = gcry_malloc (sizeof (*key_secret)); - if (! key_secret) - { - err = gcry_error_from_errno (errno); - goto out; - } - key_public = gcry_malloc (sizeof (*key_public)); - if (! key_public) - { - err = gcry_error_from_errno (errno); - goto out; - } - - /* Calculate size of the format string, that is used for creating - the request S-expression. */ - genkey_format_n = 22; - - /* Respect any relevant algorithm specific commands. */ - if (key_spec) - for (i = 0; i < DIM (ac_key_generate_specs); i++) - if (handle->algorithm == ac_key_generate_specs[i].algorithm) - genkey_format_n += 6; - - /* Create format string. */ - genkey_format = gcry_malloc (genkey_format_n); - if (! genkey_format) - { - err = gcry_error_from_errno (errno); - goto out; - } - - /* Fill format string. */ - *genkey_format = 0; - strcat (genkey_format, "(genkey(%s(nbits%d)"); - if (key_spec) - for (i = 0; i < DIM (ac_key_generate_specs); i++) - if (handle->algorithm == ac_key_generate_specs[i].algorithm) - strcat (genkey_format, "(%s%m)"); - strcat (genkey_format, "))"); - - /* Build list of argument pointers, the algorithm name and the nbits - are always needed. */ - arg_list_n = 2; - - /* Now the algorithm specific arguments. */ - if (key_spec) - for (i = 0; i < DIM (ac_key_generate_specs); i++) - if (handle->algorithm == ac_key_generate_specs[i].algorithm) - arg_list_n += 2; - - /* Allocate list. */ - arg_list = gcry_malloc (sizeof (*arg_list) * arg_list_n); - if (! arg_list) - { - err = gcry_error_from_errno (errno); - goto out; - } - - arg_list[0] = (void *) &handle->algorithm_name; - arg_list[1] = (void *) &nbits; - if (key_spec) - for (j = 2, i = 0; i < DIM (ac_key_generate_specs); i++) - if (handle->algorithm == ac_key_generate_specs[i].algorithm) - { - /* Add name of this specification flag and the - according member of the spec strucuture. */ - arg_list[j++] = (void *)(&ac_key_generate_specs[i].name); - arg_list[j++] = (void *) - (((char *) key_spec) - + ac_key_generate_specs[i].offset); - /* FIXME: above seems to suck. */ - } - - /* Construct final request S-expression. */ - err = gcry_sexp_build_array (&genkey_sexp_request, - NULL, genkey_format, arg_list); - if (err) - goto out; - - /* Perform genkey operation. */ - err = gcry_pk_genkey (&genkey_sexp_reply, genkey_sexp_request); - if (err) - goto out; - - key_sexp = gcry_sexp_find_token (genkey_sexp_reply, "private-key", 0); - if (! key_sexp) - { - err = gcry_error (GPG_ERR_INTERNAL); - goto out; - } - err = ac_data_extract ("private-key", handle->algorithm_name, - key_sexp, &key_data_secret); - if (err) - goto out; - - gcry_sexp_release (key_sexp); - key_sexp = gcry_sexp_find_token (genkey_sexp_reply, "public-key", 0); - if (! key_sexp) - { - err = gcry_error (GPG_ERR_INTERNAL); - goto out; - } - err = ac_data_extract ("public-key", handle->algorithm_name, - key_sexp, &key_data_public); - if (err) - goto out; - - /* Done. */ - - key_secret->type = GCRY_AC_KEY_SECRET; - key_secret->data = key_data_secret; - key_public->type = GCRY_AC_KEY_PUBLIC; - key_public->data = key_data_public; - key_pair_new->secret = key_secret; - key_pair_new->public = key_public; - *key_pair = key_pair_new; - - out: - - /* Deallocate resources. */ - - gcry_free (genkey_format); - gcry_free (arg_list); - gcry_sexp_release (genkey_sexp_request); - gcry_sexp_release (genkey_sexp_reply); - gcry_sexp_release (key_sexp); - if (err) - { - _gcry_ac_data_destroy (key_data_secret); - _gcry_ac_data_destroy (key_data_public); - gcry_free (key_secret); - gcry_free (key_public); - gcry_free (key_pair_new); - } - - return err; -} - -/* Returns the key of type WHICH out of the key pair KEY_PAIR. */ -gcry_ac_key_t -_gcry_ac_key_pair_extract (gcry_ac_key_pair_t key_pair, - gcry_ac_key_type_t which) -{ - gcry_ac_key_t key; - - if (fips_mode ()) - return NULL; - - switch (which) - { - case GCRY_AC_KEY_SECRET: - key = key_pair->secret; - break; - - case GCRY_AC_KEY_PUBLIC: - key = key_pair->public; - break; - - default: - key = NULL; - break; - } - - return key; -} - -/* Destroys the key KEY. */ -void -_gcry_ac_key_destroy (gcry_ac_key_t key) -{ - unsigned int i; - - if (key) - { - if (key->data) - { - for (i = 0; i < key->data->data_n; i++) - { - if (key->data->data[i].mpi) - gcry_mpi_release (key->data->data[i].mpi); - if (key->data->data[i].name) - gcry_free (key->data->data[i].name); - } - gcry_free (key->data->data); - gcry_free (key->data); - } - gcry_free (key); - } -} - -/* Destroys the key pair KEY_PAIR. */ -void -_gcry_ac_key_pair_destroy (gcry_ac_key_pair_t key_pair) -{ - if (key_pair) - { - gcry_ac_key_destroy (key_pair->secret); - gcry_ac_key_destroy (key_pair->public); - gcry_free (key_pair); - } -} - -/* Returns the data set contained in the key KEY. */ -gcry_ac_data_t -_gcry_ac_key_data_get (gcry_ac_key_t key) -{ - if (fips_mode ()) - return NULL; - return key->data; -} - -/* Verifies that the key KEY is sane via HANDLE. */ -gcry_error_t -_gcry_ac_key_test (gcry_ac_handle_t handle, gcry_ac_key_t key) -{ - gcry_sexp_t key_sexp; - gcry_error_t err; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - key_sexp = NULL; - err = ac_data_construct (ac_key_identifiers[key->type], 0, 0, - handle->algorithm_name, key->data, &key_sexp); - if (err) - goto out; - - err = gcry_pk_testkey (key_sexp); - - out: - - gcry_sexp_release (key_sexp); - - return gcry_error (err); -} - -/* Stores the number of bits of the key KEY in NBITS via HANDLE. */ -gcry_error_t -_gcry_ac_key_get_nbits (gcry_ac_handle_t handle, - gcry_ac_key_t key, unsigned int *nbits) -{ - gcry_sexp_t key_sexp; - gcry_error_t err; - unsigned int n; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - key_sexp = NULL; - - err = ac_data_construct (ac_key_identifiers[key->type], - 0, 0, handle->algorithm_name, key->data, &key_sexp); - if (err) - goto out; - - n = gcry_pk_get_nbits (key_sexp); - if (! n) - { - err = gcry_error (GPG_ERR_PUBKEY_ALGO); - goto out; - } - - *nbits = n; - - out: - - gcry_sexp_release (key_sexp); - - return err; -} - -/* Writes the 20 byte long key grip of the key KEY to KEY_GRIP via - HANDLE. */ -gcry_error_t -_gcry_ac_key_get_grip (gcry_ac_handle_t handle, - gcry_ac_key_t key, unsigned char *key_grip) -{ - gcry_sexp_t key_sexp; - gcry_error_t err; - unsigned char *ret; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - key_sexp = NULL; - err = ac_data_construct (ac_key_identifiers[key->type], 0, 0, - handle->algorithm_name, key->data, &key_sexp); - if (err) - goto out; - - ret = gcry_pk_get_keygrip (key_sexp, key_grip); - if (! ret) - { - err = gcry_error (GPG_ERR_INV_OBJ); - goto out; - } - - err = 0; - - out: - - gcry_sexp_release (key_sexp); - - return err; -} - - - - -/* - * Functions performing cryptographic operations. - */ - -/* Encrypts the plain text MPI value DATA_PLAIN with the key public - KEY under the control of the flags FLAGS and stores the resulting - data set into DATA_ENCRYPTED. */ -gcry_error_t -_gcry_ac_data_encrypt (gcry_ac_handle_t handle, - unsigned int flags, - gcry_ac_key_t key, - gcry_mpi_t data_plain, - gcry_ac_data_t *data_encrypted) -{ - gcry_ac_data_t data_encrypted_new; - gcry_ac_data_t data_value; - gcry_sexp_t sexp_request; - gcry_sexp_t sexp_reply; - gcry_sexp_t sexp_key; - gcry_error_t err; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - data_encrypted_new = NULL; - sexp_request = NULL; - sexp_reply = NULL; - data_value = NULL; - sexp_key = NULL; - - if (key->type != GCRY_AC_KEY_PUBLIC) - { - err = gcry_error (GPG_ERR_WRONG_KEY_USAGE); - goto out; - } - - err = ac_data_construct (ac_key_identifiers[key->type], 0, 0, - handle->algorithm_name, key->data, &sexp_key); - if (err) - goto out; - - err = _gcry_ac_data_new (&data_value); - if (err) - goto out; - - err = _gcry_ac_data_set (data_value, 0, "value", data_plain); - if (err) - goto out; - - err = ac_data_construct ("data", 1, flags, handle->algorithm_name, - data_value, &sexp_request); - if (err) - goto out; - - /* FIXME: error vs. errcode? */ - - err = gcry_pk_encrypt (&sexp_reply, sexp_request, sexp_key); - if (err) - goto out; - - /* Extract data. */ - err = ac_data_extract ("enc-val", handle->algorithm_name, - sexp_reply, &data_encrypted_new); - if (err) - goto out; - - *data_encrypted = data_encrypted_new; - - out: - - /* Deallocate resources. */ - - gcry_sexp_release (sexp_request); - gcry_sexp_release (sexp_reply); - gcry_sexp_release (sexp_key); - _gcry_ac_data_destroy (data_value); - - return err; -} - -/* Decrypts the encrypted data contained in the data set - DATA_ENCRYPTED with the secret key KEY under the control of the - flags FLAGS and stores the resulting plain text MPI value in - DATA_PLAIN. */ -gcry_error_t -_gcry_ac_data_decrypt (gcry_ac_handle_t handle, - unsigned int flags, - gcry_ac_key_t key, - gcry_mpi_t *data_plain, - gcry_ac_data_t data_encrypted) -{ - gcry_mpi_t data_decrypted; - gcry_sexp_t sexp_request; - gcry_sexp_t sexp_reply; - gcry_sexp_t sexp_value; - gcry_sexp_t sexp_key; - gcry_error_t err; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - sexp_request = NULL; - sexp_reply = NULL; - sexp_value = NULL; - sexp_key = NULL; - - if (key->type != GCRY_AC_KEY_SECRET) - { - err = gcry_error (GPG_ERR_WRONG_KEY_USAGE); - goto out; - } - - err = ac_data_construct (ac_key_identifiers[key->type], 0, 0, - handle->algorithm_name, key->data, &sexp_key); - if (err) - goto out; - - /* Create S-expression from data. */ - err = ac_data_construct ("enc-val", 1, flags, handle->algorithm_name, - data_encrypted, &sexp_request); - if (err) - goto out; - - /* Decrypt. */ - err = gcry_pk_decrypt (&sexp_reply, sexp_request, sexp_key); - if (err) - goto out; - - /* Extract plain text. */ - sexp_value = gcry_sexp_find_token (sexp_reply, "value", 0); - if (! sexp_value) - { - /* FIXME? */ - err = gcry_error (GPG_ERR_GENERAL); - goto out; - } - - data_decrypted = gcry_sexp_nth_mpi (sexp_value, 1, GCRYMPI_FMT_USG); - if (! data_decrypted) - { - err = gcry_error (GPG_ERR_GENERAL); - goto out; - } - - *data_plain = data_decrypted; - - out: - - /* Deallocate resources. */ - gcry_sexp_release (sexp_request); - gcry_sexp_release (sexp_reply); - gcry_sexp_release (sexp_value); - gcry_sexp_release (sexp_key); - - return gcry_error (err); - -} - -/* Signs the data contained in DATA with the secret key KEY and stores - the resulting signature data set in DATA_SIGNATURE. */ -gcry_error_t -_gcry_ac_data_sign (gcry_ac_handle_t handle, - gcry_ac_key_t key, - gcry_mpi_t data, - gcry_ac_data_t *data_signature) -{ - gcry_ac_data_t data_signed; - gcry_ac_data_t data_value; - gcry_sexp_t sexp_request; - gcry_sexp_t sexp_reply; - gcry_sexp_t sexp_key; - gcry_error_t err; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - data_signed = NULL; - data_value = NULL; - sexp_request = NULL; - sexp_reply = NULL; - sexp_key = NULL; - - if (key->type != GCRY_AC_KEY_SECRET) - { - err = gcry_error (GPG_ERR_WRONG_KEY_USAGE); - goto out; - } - - err = ac_data_construct (ac_key_identifiers[key->type], 0, 0, - handle->algorithm_name, key->data, &sexp_key); - if (err) - goto out; - - err = _gcry_ac_data_new (&data_value); - if (err) - goto out; - - err = _gcry_ac_data_set (data_value, 0, "value", data); - if (err) - goto out; - - /* Create S-expression holding the data. */ - err = ac_data_construct ("data", 1, 0, NULL, data_value, &sexp_request); - if (err) - goto out; - - /* Sign. */ - err = gcry_pk_sign (&sexp_reply, sexp_request, sexp_key); - if (err) - goto out; - - /* Extract data. */ - err = ac_data_extract ("sig-val", handle->algorithm_name, - sexp_reply, &data_signed); - if (err) - goto out; - - /* Done. */ - *data_signature = data_signed; - - out: - - gcry_sexp_release (sexp_request); - gcry_sexp_release (sexp_reply); - gcry_sexp_release (sexp_key); - _gcry_ac_data_destroy (data_value); - - return gcry_error (err); -} - - -/* Verifies that the signature contained in the data set - DATA_SIGNATURE is indeed the result of signing the data contained - in DATA with the secret key belonging to the public key KEY. */ -gcry_error_t -_gcry_ac_data_verify (gcry_ac_handle_t handle, - gcry_ac_key_t key, - gcry_mpi_t data, - gcry_ac_data_t data_signature) -{ - gcry_sexp_t sexp_signature; - gcry_ac_data_t data_value; - gcry_sexp_t sexp_data; - gcry_sexp_t sexp_key; - gcry_error_t err; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - sexp_signature = NULL; - data_value = NULL; - sexp_data = NULL; - sexp_key = NULL; - - err = ac_data_construct ("public-key", 0, 0, - handle->algorithm_name, key->data, &sexp_key); - if (err) - goto out; - - if (key->type != GCRY_AC_KEY_PUBLIC) - { - err = gcry_error (GPG_ERR_WRONG_KEY_USAGE); - goto out; - } - - /* Construct S-expression holding the signature data. */ - err = ac_data_construct ("sig-val", 1, 0, handle->algorithm_name, - data_signature, &sexp_signature); - if (err) - goto out; - - err = _gcry_ac_data_new (&data_value); - if (err) - goto out; - - err = _gcry_ac_data_set (data_value, 0, "value", data); - if (err) - goto out; - - /* Construct S-expression holding the data. */ - err = ac_data_construct ("data", 1, 0, NULL, data_value, &sexp_data); - if (err) - goto out; - - /* Verify signature. */ - err = gcry_pk_verify (sexp_signature, sexp_data, sexp_key); - - out: - - gcry_sexp_release (sexp_signature); - gcry_sexp_release (sexp_data); - gcry_sexp_release (sexp_key); - _gcry_ac_data_destroy (data_value); - - return gcry_error (err); -} - - - - -/* - * Implementation of encoding methods (em). - */ - -/* Type for functions that encode or decode (hence the name) a - message. */ -typedef gcry_error_t (*gcry_ac_em_dencode_t) (unsigned int flags, - void *options, - gcry_ac_io_t *ac_io_read, - gcry_ac_io_t *ac_io_write); - -/* Fill the buffer BUFFER which is BUFFER_N bytes long with non-zero - random bytes of random level LEVEL. */ -static void -em_randomize_nonzero (unsigned char *buffer, size_t buffer_n, - gcry_random_level_t level) -{ - unsigned char *buffer_rand; - unsigned int buffer_rand_n; - unsigned int zeros; - unsigned int i; - unsigned int j; - - for (i = 0; i < buffer_n; i++) - buffer[i] = 0; - - do - { - /* Count zeros. */ - for (i = zeros = 0; i < buffer_n; i++) - if (! buffer[i]) - zeros++; - - if (zeros) - { - /* Get random bytes. */ - buffer_rand_n = zeros + (zeros / 128); - buffer_rand = gcry_random_bytes_secure (buffer_rand_n, level); - - /* Substitute zeros with non-zero random bytes. */ - for (i = j = 0; zeros && (i < buffer_n) && (j < buffer_rand_n); i++) - if (! buffer[i]) - { - while ((j < buffer_rand_n) && (! buffer_rand[j])) - j++; - if (j < buffer_rand_n) - { - buffer[i] = buffer_rand[j++]; - zeros--; - } - else - break; - } - gcry_free (buffer_rand); - } - } - while (zeros); -} - -/* Encode a message according to the Encoding Method for Encryption - `PKCS-V1_5' (EME-PKCS-V1_5). */ -static gcry_error_t -eme_pkcs_v1_5_encode (unsigned int flags, void *opts, - gcry_ac_io_t *ac_io_read, - gcry_ac_io_t *ac_io_write) -{ - gcry_ac_eme_pkcs_v1_5_t *options; - gcry_error_t err; - unsigned char *buffer; - unsigned char *ps; - unsigned char *m; - size_t m_n; - unsigned int ps_n; - unsigned int k; - - (void)flags; - - options = opts; - buffer = NULL; - m = NULL; - - err = _gcry_ac_io_read_all (ac_io_read, &m, &m_n); - if (err) - goto out; - - /* Figure out key length in bytes. */ - k = options->key_size / 8; - - if (m_n > k - 11) - { - /* Key is too short for message. */ - err = gcry_error (GPG_ERR_TOO_SHORT); - goto out; - } - - /* According to this encoding method, the first byte of the encoded - message is zero. This byte will be lost anyway, when the encoded - message is to be converted into an MPI, that's why we skip - it. */ - - /* Allocate buffer. */ - buffer = gcry_malloc (k - 1); - if (! buffer) - { - err = gcry_error_from_errno (errno); - goto out; - } - - /* Generate an octet string PS of length k - mLen - 3 consisting - of pseudorandomly generated nonzero octets. The length of PS - will be at least eight octets. */ - ps_n = k - m_n - 3; - ps = buffer + 1; - em_randomize_nonzero (ps, ps_n, GCRY_STRONG_RANDOM); - - /* Concatenate PS, the message M, and other padding to form an - encoded message EM of length k octets as: - - EM = 0x00 || 0x02 || PS || 0x00 || M. */ - - buffer[0] = 0x02; - buffer[ps_n + 1] = 0x00; - memcpy (buffer + ps_n + 2, m, m_n); - - err = _gcry_ac_io_write (ac_io_write, buffer, k - 1); - - out: - - gcry_free (buffer); - gcry_free (m); - - return err; -} - -/* Decode a message according to the Encoding Method for Encryption - `PKCS-V1_5' (EME-PKCS-V1_5). */ -static gcry_error_t -eme_pkcs_v1_5_decode (unsigned int flags, void *opts, - gcry_ac_io_t *ac_io_read, - gcry_ac_io_t *ac_io_write) -{ - gcry_ac_eme_pkcs_v1_5_t *options; - unsigned char *buffer; - unsigned char *em; - size_t em_n; - gcry_error_t err; - unsigned int i; - unsigned int k; - - (void)flags; - - options = opts; - buffer = NULL; - em = NULL; - - err = _gcry_ac_io_read_all (ac_io_read, &em, &em_n); - if (err) - goto out; - - /* Figure out key size. */ - k = options->key_size / 8; - - /* Search for zero byte. */ - for (i = 0; (i < em_n) && em[i]; i++); - - /* According to this encoding method, the first byte of the encoded - message should be zero. This byte is lost. */ - - if (! ((em_n >= 10) - && (em_n == (k - 1)) - && (em[0] == 0x02) - && (i < em_n) - && ((i - 1) >= 8))) - { - err = gcry_error (GPG_ERR_DECRYPT_FAILED); - goto out; - } - - i++; - buffer = gcry_malloc (em_n - i); - if (! buffer) - { - err = gcry_error_from_errno (errno); - goto out; - } - - memcpy (buffer, em + i, em_n - i); - err = _gcry_ac_io_write (ac_io_write, buffer, em_n - i); - - out: - - gcry_free (buffer); - gcry_free (em); - - return err; -} - -static gcry_error_t -emsa_pkcs_v1_5_encode_data_cb (void *opaque, - unsigned char *buffer, size_t buffer_n) -{ - gcry_md_hd_t md_handle; - - md_handle = opaque; - gcry_md_write (md_handle, buffer, buffer_n); - - return 0; -} - - -/* Encode a message according to the Encoding Method for Signatures - with Appendix `PKCS-V1_5' (EMSA-PKCS-V1_5). */ -static gcry_error_t -emsa_pkcs_v1_5_encode (unsigned int flags, void *opts, - gcry_ac_io_t *ac_io_read, - gcry_ac_io_t *ac_io_write) -{ - gcry_ac_emsa_pkcs_v1_5_t *options; - gcry_error_t err; - gcry_md_hd_t md; - unsigned char *t; - size_t t_n; - unsigned char *h; - size_t h_n; - unsigned char *ps; - size_t ps_n; - unsigned char *buffer; - size_t buffer_n; - unsigned char asn[100]; /* FIXME, always enough? */ - size_t asn_n; - unsigned int i; - - (void)flags; - - options = opts; - buffer = NULL; - md = NULL; - ps = NULL; - t = NULL; - - /* Create hashing handle and get the necessary information. */ - err = gcry_md_open (&md, options->md, 0); - if (err) - goto out; - - asn_n = DIM (asn); - err = gcry_md_algo_info (options->md, GCRYCTL_GET_ASNOID, asn, &asn_n); - if (err) - goto out; - - h_n = gcry_md_get_algo_dlen (options->md); - - err = _gcry_ac_io_process (ac_io_read, emsa_pkcs_v1_5_encode_data_cb, md); - if (err) - goto out; - - h = gcry_md_read (md, 0); - - /* Encode the algorithm ID for the hash function and the hash value - into an ASN.1 value of type DigestInfo with the Distinguished - Encoding Rules (DER), where the type DigestInfo has the syntax: - - DigestInfo ::== SEQUENCE { - digestAlgorithm AlgorithmIdentifier, - digest OCTET STRING - } - - The first field identifies the hash function and the second - contains the hash value. Let T be the DER encoding of the - DigestInfo value and let tLen be the length in octets of T. */ - - t_n = asn_n + h_n; - t = gcry_malloc (t_n); - if (! t) - { - err = gcry_error_from_errno (errno); - goto out; - } - - for (i = 0; i < asn_n; i++) - t[i] = asn[i]; - for (i = 0; i < h_n; i++) - t[asn_n + i] = h[i]; - - /* If emLen < tLen + 11, output "intended encoded message length - too short" and stop. */ - if (options->em_n < t_n + 11) - { - err = gcry_error (GPG_ERR_TOO_SHORT); - goto out; - } - - /* Generate an octet string PS consisting of emLen - tLen - 3 octets - with hexadecimal value 0xFF. The length of PS will be at least 8 - octets. */ - ps_n = options->em_n - t_n - 3; - ps = gcry_malloc (ps_n); - if (! ps) - { - err = gcry_error_from_errno (errno); - goto out; - } - for (i = 0; i < ps_n; i++) - ps[i] = 0xFF; - - /* Concatenate PS, the DER encoding T, and other padding to form the - encoded message EM as: - - EM = 0x00 || 0x01 || PS || 0x00 || T. */ - - buffer_n = ps_n + t_n + 3; - buffer = gcry_malloc (buffer_n); - if (! buffer) - { - err = gcry_error_from_errno (errno); - goto out; - } - - buffer[0] = 0x00; - buffer[1] = 0x01; - for (i = 0; i < ps_n; i++) - buffer[2 + i] = ps[i]; - buffer[2 + ps_n] = 0x00; - for (i = 0; i < t_n; i++) - buffer[3 + ps_n + i] = t[i]; - - err = _gcry_ac_io_write (ac_io_write, buffer, buffer_n); - - out: - - gcry_md_close (md); - - gcry_free (buffer); - gcry_free (ps); - gcry_free (t); - - return err; -} - -/* `Actions' for data_dencode(). */ -typedef enum dencode_action - { - DATA_ENCODE, - DATA_DECODE, - } -dencode_action_t; - -/* Encode or decode a message according to the the encoding method - METHOD; ACTION specifies wether the message that is contained in - BUFFER_IN and of length BUFFER_IN_N should be encoded or decoded. - The resulting message will be stored in a newly allocated buffer in - BUFFER_OUT and BUFFER_OUT_N. */ -static gcry_error_t -ac_data_dencode (gcry_ac_em_t method, dencode_action_t action, - unsigned int flags, void *options, - gcry_ac_io_t *ac_io_read, - gcry_ac_io_t *ac_io_write) -{ - struct - { - gcry_ac_em_t method; - gcry_ac_em_dencode_t encode; - gcry_ac_em_dencode_t decode; - } methods[] = - { - { GCRY_AC_EME_PKCS_V1_5, - eme_pkcs_v1_5_encode, eme_pkcs_v1_5_decode }, - { GCRY_AC_EMSA_PKCS_V1_5, - emsa_pkcs_v1_5_encode, NULL }, - }; - size_t methods_n; - gcry_error_t err; - unsigned int i; - - methods_n = sizeof (methods) / sizeof (*methods); - - for (i = 0; i < methods_n; i++) - if (methods[i].method == method) - break; - if (i == methods_n) - { - err = gcry_error (GPG_ERR_NOT_FOUND); /* FIXME? */ - goto out; - } - - err = 0; - switch (action) - { - case DATA_ENCODE: - if (methods[i].encode) - /* FIXME? */ - err = (*methods[i].encode) (flags, options, ac_io_read, ac_io_write); - break; - - case DATA_DECODE: - if (methods[i].decode) - /* FIXME? */ - err = (*methods[i].decode) (flags, options, ac_io_read, ac_io_write); - break; - - default: - err = gcry_error (GPG_ERR_INV_ARG); - break; - } - - out: - - return err; -} - -/* Encode a message according to the encoding method METHOD. OPTIONS - must be a pointer to a method-specific structure - (gcry_ac_em*_t). */ -gcry_error_t -_gcry_ac_data_encode (gcry_ac_em_t method, - unsigned int flags, void *options, - gcry_ac_io_t *ac_io_read, - gcry_ac_io_t *ac_io_write) -{ - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - return ac_data_dencode (method, DATA_ENCODE, flags, options, - ac_io_read, ac_io_write); -} - -/* Dencode a message according to the encoding method METHOD. OPTIONS - must be a pointer to a method-specific structure - (gcry_ac_em*_t). */ -gcry_error_t -_gcry_ac_data_decode (gcry_ac_em_t method, - unsigned int flags, void *options, - gcry_ac_io_t *ac_io_read, - gcry_ac_io_t *ac_io_write) -{ - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - return ac_data_dencode (method, DATA_DECODE, flags, options, - ac_io_read, ac_io_write); -} - -/* Convert an MPI into an octet string. */ -void -_gcry_ac_mpi_to_os (gcry_mpi_t mpi, unsigned char *os, size_t os_n) -{ - unsigned long digit; - gcry_mpi_t base; - unsigned int i; - unsigned int n; - gcry_mpi_t m; - gcry_mpi_t d; - - if (fips_mode ()) - return; - - base = gcry_mpi_new (0); - gcry_mpi_set_ui (base, 256); - - n = 0; - m = gcry_mpi_copy (mpi); - while (gcry_mpi_cmp_ui (m, 0)) - { - n++; - gcry_mpi_div (m, NULL, m, base, 0); - } - - gcry_mpi_set (m, mpi); - d = gcry_mpi_new (0); - for (i = 0; (i < n) && (i < os_n); i++) - { - gcry_mpi_mod (d, m, base); - _gcry_mpi_get_ui (d, &digit); - gcry_mpi_div (m, NULL, m, base, 0); - os[os_n - i - 1] = (digit & 0xFF); - } - - for (; i < os_n; i++) - os[os_n - i - 1] = 0; - - gcry_mpi_release (base); - gcry_mpi_release (d); - gcry_mpi_release (m); -} - -/* Convert an MPI into an newly allocated octet string. */ -gcry_error_t -_gcry_ac_mpi_to_os_alloc (gcry_mpi_t mpi, unsigned char **os, size_t *os_n) -{ - unsigned char *buffer; - size_t buffer_n; - gcry_error_t err; - unsigned int nbits; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - nbits = gcry_mpi_get_nbits (mpi); - buffer_n = (nbits + 7) / 8; - buffer = gcry_malloc (buffer_n); - if (! buffer) - { - err = gcry_error_from_errno (errno); - goto out; - } - - _gcry_ac_mpi_to_os (mpi, buffer, buffer_n); - *os = buffer; - *os_n = buffer_n; - err = 0; - - out: - - return err; -} - - -/* Convert an octet string into an MPI. */ -void -_gcry_ac_os_to_mpi (gcry_mpi_t mpi, unsigned char *os, size_t os_n) -{ - unsigned int i; - gcry_mpi_t xi; - gcry_mpi_t x; - gcry_mpi_t a; - - if (fips_mode ()) - return; - - a = gcry_mpi_new (0); - gcry_mpi_set_ui (a, 1); - x = gcry_mpi_new (0); - gcry_mpi_set_ui (x, 0); - xi = gcry_mpi_new (0); - - for (i = 0; i < os_n; i++) - { - gcry_mpi_mul_ui (xi, a, os[os_n - i - 1]); - gcry_mpi_add (x, x, xi); - gcry_mpi_mul_ui (a, a, 256); - } - - gcry_mpi_release (xi); - gcry_mpi_release (a); - - gcry_mpi_set (mpi, x); - gcry_mpi_release (x); /* FIXME: correct? */ -} - - - -/* - * Implementation of Encryption Schemes (ES) and Signature Schemes - * with Appendix (SSA). - */ - -/* Schemes consist of two things: encoding methods and cryptographic - primitives. - - Since encoding methods are accessible through a common API with - method-specific options passed as an anonymous struct, schemes have - to provide functions that construct this method-specific structure; - this is what the functions of type `gcry_ac_dencode_prepare_t' are - there for. */ - -typedef gcry_error_t (*gcry_ac_dencode_prepare_t) (gcry_ac_handle_t handle, - gcry_ac_key_t key, - void *opts, - void *opts_em); - -/* The `dencode_prepare' function for ES-PKCS-V1_5. */ -static gcry_error_t -ac_es_dencode_prepare_pkcs_v1_5 (gcry_ac_handle_t handle, gcry_ac_key_t key, - void *opts, void *opts_em) -{ - gcry_ac_eme_pkcs_v1_5_t *options_em; - unsigned int nbits; - gcry_error_t err; - - (void)opts; - - err = _gcry_ac_key_get_nbits (handle, key, &nbits); - if (err) - goto out; - - options_em = opts_em; - options_em->key_size = nbits; - - out: - - return err; -} - -/* The `dencode_prepare' function for SSA-PKCS-V1_5. */ -static gcry_error_t -ac_ssa_dencode_prepare_pkcs_v1_5 (gcry_ac_handle_t handle, gcry_ac_key_t key, - void *opts, void *opts_em) -{ - gcry_ac_emsa_pkcs_v1_5_t *options_em; - gcry_ac_ssa_pkcs_v1_5_t *options; - gcry_error_t err; - unsigned int k; - - options_em = opts_em; - options = opts; - - err = _gcry_ac_key_get_nbits (handle, key, &k); - if (err) - goto out; - - k = (k + 7) / 8; - options_em->md = options->md; - options_em->em_n = k; - - out: - - return err; -} - -/* Type holding the information about each supported - Encryption/Signature Scheme. */ -typedef struct ac_scheme -{ - gcry_ac_scheme_t scheme; - gcry_ac_em_t scheme_encoding; - gcry_ac_dencode_prepare_t dencode_prepare; - size_t options_em_n; -} ac_scheme_t; - -/* List of supported Schemes. */ -static ac_scheme_t ac_schemes[] = - { - { GCRY_AC_ES_PKCS_V1_5, GCRY_AC_EME_PKCS_V1_5, - ac_es_dencode_prepare_pkcs_v1_5, - sizeof (gcry_ac_eme_pkcs_v1_5_t) }, - { GCRY_AC_SSA_PKCS_V1_5, GCRY_AC_EMSA_PKCS_V1_5, - ac_ssa_dencode_prepare_pkcs_v1_5, - sizeof (gcry_ac_emsa_pkcs_v1_5_t) } - }; - -/* Lookup a scheme by it's ID. */ -static ac_scheme_t * -ac_scheme_get (gcry_ac_scheme_t scheme) -{ - ac_scheme_t *ac_scheme; - unsigned int i; - - for (i = 0; i < DIM (ac_schemes); i++) - if (scheme == ac_schemes[i].scheme) - break; - if (i == DIM (ac_schemes)) - ac_scheme = NULL; - else - ac_scheme = ac_schemes + i; - - return ac_scheme; -} - -/* Prepares the encoding/decoding by creating an according option - structure. */ -static gcry_error_t -ac_dencode_prepare (gcry_ac_handle_t handle, gcry_ac_key_t key, void *opts, - ac_scheme_t scheme, void **opts_em) -{ - gcry_error_t err; - void *options_em; - - options_em = gcry_malloc (scheme.options_em_n); - if (! options_em) - { - err = gcry_error_from_errno (errno); - goto out; - } - - err = (*scheme.dencode_prepare) (handle, key, opts, options_em); - if (err) - goto out; - - *opts_em = options_em; - - out: - - if (err) - free (options_em); - - return err; -} - -/* Convert a data set into a single MPI; currently, this is only - supported for data sets containing a single MPI. */ -static gcry_error_t -ac_data_set_to_mpi (gcry_ac_data_t data, gcry_mpi_t *mpi) -{ - gcry_error_t err; - gcry_mpi_t mpi_new; - unsigned int elems; - - elems = _gcry_ac_data_length (data); - - if (elems != 1) - { - /* FIXME: I guess, we should be more flexible in this respect by - allowing the actual encryption/signature schemes to implement - this conversion mechanism. */ - err = gcry_error (GPG_ERR_CONFLICT); - goto out; - } - - err = _gcry_ac_data_get_index (data, GCRY_AC_FLAG_COPY, 0, NULL, &mpi_new); - if (err) - goto out; - - *mpi = mpi_new; - - out: - - return err; -} - -/* Encrypts the plain text message contained in M, which is of size - M_N, with the public key KEY_PUBLIC according to the Encryption - Scheme SCHEME_ID. HANDLE is used for accessing the low-level - cryptographic primitives. If OPTS is not NULL, it has to be an - anonymous structure specific to the chosen scheme (gcry_ac_es_*_t). - The encrypted message will be stored in C and C_N. */ -gcry_error_t -_gcry_ac_data_encrypt_scheme (gcry_ac_handle_t handle, - gcry_ac_scheme_t scheme_id, - unsigned int flags, void *opts, - gcry_ac_key_t key, - gcry_ac_io_t *io_message, - gcry_ac_io_t *io_cipher) -{ - gcry_error_t err; - gcry_ac_io_t io_em; - unsigned char *em; - size_t em_n; - gcry_mpi_t mpi_plain; - gcry_ac_data_t data_encrypted; - gcry_mpi_t mpi_encrypted; - unsigned char *buffer; - size_t buffer_n; - void *opts_em; - ac_scheme_t *scheme; - - (void)flags; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - data_encrypted = NULL; - mpi_encrypted = NULL; - mpi_plain = NULL; - opts_em = NULL; - buffer = NULL; - em = NULL; - - scheme = ac_scheme_get (scheme_id); - if (! scheme) - { - err = gcry_error (GPG_ERR_NO_ENCRYPTION_SCHEME); - goto out; - } - - if (key->type != GCRY_AC_KEY_PUBLIC) - { - err = gcry_error (GPG_ERR_WRONG_KEY_USAGE); - goto out; - } - - err = ac_dencode_prepare (handle, key, opts, *scheme, &opts_em); - if (err) - goto out; - - _gcry_ac_io_init (&io_em, GCRY_AC_IO_WRITABLE, - GCRY_AC_IO_STRING, &em, &em_n); - - err = _gcry_ac_data_encode (scheme->scheme_encoding, 0, opts_em, - io_message, &io_em); - if (err) - goto out; - - mpi_plain = gcry_mpi_snew (0); - gcry_ac_os_to_mpi (mpi_plain, em, em_n); - - err = _gcry_ac_data_encrypt (handle, 0, key, mpi_plain, &data_encrypted); - if (err) - goto out; - - err = ac_data_set_to_mpi (data_encrypted, &mpi_encrypted); - if (err) - goto out; - - err = _gcry_ac_mpi_to_os_alloc (mpi_encrypted, &buffer, &buffer_n); - if (err) - goto out; - - err = _gcry_ac_io_write (io_cipher, buffer, buffer_n); - - out: - - gcry_ac_data_destroy (data_encrypted); - gcry_mpi_release (mpi_encrypted); - gcry_mpi_release (mpi_plain); - gcry_free (opts_em); - gcry_free (buffer); - gcry_free (em); - - return err; -} - -/* Decryptes the cipher message contained in C, which is of size C_N, - with the secret key KEY_SECRET according to the Encryption Scheme - SCHEME_ID. Handle is used for accessing the low-level - cryptographic primitives. If OPTS is not NULL, it has to be an - anonymous structure specific to the chosen scheme (gcry_ac_es_*_t). - The decrypted message will be stored in M and M_N. */ -gcry_error_t -_gcry_ac_data_decrypt_scheme (gcry_ac_handle_t handle, - gcry_ac_scheme_t scheme_id, - unsigned int flags, void *opts, - gcry_ac_key_t key, - gcry_ac_io_t *io_cipher, - gcry_ac_io_t *io_message) -{ - gcry_ac_io_t io_em; - gcry_error_t err; - gcry_ac_data_t data_encrypted; - unsigned char *em; - size_t em_n; - gcry_mpi_t mpi_encrypted; - gcry_mpi_t mpi_decrypted; - void *opts_em; - ac_scheme_t *scheme; - char *elements_enc; - size_t elements_enc_n; - unsigned char *c; - size_t c_n; - - (void)flags; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - data_encrypted = NULL; - mpi_encrypted = NULL; - mpi_decrypted = NULL; - elements_enc = NULL; - opts_em = NULL; - em = NULL; - c = NULL; - - scheme = ac_scheme_get (scheme_id); - if (! scheme) - { - err = gcry_error (GPG_ERR_NO_ENCRYPTION_SCHEME); - goto out; - } - - if (key->type != GCRY_AC_KEY_SECRET) - { - err = gcry_error (GPG_ERR_WRONG_KEY_USAGE); - goto out; - } - - err = _gcry_ac_io_read_all (io_cipher, &c, &c_n); - if (err) - goto out; - - mpi_encrypted = gcry_mpi_snew (0); - gcry_ac_os_to_mpi (mpi_encrypted, c, c_n); - - err = _gcry_pk_get_elements (handle->algorithm, &elements_enc, NULL); - if (err) - goto out; - - elements_enc_n = strlen (elements_enc); - if (elements_enc_n != 1) - { - /* FIXME? */ - err = gcry_error (GPG_ERR_CONFLICT); - goto out; - } - - err = _gcry_ac_data_new (&data_encrypted); - if (err) - goto out; - - err = _gcry_ac_data_set (data_encrypted, GCRY_AC_FLAG_COPY | GCRY_AC_FLAG_DEALLOC, - elements_enc, mpi_encrypted); - if (err) - goto out; - - err = _gcry_ac_data_decrypt (handle, 0, key, &mpi_decrypted, data_encrypted); - if (err) - goto out; - - err = _gcry_ac_mpi_to_os_alloc (mpi_decrypted, &em, &em_n); - if (err) - goto out; - - err = ac_dencode_prepare (handle, key, opts, *scheme, &opts_em); - if (err) - goto out; - - _gcry_ac_io_init (&io_em, GCRY_AC_IO_READABLE, - GCRY_AC_IO_STRING, em, em_n); - - err = _gcry_ac_data_decode (scheme->scheme_encoding, 0, opts_em, - &io_em, io_message); - if (err) - goto out; - - out: - - _gcry_ac_data_destroy (data_encrypted); - gcry_mpi_release (mpi_encrypted); - gcry_mpi_release (mpi_decrypted); - free (elements_enc); - gcry_free (opts_em); - gcry_free (em); - gcry_free (c); - - return err; -} - - -/* Signs the message contained in M, which is of size M_N, with the - secret key KEY according to the Signature Scheme SCHEME_ID. Handle - is used for accessing the low-level cryptographic primitives. If - OPTS is not NULL, it has to be an anonymous structure specific to - the chosen scheme (gcry_ac_ssa_*_t). The signed message will be - stored in S and S_N. */ -gcry_error_t -_gcry_ac_data_sign_scheme (gcry_ac_handle_t handle, - gcry_ac_scheme_t scheme_id, - unsigned int flags, void *opts, - gcry_ac_key_t key, - gcry_ac_io_t *io_message, - gcry_ac_io_t *io_signature) -{ - gcry_ac_io_t io_em; - gcry_error_t err; - gcry_ac_data_t data_signed; - unsigned char *em; - size_t em_n; - gcry_mpi_t mpi; - void *opts_em; - unsigned char *buffer; - size_t buffer_n; - gcry_mpi_t mpi_signed; - ac_scheme_t *scheme; - - (void)flags; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - data_signed = NULL; - mpi_signed = NULL; - opts_em = NULL; - buffer = NULL; - mpi = NULL; - em = NULL; - - if (key->type != GCRY_AC_KEY_SECRET) - { - err = gcry_error (GPG_ERR_WRONG_KEY_USAGE); - goto out; - } - - scheme = ac_scheme_get (scheme_id); - if (! scheme) - { - /* FIXME: adjust api of scheme_get in respect to err codes. */ - err = gcry_error (GPG_ERR_NO_SIGNATURE_SCHEME); - goto out; - } - - err = ac_dencode_prepare (handle, key, opts, *scheme, &opts_em); - if (err) - goto out; - - _gcry_ac_io_init (&io_em, GCRY_AC_IO_WRITABLE, - GCRY_AC_IO_STRING, &em, &em_n); - - err = _gcry_ac_data_encode (scheme->scheme_encoding, 0, opts_em, - io_message, &io_em); - if (err) - goto out; - - mpi = gcry_mpi_new (0); - _gcry_ac_os_to_mpi (mpi, em, em_n); - - err = _gcry_ac_data_sign (handle, key, mpi, &data_signed); - if (err) - goto out; - - err = ac_data_set_to_mpi (data_signed, &mpi_signed); - if (err) - goto out; - - err = _gcry_ac_mpi_to_os_alloc (mpi_signed, &buffer, &buffer_n); - if (err) - goto out; - - err = _gcry_ac_io_write (io_signature, buffer, buffer_n); - - out: - - _gcry_ac_data_destroy (data_signed); - gcry_mpi_release (mpi_signed); - gcry_mpi_release (mpi); - gcry_free (opts_em); - gcry_free (buffer); - gcry_free (em); - - return err; -} - -/* Verifies that the signature contained in S, which is of length S_N, - is indeed the result of signing the message contained in M, which - is of size M_N, with the secret key belonging to the public key - KEY_PUBLIC. If OPTS is not NULL, it has to be an anonymous - structure (gcry_ac_ssa_*_t) specific to the Signature Scheme, whose - ID is contained in SCHEME_ID. */ -gcry_error_t -_gcry_ac_data_verify_scheme (gcry_ac_handle_t handle, - gcry_ac_scheme_t scheme_id, - unsigned int flags, void *opts, - gcry_ac_key_t key, - gcry_ac_io_t *io_message, - gcry_ac_io_t *io_signature) -{ - gcry_ac_io_t io_em; - gcry_error_t err; - gcry_ac_data_t data_signed; - unsigned char *em; - size_t em_n; - void *opts_em; - gcry_mpi_t mpi_signature; - gcry_mpi_t mpi_data; - ac_scheme_t *scheme; - char *elements_sig; - size_t elements_sig_n; - unsigned char *s; - size_t s_n; - - (void)flags; - - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - mpi_signature = NULL; - elements_sig = NULL; - data_signed = NULL; - mpi_data = NULL; - opts_em = NULL; - em = NULL; - s = NULL; - - if (key->type != GCRY_AC_KEY_PUBLIC) - { - err = gcry_error (GPG_ERR_WRONG_KEY_USAGE); - goto out; - } - - scheme = ac_scheme_get (scheme_id); - if (! scheme) - { - err = gcry_error (GPG_ERR_NO_SIGNATURE_SCHEME); - goto out; - } - - err = ac_dencode_prepare (handle, key, opts, *scheme, &opts_em); - if (err) - goto out; - - _gcry_ac_io_init (&io_em, GCRY_AC_IO_WRITABLE, - GCRY_AC_IO_STRING, &em, &em_n); - - err = _gcry_ac_data_encode (scheme->scheme_encoding, 0, opts_em, - io_message, &io_em); - if (err) - goto out; - - mpi_data = gcry_mpi_new (0); - _gcry_ac_os_to_mpi (mpi_data, em, em_n); - - err = _gcry_ac_io_read_all (io_signature, &s, &s_n); - if (err) - goto out; - - mpi_signature = gcry_mpi_new (0); - _gcry_ac_os_to_mpi (mpi_signature, s, s_n); - - err = _gcry_pk_get_elements (handle->algorithm, NULL, &elements_sig); - if (err) - goto out; - - elements_sig_n = strlen (elements_sig); - if (elements_sig_n != 1) - { - /* FIXME? */ - err = gcry_error (GPG_ERR_CONFLICT); - goto out; - } - - err = _gcry_ac_data_new (&data_signed); - if (err) - goto out; - - err = _gcry_ac_data_set (data_signed, GCRY_AC_FLAG_COPY | GCRY_AC_FLAG_DEALLOC, - elements_sig, mpi_signature); - if (err) - goto out; - - gcry_mpi_release (mpi_signature); - mpi_signature = NULL; - - err = _gcry_ac_data_verify (handle, key, mpi_data, data_signed); - - out: - - _gcry_ac_data_destroy (data_signed); - gcry_mpi_release (mpi_signature); - gcry_mpi_release (mpi_data); - free (elements_sig); - gcry_free (opts_em); - gcry_free (em); - gcry_free (s); - - return err; -} - - -/* - * General functions. - */ - -gcry_err_code_t -_gcry_ac_init (void) -{ - if (fips_mode ()) - return GPG_ERR_NOT_SUPPORTED; - - return 0; -} diff --git a/plugins/MirOTR/Libgcrypt/cipher/arcfour.c b/plugins/MirOTR/Libgcrypt/cipher/arcfour.c index 6bb0555c60..d692c84a97 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/arcfour.c +++ b/plugins/MirOTR/Libgcrypt/cipher/arcfour.c @@ -34,18 +34,43 @@ static const char *selftest(void); typedef struct { - int idx_i, idx_j; byte sbox[256]; + int idx_i, idx_j; } ARCFOUR_context; static void do_encrypt_stream( ARCFOUR_context *ctx, - byte *outbuf, const byte *inbuf, unsigned int length ) + byte *outbuf, const byte *inbuf, size_t length ) { +#ifndef __i386__ + register unsigned int i = ctx->idx_i; + register byte j = ctx->idx_j; + register byte *sbox = ctx->sbox; + register byte t, u; + + while ( length-- ) + { + i++; + t = sbox[(byte)i]; + j += t; + u = sbox[j]; + sbox[(byte)i] = u; + u += t; + sbox[j] = t; + *outbuf++ = sbox[u] ^ *inbuf++; + } + + ctx->idx_i = (byte)i; + ctx->idx_j = (byte)j; +#else /*__i386__*/ + /* Old implementation of arcfour is faster on i386 than the version above. + * This is because version above increases register pressure which on i386 + * would push some of the variables to memory/stack. Therefore keep this + * version for i386 to avoid regressing performance. */ register int i = ctx->idx_i; register int j = ctx->idx_j; register byte *sbox = ctx->sbox; - register int t; + register int t; while ( length-- ) { @@ -56,14 +81,15 @@ do_encrypt_stream( ARCFOUR_context *ctx, t = sbox[i]; sbox[i] = sbox[j]; sbox[j] = t; *outbuf++ = *inbuf++ ^ sbox[(sbox[i] + sbox[j]) & 255]; } - + ctx->idx_i = i; ctx->idx_j = j; +#endif } static void encrypt_stream (void *context, - byte *outbuf, const byte *inbuf, unsigned int length) + byte *outbuf, const byte *inbuf, size_t length) { ARCFOUR_context *ctx = (ARCFOUR_context *) context; do_encrypt_stream (ctx, outbuf, inbuf, length ); @@ -80,7 +106,7 @@ do_arcfour_setkey (void *context, const byte *key, unsigned int keylen) byte karr[256]; ARCFOUR_context *ctx = (ARCFOUR_context *) context; - if (!initialized ) + if (!initialized ) { initialized = 1; selftest_failed = selftest(); @@ -96,17 +122,21 @@ do_arcfour_setkey (void *context, const byte *key, unsigned int keylen) ctx->idx_i = ctx->idx_j = 0; for (i=0; i < 256; i++ ) ctx->sbox[i] = i; - for (i=0; i < 256; i++ ) - karr[i] = key[i%keylen]; - for (i=j=0; i < 256; i++ ) + for (i=j=0; i < 256; i++,j++ ) + { + if (j >= keylen) + j = 0; + karr[i] = key[j]; + } + for (i=j=0; i < 256; i++ ) { int t; - j = (j + ctx->sbox[i] + karr[i]) % 256; + j = (j + ctx->sbox[i] + karr[i]) & 255; t = ctx->sbox[i]; ctx->sbox[i] = ctx->sbox[j]; ctx->sbox[j] = t; - } - memset( karr, 0, 256 ); + } + wipememory( karr, sizeof(karr) ); return GPG_ERR_NO_ERROR; } @@ -116,7 +146,6 @@ arcfour_setkey ( void *context, const byte *key, unsigned int keylen ) { ARCFOUR_context *ctx = (ARCFOUR_context *) context; gcry_err_code_t rc = do_arcfour_setkey (ctx, key, keylen ); - _gcry_burn_stack (300); return rc; } @@ -125,13 +154,13 @@ static const char* selftest(void) { ARCFOUR_context ctx; - byte scratch[16]; - + byte scratch[16]; + /* Test vector from Cryptlib labeled there: "from the State/Commerce Department". */ - static byte key_1[] = + static const byte key_1[] = { 0x61, 0x8A, 0x63, 0xD2, 0xFB }; - static byte plaintext_1[] = + static const byte plaintext_1[] = { 0xDC, 0xEE, 0x4C, 0xF9, 0x2C }; static const byte ciphertext_1[] = { 0xF1, 0x38, 0x29, 0xC9, 0xDE }; @@ -150,7 +179,7 @@ selftest(void) gcry_cipher_spec_t _gcry_cipher_spec_arcfour = { + GCRY_CIPHER_ARCFOUR, {0, 0}, "ARCFOUR", NULL, NULL, 1, 128, sizeof (ARCFOUR_context), arcfour_setkey, NULL, NULL, encrypt_stream, encrypt_stream, }; - diff --git a/plugins/MirOTR/Libgcrypt/cipher/bithelp.h b/plugins/MirOTR/Libgcrypt/cipher/bithelp.h index 1505324330..6e59c53fdb 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/bithelp.h +++ b/plugins/MirOTR/Libgcrypt/cipher/bithelp.h @@ -20,35 +20,61 @@ #ifndef G10_BITHELP_H #define G10_BITHELP_H +#include "types.h" + /**************** * Rotate the 32 bit unsigned integer X by N bits left/right */ -#if defined(__GNUC__) && defined(__i386__) -static inline u32 -rol( u32 x, int n) +static inline u32 rol(u32 x, int n) { - __asm__("roll %%cl,%0" - :"=r" (x) - :"0" (x),"c" (n)); - return x; + return ( (x << (n&(32-1))) | (x >> ((32-n)&(32-1))) ); } + +static inline u32 ror(u32 x, int n) +{ + return ( (x >> (n&(32-1))) | (x << ((32-n)&(32-1))) ); +} + +/* Byte swap for 32-bit and 64-bit integers. If available, use compiler + provided helpers. */ +#ifdef HAVE_BUILTIN_BSWAP32 +# define _gcry_bswap32 __builtin_bswap32 #else -#define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) ) +static inline u32 +_gcry_bswap32(u32 x) +{ + return ((rol(x, 8) & 0x00ff00ffL) | (ror(x, 8) & 0xff00ff00L)); +} #endif -#if defined(__GNUC__) && defined(__i386__) -static inline u32 -ror(u32 x, int n) +#ifdef HAVE_U64_TYPEDEF +# ifdef HAVE_BUILTIN_BSWAP64 +# define _gcry_bswap64 __builtin_bswap64 +# else +static inline u64 +_gcry_bswap64(u64 x) { - __asm__("rorl %%cl,%0" - :"=r" (x) - :"0" (x),"c" (n)); - return x; + return ((u64)_gcry_bswap32(x) << 32) | (_gcry_bswap32(x >> 32)); } -#else -#define ror(x,n) ( ((x) >> (n)) | ((x) << (32-(n))) ) +# endif #endif +/* Endian dependent byte swap operations. */ +#ifdef WORDS_BIGENDIAN +# define le_bswap32(x) _gcry_bswap32(x) +# define be_bswap32(x) ((u32)(x)) +# ifdef HAVE_U64_TYPEDEF +# define le_bswap64(x) _gcry_bswap64(x) +# define be_bswap64(x) ((u64)(x)) +# endif +#else +# define le_bswap32(x) ((u32)(x)) +# define be_bswap32(x) _gcry_bswap32(x) +# ifdef HAVE_U64_TYPEDEF +# define le_bswap64(x) ((u64)(x)) +# define be_bswap64(x) _gcry_bswap64(x) +# endif +#endif #endif /*G10_BITHELP_H*/ diff --git a/plugins/MirOTR/Libgcrypt/cipher/blowfish.c b/plugins/MirOTR/Libgcrypt/cipher/blowfish.c index 6ef68e371d..ae470d8b4c 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/blowfish.c +++ b/plugins/MirOTR/Libgcrypt/cipher/blowfish.c @@ -36,10 +36,28 @@ #include "types.h" #include "g10lib.h" #include "cipher.h" +#include "bufhelp.h" +#include "cipher-selftest.h" #define BLOWFISH_BLOCKSIZE 8 #define BLOWFISH_ROUNDS 16 + +/* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */ +#undef USE_AMD64_ASM +#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) && \ + (BLOWFISH_ROUNDS == 16) +# define USE_AMD64_ASM 1 +#endif + +/* USE_ARM_ASM indicates whether to use ARM assembly code. */ +#undef USE_ARM_ASM +#if defined(__ARMEL__) +# if (BLOWFISH_ROUNDS == 16) && defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) +# define USE_ARM_ASM 1 +# endif +#endif + typedef struct { u32 s0[256]; u32 s1[256]; @@ -49,8 +67,8 @@ typedef struct { } BLOWFISH_context; static gcry_err_code_t bf_setkey (void *c, const byte *key, unsigned keylen); -static void encrypt_block (void *bc, byte *outbuf, const byte *inbuf); -static void decrypt_block (void *bc, byte *outbuf, const byte *inbuf); +static unsigned int encrypt_block (void *bc, byte *outbuf, const byte *inbuf); +static unsigned int decrypt_block (void *bc, byte *outbuf, const byte *inbuf); /* precomputed S boxes */ @@ -240,6 +258,119 @@ static const u32 ps[BLOWFISH_ROUNDS+2] = { 0xC0AC29B7,0xC97C50DD,0x3F84D5B5,0xB5470917,0x9216D5D9,0x8979FB1B }; +#ifdef USE_AMD64_ASM + +/* Assembly implementations of Blowfish. */ +extern void _gcry_blowfish_amd64_do_encrypt(BLOWFISH_context *c, u32 *ret_xl, + u32 *ret_xr); + +extern void _gcry_blowfish_amd64_encrypt_block(BLOWFISH_context *c, byte *out, + const byte *in); + +extern void _gcry_blowfish_amd64_decrypt_block(BLOWFISH_context *c, byte *out, + const byte *in); + +/* These assembly implementations process four blocks in parallel. */ +extern void _gcry_blowfish_amd64_ctr_enc(BLOWFISH_context *ctx, byte *out, + const byte *in, byte *ctr); + +extern void _gcry_blowfish_amd64_cbc_dec(BLOWFISH_context *ctx, byte *out, + const byte *in, byte *iv); + +extern void _gcry_blowfish_amd64_cfb_dec(BLOWFISH_context *ctx, byte *out, + const byte *in, byte *iv); + +static void +do_encrypt ( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr ) +{ + _gcry_blowfish_amd64_do_encrypt (bc, ret_xl, ret_xr); +} + +static void +do_encrypt_block (BLOWFISH_context *context, byte *outbuf, const byte *inbuf) +{ + _gcry_blowfish_amd64_encrypt_block (context, outbuf, inbuf); +} + +static void +do_decrypt_block (BLOWFISH_context *context, byte *outbuf, const byte *inbuf) +{ + _gcry_blowfish_amd64_decrypt_block (context, outbuf, inbuf); +} + +static unsigned int +encrypt_block (void *context , byte *outbuf, const byte *inbuf) +{ + BLOWFISH_context *c = (BLOWFISH_context *) context; + do_encrypt_block (c, outbuf, inbuf); + return /*burn_stack*/ (2*8); +} + +static unsigned int +decrypt_block (void *context, byte *outbuf, const byte *inbuf) +{ + BLOWFISH_context *c = (BLOWFISH_context *) context; + do_decrypt_block (c, outbuf, inbuf); + return /*burn_stack*/ (2*8); +} + +#elif defined(USE_ARM_ASM) + +/* Assembly implementations of Blowfish. */ +extern void _gcry_blowfish_arm_do_encrypt(BLOWFISH_context *c, u32 *ret_xl, + u32 *ret_xr); + +extern void _gcry_blowfish_arm_encrypt_block(BLOWFISH_context *c, byte *out, + const byte *in); + +extern void _gcry_blowfish_arm_decrypt_block(BLOWFISH_context *c, byte *out, + const byte *in); + +/* These assembly implementations process two blocks in parallel. */ +extern void _gcry_blowfish_arm_ctr_enc(BLOWFISH_context *ctx, byte *out, + const byte *in, byte *ctr); + +extern void _gcry_blowfish_arm_cbc_dec(BLOWFISH_context *ctx, byte *out, + const byte *in, byte *iv); + +extern void _gcry_blowfish_arm_cfb_dec(BLOWFISH_context *ctx, byte *out, + const byte *in, byte *iv); + +static void +do_encrypt ( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr ) +{ + _gcry_blowfish_arm_do_encrypt (bc, ret_xl, ret_xr); +} + +static void +do_encrypt_block (BLOWFISH_context *context, byte *outbuf, const byte *inbuf) +{ + _gcry_blowfish_arm_encrypt_block (context, outbuf, inbuf); +} + +static void +do_decrypt_block (BLOWFISH_context *context, byte *outbuf, const byte *inbuf) +{ + _gcry_blowfish_arm_decrypt_block (context, outbuf, inbuf); +} + +static unsigned int +encrypt_block (void *context , byte *outbuf, const byte *inbuf) +{ + BLOWFISH_context *c = (BLOWFISH_context *) context; + do_encrypt_block (c, outbuf, inbuf); + return /*burn_stack*/ (10*4); +} + +static unsigned int +decrypt_block (void *context, byte *outbuf, const byte *inbuf) +{ + BLOWFISH_context *c = (BLOWFISH_context *) context; + do_decrypt_block (c, outbuf, inbuf); + return /*burn_stack*/ (10*4); +} + +#else /*USE_ARM_ASM*/ #if BLOWFISH_ROUNDS != 16 static inline u32 @@ -413,25 +544,19 @@ do_encrypt_block ( BLOWFISH_context *bc, byte *outbuf, const byte *inbuf ) { u32 d1, d2; - d1 = inbuf[0] << 24 | inbuf[1] << 16 | inbuf[2] << 8 | inbuf[3]; - d2 = inbuf[4] << 24 | inbuf[5] << 16 | inbuf[6] << 8 | inbuf[7]; + d1 = buf_get_be32(inbuf); + d2 = buf_get_be32(inbuf + 4); do_encrypt( bc, &d1, &d2 ); - outbuf[0] = (d1 >> 24) & 0xff; - outbuf[1] = (d1 >> 16) & 0xff; - outbuf[2] = (d1 >> 8) & 0xff; - outbuf[3] = d1 & 0xff; - outbuf[4] = (d2 >> 24) & 0xff; - outbuf[5] = (d2 >> 16) & 0xff; - outbuf[6] = (d2 >> 8) & 0xff; - outbuf[7] = d2 & 0xff; + buf_put_be32(outbuf, d1); + buf_put_be32(outbuf + 4, d2); } -static void +static unsigned int encrypt_block (void *context, byte *outbuf, const byte *inbuf) { BLOWFISH_context *bc = (BLOWFISH_context *) context; do_encrypt_block (bc, outbuf, inbuf); - _gcry_burn_stack (64); + return /*burn_stack*/ (64); } @@ -440,25 +565,254 @@ do_decrypt_block (BLOWFISH_context *bc, byte *outbuf, const byte *inbuf) { u32 d1, d2; - d1 = inbuf[0] << 24 | inbuf[1] << 16 | inbuf[2] << 8 | inbuf[3]; - d2 = inbuf[4] << 24 | inbuf[5] << 16 | inbuf[6] << 8 | inbuf[7]; + d1 = buf_get_be32(inbuf); + d2 = buf_get_be32(inbuf + 4); decrypt( bc, &d1, &d2 ); - outbuf[0] = (d1 >> 24) & 0xff; - outbuf[1] = (d1 >> 16) & 0xff; - outbuf[2] = (d1 >> 8) & 0xff; - outbuf[3] = d1 & 0xff; - outbuf[4] = (d2 >> 24) & 0xff; - outbuf[5] = (d2 >> 16) & 0xff; - outbuf[6] = (d2 >> 8) & 0xff; - outbuf[7] = d2 & 0xff; + buf_put_be32(outbuf, d1); + buf_put_be32(outbuf + 4, d2); } -static void +static unsigned int decrypt_block (void *context, byte *outbuf, const byte *inbuf) { BLOWFISH_context *bc = (BLOWFISH_context *) context; do_decrypt_block (bc, outbuf, inbuf); - _gcry_burn_stack (64); + return /*burn_stack*/ (64); +} + +#endif /*!USE_AMD64_ASM&&!USE_ARM_ASM*/ + + +/* Bulk encryption of complete blocks in CTR mode. This function is only + intended for the bulk encryption feature of cipher.c. CTR is expected to be + of size BLOWFISH_BLOCKSIZE. */ +void +_gcry_blowfish_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks) +{ + BLOWFISH_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char tmpbuf[BLOWFISH_BLOCKSIZE]; + int burn_stack_depth = (64) + 2 * BLOWFISH_BLOCKSIZE; + int i; + +#ifdef USE_AMD64_ASM + { + if (nblocks >= 4) + burn_stack_depth += 5 * sizeof(void*); + + /* Process data in 4 block chunks. */ + while (nblocks >= 4) + { + _gcry_blowfish_amd64_ctr_enc(ctx, outbuf, inbuf, ctr); + + nblocks -= 4; + outbuf += 4 * BLOWFISH_BLOCKSIZE; + inbuf += 4 * BLOWFISH_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + /* TODO: use caching instead? */ + } +#elif defined(USE_ARM_ASM) + { + /* Process data in 2 block chunks. */ + while (nblocks >= 2) + { + _gcry_blowfish_arm_ctr_enc(ctx, outbuf, inbuf, ctr); + + nblocks -= 2; + outbuf += 2 * BLOWFISH_BLOCKSIZE; + inbuf += 2 * BLOWFISH_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + /* TODO: use caching instead? */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* Encrypt the counter. */ + do_encrypt_block(ctx, tmpbuf, ctr); + /* XOR the input with the encrypted counter and store in output. */ + buf_xor(outbuf, tmpbuf, inbuf, BLOWFISH_BLOCKSIZE); + outbuf += BLOWFISH_BLOCKSIZE; + inbuf += BLOWFISH_BLOCKSIZE; + /* Increment the counter. */ + for (i = BLOWFISH_BLOCKSIZE; i > 0; i--) + { + ctr[i-1]++; + if (ctr[i-1]) + break; + } + } + + wipememory(tmpbuf, sizeof(tmpbuf)); + _gcry_burn_stack(burn_stack_depth); +} + + +/* Bulk decryption of complete blocks in CBC mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +void +_gcry_blowfish_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks) +{ + BLOWFISH_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char savebuf[BLOWFISH_BLOCKSIZE]; + int burn_stack_depth = (64) + 2 * BLOWFISH_BLOCKSIZE; + +#ifdef USE_AMD64_ASM + { + if (nblocks >= 4) + burn_stack_depth += 5 * sizeof(void*); + + /* Process data in 4 block chunks. */ + while (nblocks >= 4) + { + _gcry_blowfish_amd64_cbc_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 4; + outbuf += 4 * BLOWFISH_BLOCKSIZE; + inbuf += 4 * BLOWFISH_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#elif defined(USE_ARM_ASM) + { + /* Process data in 2 block chunks. */ + while (nblocks >= 2) + { + _gcry_blowfish_arm_cbc_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 2; + outbuf += 2 * BLOWFISH_BLOCKSIZE; + inbuf += 2 * BLOWFISH_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* INBUF is needed later and it may be identical to OUTBUF, so store + the intermediate result to SAVEBUF. */ + do_decrypt_block (ctx, savebuf, inbuf); + + buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, BLOWFISH_BLOCKSIZE); + inbuf += BLOWFISH_BLOCKSIZE; + outbuf += BLOWFISH_BLOCKSIZE; + } + + wipememory(savebuf, sizeof(savebuf)); + _gcry_burn_stack(burn_stack_depth); +} + + +/* Bulk decryption of complete blocks in CFB mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +void +_gcry_blowfish_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks) +{ + BLOWFISH_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + int burn_stack_depth = (64) + 2 * BLOWFISH_BLOCKSIZE; + +#ifdef USE_AMD64_ASM + { + if (nblocks >= 4) + burn_stack_depth += 5 * sizeof(void*); + + /* Process data in 4 block chunks. */ + while (nblocks >= 4) + { + _gcry_blowfish_amd64_cfb_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 4; + outbuf += 4 * BLOWFISH_BLOCKSIZE; + inbuf += 4 * BLOWFISH_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#elif defined(USE_ARM_ASM) + { + /* Process data in 2 block chunks. */ + while (nblocks >= 2) + { + _gcry_blowfish_arm_cfb_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 2; + outbuf += 2 * BLOWFISH_BLOCKSIZE; + inbuf += 2 * BLOWFISH_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + do_encrypt_block(ctx, iv, iv); + buf_xor_n_copy(outbuf, iv, inbuf, BLOWFISH_BLOCKSIZE); + outbuf += BLOWFISH_BLOCKSIZE; + inbuf += BLOWFISH_BLOCKSIZE; + } + + _gcry_burn_stack(burn_stack_depth); +} + + +/* Run the self-tests for BLOWFISH-CTR, tests IV increment of bulk CTR + encryption. Returns NULL on success. */ +static const char * +selftest_ctr (void) +{ + const int nblocks = 4+1; + const int blocksize = BLOWFISH_BLOCKSIZE; + const int context_size = sizeof(BLOWFISH_context); + + return _gcry_selftest_helper_ctr("BLOWFISH", &bf_setkey, + &encrypt_block, &_gcry_blowfish_ctr_enc, nblocks, blocksize, + context_size); +} + + +/* Run the self-tests for BLOWFISH-CBC, tests bulk CBC decryption. + Returns NULL on success. */ +static const char * +selftest_cbc (void) +{ + const int nblocks = 4+2; + const int blocksize = BLOWFISH_BLOCKSIZE; + const int context_size = sizeof(BLOWFISH_context); + + return _gcry_selftest_helper_cbc("BLOWFISH", &bf_setkey, + &encrypt_block, &_gcry_blowfish_cbc_dec, nblocks, blocksize, + context_size); +} + + +/* Run the self-tests for BLOWFISH-CFB, tests bulk CBC decryption. + Returns NULL on success. */ +static const char * +selftest_cfb (void) +{ + const int nblocks = 4+2; + const int blocksize = BLOWFISH_BLOCKSIZE; + const int context_size = sizeof(BLOWFISH_context); + + return _gcry_selftest_helper_cfb("BLOWFISH", &bf_setkey, + &encrypt_block, &_gcry_blowfish_cfb_dec, nblocks, blocksize, + context_size); } @@ -468,9 +822,13 @@ selftest(void) BLOWFISH_context c; byte plain[] = "BLOWFISH"; byte buffer[8]; - byte plain3[] = { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }; - byte key3[] = { 0x41, 0x79, 0x6E, 0xA0, 0x52, 0x61, 0x6E, 0xE4 }; - byte cipher3[] = { 0xE1, 0x13, 0xF4, 0x10, 0x2C, 0xFC, 0xCE, 0x43 }; + static const byte plain3[] = + { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }; + static const byte key3[] = + { 0x41, 0x79, 0x6E, 0xA0, 0x52, 0x61, 0x6E, 0xE4 }; + static const byte cipher3[] = + { 0xE1, 0x13, 0xF4, 0x10, 0x2C, 0xFC, 0xCE, 0x43 }; + const char *r; bf_setkey( (void *) &c, (const unsigned char*)"abcdefghijklmnopqrstuvwxyz", 26 ); @@ -488,20 +846,86 @@ selftest(void) decrypt_block( (void *) &c, buffer, buffer ); if( memcmp( buffer, plain3, 8 ) ) return "Blowfish selftest failed (4)."; + + if ( (r = selftest_cbc ()) ) + return r; + + if ( (r = selftest_cfb ()) ) + return r; + + if ( (r = selftest_ctr ()) ) + return r; + return NULL; } +struct hashset_elem { + u32 val; + short nidx; + char used; +}; + +static inline byte +val_to_hidx(u32 val) +{ + /* bf sboxes are quite random already. */ + return (val >> 24) ^ (val >> 16) ^ (val >> 8) ^ val; +} + +static inline int +add_val(struct hashset_elem hset[256], u32 val, int *midx, + struct hashset_elem *mpool) +{ + struct hashset_elem *elem; + byte hidx; + + hidx = val_to_hidx(val); + elem = &hset[hidx]; + + /* Check if first is in use. */ + if (elem->used == 0) + { + elem->val = val; + elem->nidx = -1; + elem->used = 1; + return 0; + } + + /* Check if first matches. */ + if (elem->val == val) + return 1; + + for (; elem->nidx >= 0; elem = &mpool[elem->nidx]) + { + /* Check if elem matches. */ + if (elem->val == val) + return 1; + } + + elem->nidx = (*midx)++; + elem = &mpool[elem->nidx]; + + elem->val = val; + elem->nidx = -1; + elem->used = 1; + + return 0; +} static gcry_err_code_t do_bf_setkey (BLOWFISH_context *c, const byte *key, unsigned keylen) { - int i, j; + struct hashset_elem mempool[4 * 255]; /* Enough entries for the worst case. */ + struct hashset_elem hset[4][256]; + int memidx = 0; + int weak = 0; + int i, j, ret; u32 data, datal, datar; static int initialized; static const char *selftest_failed; - if( !initialized ) + if( !initialized ) { initialized = 1; selftest_failed = selftest(); @@ -511,9 +935,11 @@ do_bf_setkey (BLOWFISH_context *c, const byte *key, unsigned keylen) if( selftest_failed ) return GPG_ERR_SELFTEST_FAILED; + memset(hset, 0, sizeof(hset)); + for(i=0; i < BLOWFISH_ROUNDS+2; i++ ) c->p[i] = ps[i]; - for(i=0; i < 256; i++ ) + for(i=0; i < 256; i++ ) { c->s0[i] = ks0[i]; c->s1[i] = ks1[i]; @@ -521,19 +947,12 @@ do_bf_setkey (BLOWFISH_context *c, const byte *key, unsigned keylen) c->s3[i] = ks3[i]; } - for(i=j=0; i < BLOWFISH_ROUNDS+2; i++ ) + for(i=j=0; i < BLOWFISH_ROUNDS+2; i++ ) { -#ifdef WORDS_BIGENDIAN - ((byte*)&data)[0] = key[j]; - ((byte*)&data)[1] = key[(j+1)%keylen]; - ((byte*)&data)[2] = key[(j+2)%keylen]; - ((byte*)&data)[3] = key[(j+3)%keylen]; -#else - ((byte*)&data)[3] = key[j]; - ((byte*)&data)[2] = key[(j+1)%keylen]; - ((byte*)&data)[1] = key[(j+2)%keylen]; - ((byte*)&data)[0] = key[(j+3)%keylen]; -#endif + data = ((u32)key[j] << 24) | + ((u32)key[(j+1)%keylen] << 16) | + ((u32)key[(j+2)%keylen] << 8) | + ((u32)key[(j+3)%keylen]); c->p[i] ^= data; j = (j+4) % keylen; } @@ -545,43 +964,65 @@ do_bf_setkey (BLOWFISH_context *c, const byte *key, unsigned keylen) c->p[i] = datal; c->p[i+1] = datar; } - for(i=0; i < 256; i += 2 ) + for(i=0; i < 256; i += 2 ) { do_encrypt( c, &datal, &datar ); c->s0[i] = datal; c->s0[i+1] = datar; + + /* Add values to hashset, detect duplicates (weak keys). */ + ret = add_val (hset[0], datal, &memidx, mempool); + weak = ret ? 1 : weak; + ret = add_val (hset[0], datar, &memidx, mempool); + weak = ret ? 1 : weak; } for(i=0; i < 256; i += 2 ) { do_encrypt( c, &datal, &datar ); c->s1[i] = datal; c->s1[i+1] = datar; + + /* Add values to hashset, detect duplicates (weak keys). */ + ret = add_val (hset[1], datal, &memidx, mempool); + weak = ret ? 1 : weak; + ret = add_val (hset[1], datar, &memidx, mempool); + weak = ret ? 1 : weak; } for(i=0; i < 256; i += 2 ) { do_encrypt( c, &datal, &datar ); c->s2[i] = datal; c->s2[i+1] = datar; + + /* Add values to hashset, detect duplicates (weak keys). */ + ret = add_val (hset[2], datal, &memidx, mempool); + weak = ret ? 1 : weak; + ret = add_val (hset[2], datar, &memidx, mempool); + weak = ret ? 1 : weak; } for(i=0; i < 256; i += 2 ) { do_encrypt( c, &datal, &datar ); c->s3[i] = datal; c->s3[i+1] = datar; + + /* Add values to hashset, detect duplicates (weak keys). */ + ret = add_val (hset[3], datal, &memidx, mempool); + weak = ret ? 1 : weak; + ret = add_val (hset[3], datar, &memidx, mempool); + weak = ret ? 1 : weak; } + /* Clear stack. */ + wipememory(hset, sizeof(hset)); + wipememory(mempool, sizeof(mempool[0]) * memidx); + + _gcry_burn_stack (64); /* Check for weak key. A weak key is a key in which a value in the P-array (here c) occurs more than once per table. */ - for(i=0; i < 255; i++ ) - { - for( j=i+1; j < 256; j++) - { - if( (c->s0[i] == c->s0[j]) || (c->s1[i] == c->s1[j]) || - (c->s2[i] == c->s2[j]) || (c->s3[i] == c->s3[j]) ) - return GPG_ERR_WEAK_KEY; - } - } + if (weak) + return GPG_ERR_WEAK_KEY; return GPG_ERR_NO_ERROR; } @@ -592,13 +1033,13 @@ bf_setkey (void *context, const byte *key, unsigned keylen) { BLOWFISH_context *c = (BLOWFISH_context *) context; gcry_err_code_t rc = do_bf_setkey (c, key, keylen); - _gcry_burn_stack (64); return rc; } gcry_cipher_spec_t _gcry_cipher_spec_blowfish = { + GCRY_CIPHER_BLOWFISH, {0, 0}, "BLOWFISH", NULL, NULL, BLOWFISH_BLOCKSIZE, 128, sizeof (BLOWFISH_context), bf_setkey, encrypt_block, decrypt_block diff --git a/plugins/MirOTR/Libgcrypt/cipher/bufhelp.h b/plugins/MirOTR/Libgcrypt/cipher/bufhelp.h new file mode 100644 index 0000000000..45a720941d --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/bufhelp.h @@ -0,0 +1,378 @@ +/* bufhelp.h - Some buffer manipulation helpers + * Copyright © 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef G10_BUFHELP_H +#define G10_BUFHELP_H + +#include <config.h> + +#ifdef HAVE_STDINT_H +# include <stdint.h> /* uintptr_t */ +#elif defined(HAVE_INTTYPES_H) +# include <inttypes.h> +#else +/* In this case, uintptr_t is provided by config.h. */ +#endif + +#include "bithelp.h" + + +#if defined(__i386__) || defined(__x86_64__) || \ + defined(__powerpc__) || defined(__powerpc64__) || \ + (defined(__arm__) && defined(__ARM_FEATURE_UNALIGNED)) || \ + defined(__aarch64__) +/* These architectures are able of unaligned memory accesses and can + handle those fast. + */ +# define BUFHELP_FAST_UNALIGNED_ACCESS 1 +#endif + + +/* Optimized function for small buffer copying */ +static inline void +buf_cpy(void *_dst, const void *_src, size_t len) +{ +#if __GNUC__ >= 4 && (defined(__x86_64__) || defined(__i386__)) + /* For AMD64 and i386, memcpy is faster. */ + memcpy(_dst, _src, len); +#else + byte *dst = _dst; + const byte *src = _src; + uintptr_t *ldst; + const uintptr_t *lsrc; +#ifndef BUFHELP_FAST_UNALIGNED_ACCESS + const unsigned int longmask = sizeof(uintptr_t) - 1; + + /* Skip fast processing if buffers are unaligned. */ + if (((uintptr_t)dst | (uintptr_t)src) & longmask) + goto do_bytes; +#endif + + ldst = (uintptr_t *)(void *)dst; + lsrc = (const uintptr_t *)(const void *)src; + + for (; len >= sizeof(uintptr_t); len -= sizeof(uintptr_t)) + *ldst++ = *lsrc++; + + dst = (byte *)ldst; + src = (const byte *)lsrc; + +#ifndef BUFHELP_FAST_UNALIGNED_ACCESS +do_bytes: +#endif + /* Handle tail. */ + for (; len; len--) + *dst++ = *src++; +#endif /*__GNUC__ >= 4 && (__x86_64__ || __i386__)*/ +} + + +/* Optimized function for buffer xoring */ +static inline void +buf_xor(void *_dst, const void *_src1, const void *_src2, size_t len) +{ + byte *dst = _dst; + const byte *src1 = _src1; + const byte *src2 = _src2; + uintptr_t *ldst; + const uintptr_t *lsrc1, *lsrc2; +#ifndef BUFHELP_FAST_UNALIGNED_ACCESS + const unsigned int longmask = sizeof(uintptr_t) - 1; + + /* Skip fast processing if buffers are unaligned. */ + if (((uintptr_t)dst | (uintptr_t)src1 | (uintptr_t)src2) & longmask) + goto do_bytes; +#endif + + ldst = (uintptr_t *)(void *)dst; + lsrc1 = (const uintptr_t *)(const void *)src1; + lsrc2 = (const uintptr_t *)(const void *)src2; + + for (; len >= sizeof(uintptr_t); len -= sizeof(uintptr_t)) + *ldst++ = *lsrc1++ ^ *lsrc2++; + + dst = (byte *)ldst; + src1 = (const byte *)lsrc1; + src2 = (const byte *)lsrc2; + +#ifndef BUFHELP_FAST_UNALIGNED_ACCESS +do_bytes: +#endif + /* Handle tail. */ + for (; len; len--) + *dst++ = *src1++ ^ *src2++; +} + + +/* Optimized function for buffer xoring with two destination buffers. Used + mainly by CFB mode encryption. */ +static inline void +buf_xor_2dst(void *_dst1, void *_dst2, const void *_src, size_t len) +{ + byte *dst1 = _dst1; + byte *dst2 = _dst2; + const byte *src = _src; + uintptr_t *ldst1, *ldst2; + const uintptr_t *lsrc; +#ifndef BUFHELP_FAST_UNALIGNED_ACCESS + const unsigned int longmask = sizeof(uintptr_t) - 1; + + /* Skip fast processing if buffers are unaligned. */ + if (((uintptr_t)src | (uintptr_t)dst1 | (uintptr_t)dst2) & longmask) + goto do_bytes; +#endif + + ldst1 = (uintptr_t *)(void *)dst1; + ldst2 = (uintptr_t *)(void *)dst2; + lsrc = (const uintptr_t *)(const void *)src; + + for (; len >= sizeof(uintptr_t); len -= sizeof(uintptr_t)) + *ldst1++ = (*ldst2++ ^= *lsrc++); + + dst1 = (byte *)ldst1; + dst2 = (byte *)ldst2; + src = (const byte *)lsrc; + +#ifndef BUFHELP_FAST_UNALIGNED_ACCESS +do_bytes: +#endif + /* Handle tail. */ + for (; len; len--) + *dst1++ = (*dst2++ ^= *src++); +} + + +/* Optimized function for combined buffer xoring and copying. Used by mainly + CBC mode decryption. */ +static inline void +buf_xor_n_copy_2(void *_dst_xor, const void *_src_xor, void *_srcdst_cpy, + const void *_src_cpy, size_t len) +{ + byte *dst_xor = _dst_xor; + byte *srcdst_cpy = _srcdst_cpy; + const byte *src_xor = _src_xor; + const byte *src_cpy = _src_cpy; + byte temp; + uintptr_t *ldst_xor, *lsrcdst_cpy; + const uintptr_t *lsrc_cpy, *lsrc_xor; + uintptr_t ltemp; +#ifndef BUFHELP_FAST_UNALIGNED_ACCESS + const unsigned int longmask = sizeof(uintptr_t) - 1; + + /* Skip fast processing if buffers are unaligned. */ + if (((uintptr_t)src_cpy | (uintptr_t)src_xor | (uintptr_t)dst_xor | + (uintptr_t)srcdst_cpy) & longmask) + goto do_bytes; +#endif + + ldst_xor = (uintptr_t *)(void *)dst_xor; + lsrc_xor = (const uintptr_t *)(void *)src_xor; + lsrcdst_cpy = (uintptr_t *)(void *)srcdst_cpy; + lsrc_cpy = (const uintptr_t *)(const void *)src_cpy; + + for (; len >= sizeof(uintptr_t); len -= sizeof(uintptr_t)) + { + ltemp = *lsrc_cpy++; + *ldst_xor++ = *lsrcdst_cpy ^ *lsrc_xor++; + *lsrcdst_cpy++ = ltemp; + } + + dst_xor = (byte *)ldst_xor; + src_xor = (const byte *)lsrc_xor; + srcdst_cpy = (byte *)lsrcdst_cpy; + src_cpy = (const byte *)lsrc_cpy; + +#ifndef BUFHELP_FAST_UNALIGNED_ACCESS +do_bytes: +#endif + /* Handle tail. */ + for (; len; len--) + { + temp = *src_cpy++; + *dst_xor++ = *srcdst_cpy ^ *src_xor++; + *srcdst_cpy++ = temp; + } +} + + +/* Optimized function for combined buffer xoring and copying. Used by mainly + CFB mode decryption. */ +static inline void +buf_xor_n_copy(void *_dst_xor, void *_srcdst_cpy, const void *_src, size_t len) +{ + buf_xor_n_copy_2(_dst_xor, _src, _srcdst_cpy, _src, len); +} + + +/* Constant-time compare of two buffers. Returns 1 if buffers are equal, + and 0 if buffers differ. */ +static inline int +buf_eq_const(const void *_a, const void *_b, size_t len) +{ + const byte *a = _a; + const byte *b = _b; + size_t diff, i; + + /* Constant-time compare. */ + for (i = 0, diff = 0; i < len; i++) + diff -= !!(a[i] - b[i]); + + return !diff; +} + + +#ifndef BUFHELP_FAST_UNALIGNED_ACCESS + +/* Functions for loading and storing unaligned u32 values of different + endianness. */ +static inline u32 buf_get_be32(const void *_buf) +{ + const byte *in = _buf; + return ((u32)in[0] << 24) | ((u32)in[1] << 16) | \ + ((u32)in[2] << 8) | (u32)in[3]; +} + +static inline u32 buf_get_le32(const void *_buf) +{ + const byte *in = _buf; + return ((u32)in[3] << 24) | ((u32)in[2] << 16) | \ + ((u32)in[1] << 8) | (u32)in[0]; +} + +static inline void buf_put_be32(void *_buf, u32 val) +{ + byte *out = _buf; + out[0] = val >> 24; + out[1] = val >> 16; + out[2] = val >> 8; + out[3] = val; +} + +static inline void buf_put_le32(void *_buf, u32 val) +{ + byte *out = _buf; + out[3] = val >> 24; + out[2] = val >> 16; + out[1] = val >> 8; + out[0] = val; +} + +#ifdef HAVE_U64_TYPEDEF +/* Functions for loading and storing unaligned u64 values of different + endianness. */ +static inline u64 buf_get_be64(const void *_buf) +{ + const byte *in = _buf; + return ((u64)in[0] << 56) | ((u64)in[1] << 48) | \ + ((u64)in[2] << 40) | ((u64)in[3] << 32) | \ + ((u64)in[4] << 24) | ((u64)in[5] << 16) | \ + ((u64)in[6] << 8) | (u64)in[7]; +} + +static inline u64 buf_get_le64(const void *_buf) +{ + const byte *in = _buf; + return ((u64)in[7] << 56) | ((u64)in[6] << 48) | \ + ((u64)in[5] << 40) | ((u64)in[4] << 32) | \ + ((u64)in[3] << 24) | ((u64)in[2] << 16) | \ + ((u64)in[1] << 8) | (u64)in[0]; +} + +static inline void buf_put_be64(void *_buf, u64 val) +{ + byte *out = _buf; + out[0] = val >> 56; + out[1] = val >> 48; + out[2] = val >> 40; + out[3] = val >> 32; + out[4] = val >> 24; + out[5] = val >> 16; + out[6] = val >> 8; + out[7] = val; +} + +static inline void buf_put_le64(void *_buf, u64 val) +{ + byte *out = _buf; + out[7] = val >> 56; + out[6] = val >> 48; + out[5] = val >> 40; + out[4] = val >> 32; + out[3] = val >> 24; + out[2] = val >> 16; + out[1] = val >> 8; + out[0] = val; +} +#endif /*HAVE_U64_TYPEDEF*/ + +#else /*BUFHELP_FAST_UNALIGNED_ACCESS*/ + +/* Functions for loading and storing unaligned u32 values of different + endianness. */ +static inline u32 buf_get_be32(const void *_buf) +{ + return be_bswap32(*(const u32 *)_buf); +} + +static inline u32 buf_get_le32(const void *_buf) +{ + return le_bswap32(*(const u32 *)_buf); +} + +static inline void buf_put_be32(void *_buf, u32 val) +{ + u32 *out = _buf; + *out = be_bswap32(val); +} + +static inline void buf_put_le32(void *_buf, u32 val) +{ + u32 *out = _buf; + *out = le_bswap32(val); +} + +#ifdef HAVE_U64_TYPEDEF +/* Functions for loading and storing unaligned u64 values of different + endianness. */ +static inline u64 buf_get_be64(const void *_buf) +{ + return be_bswap64(*(const u64 *)_buf); +} + +static inline u64 buf_get_le64(const void *_buf) +{ + return le_bswap64(*(const u64 *)_buf); +} + +static inline void buf_put_be64(void *_buf, u64 val) +{ + u64 *out = _buf; + *out = be_bswap64(val); +} + +static inline void buf_put_le64(void *_buf, u64 val) +{ + u64 *out = _buf; + *out = le_bswap64(val); +} +#endif /*HAVE_U64_TYPEDEF*/ + +#endif /*BUFHELP_FAST_UNALIGNED_ACCESS*/ + +#endif /*G10_BITHELP_H*/ diff --git a/plugins/MirOTR/Libgcrypt/cipher/camellia-glue.c b/plugins/MirOTR/Libgcrypt/cipher/camellia-glue.c index 067af85bca..f18d13588c 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/camellia-glue.c +++ b/plugins/MirOTR/Libgcrypt/cipher/camellia-glue.c @@ -32,7 +32,7 @@ * space of the library clean. The following macro is thus useful: * * #define CAMELLIA_EXT_SYM_PREFIX foo_ - * + * * This prefixes all external symbols with "foo_". */ #ifdef HAVE_CONFIG_H @@ -50,7 +50,7 @@ #define camellia_encrypt128 CAMELLIA_PREFIX(camellia_encrypt128) #define camellia_encrypt256 CAMELLIA_PREFIX(camellia_encrypt256) #define camellia_setup128 CAMELLIA_PREFIX(camellia_setup128) -#define camellia_setup192 CAMELLIA_PREFIX(camellia_setup192) +#define camellia_setup192 CAMELLIA_PREFIX(camellia_setup192) #define camellia_setup256 CAMELLIA_PREFIX(camellia_setup256) #endif /*CAMELLIA_EXT_SYM_PREFIX*/ @@ -62,13 +62,88 @@ #include "g10lib.h" #include "cipher.h" #include "camellia.h" +#include "bufhelp.h" +#include "cipher-selftest.h" + +/* Helper macro to force alignment to 16 bytes. */ +#ifdef HAVE_GCC_ATTRIBUTE_ALIGNED +# define ATTR_ALIGNED_16 __attribute__ ((aligned (16))) +#else +# define ATTR_ALIGNED_16 +#endif + +/* USE_AESNI inidicates whether to compile with Intel AES-NI/AVX code. */ +#undef USE_AESNI_AVX +#if defined(ENABLE_AESNI_SUPPORT) && defined(ENABLE_AVX_SUPPORT) +# if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) +# define USE_AESNI_AVX 1 +# endif +#endif + +/* USE_AESNI_AVX2 inidicates whether to compile with Intel AES-NI/AVX2 code. */ +#undef USE_AESNI_AVX2 +#if defined(ENABLE_AESNI_SUPPORT) && defined(ENABLE_AVX2_SUPPORT) +# if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) +# define USE_AESNI_AVX2 1 +# endif +#endif typedef struct { - int keybitlength; KEY_TABLE_TYPE keytable; + int keybitlength; +#ifdef USE_AESNI_AVX + unsigned int use_aesni_avx:1; /* AES-NI/AVX implementation shall be used. */ +#endif /*USE_AESNI_AVX*/ +#ifdef USE_AESNI_AVX2 + unsigned int use_aesni_avx2:1;/* AES-NI/AVX2 implementation shall be used. */ +#endif /*USE_AESNI_AVX2*/ } CAMELLIA_context; +#ifdef USE_AESNI_AVX +/* Assembler implementations of Camellia using AES-NI and AVX. Process data + in 16 block same time. + */ +extern void _gcry_camellia_aesni_avx_ctr_enc(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *ctr); + +extern void _gcry_camellia_aesni_avx_cbc_dec(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *iv); + +extern void _gcry_camellia_aesni_avx_cfb_dec(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *iv); + +extern void _gcry_camellia_aesni_avx_keygen(CAMELLIA_context *ctx, + const unsigned char *key, + unsigned int keylen); +#endif + +#ifdef USE_AESNI_AVX2 +/* Assembler implementations of Camellia using AES-NI and AVX2. Process data + in 32 block same time. + */ +extern void _gcry_camellia_aesni_avx2_ctr_enc(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *ctr); + +extern void _gcry_camellia_aesni_avx2_cbc_dec(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *iv); + +extern void _gcry_camellia_aesni_avx2_cfb_dec(CAMELLIA_context *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *iv); +#endif + static const char *selftest(void); static gcry_err_code_t @@ -77,6 +152,9 @@ camellia_setkey(void *c, const byte *key, unsigned keylen) CAMELLIA_context *ctx=c; static int initialized=0; static const char *selftest_failed=NULL; +#if defined(USE_AESNI_AVX) || defined(USE_AESNI_AVX2) + unsigned int hwf = _gcry_get_hw_features (); +#endif if(keylen!=16 && keylen!=24 && keylen!=32) return GPG_ERR_INV_KEYLEN; @@ -92,44 +170,414 @@ camellia_setkey(void *c, const byte *key, unsigned keylen) if(selftest_failed) return GPG_ERR_SELFTEST_FAILED; +#ifdef USE_AESNI_AVX + ctx->use_aesni_avx = (hwf & HWF_INTEL_AESNI) && (hwf & HWF_INTEL_AVX); +#endif +#ifdef USE_AESNI_AVX2 + ctx->use_aesni_avx2 = (hwf & HWF_INTEL_AESNI) && (hwf & HWF_INTEL_AVX2); +#endif + ctx->keybitlength=keylen*8; - Camellia_Ekeygen(ctx->keybitlength,key,ctx->keytable); - _gcry_burn_stack - ((19+34+34)*sizeof(u32)+2*sizeof(void*) /* camellia_setup256 */ - +(4+32)*sizeof(u32)+2*sizeof(void*) /* camellia_setup192 */ - +0+sizeof(int)+2*sizeof(void*) /* Camellia_Ekeygen */ - +3*2*sizeof(void*) /* Function calls. */ - ); + + if (0) + { } +#ifdef USE_AESNI_AVX + else if (ctx->use_aesni_avx) + _gcry_camellia_aesni_avx_keygen(ctx, key, keylen); + else +#endif + { + Camellia_Ekeygen(ctx->keybitlength,key,ctx->keytable); + _gcry_burn_stack + ((19+34+34)*sizeof(u32)+2*sizeof(void*) /* camellia_setup256 */ + +(4+32)*sizeof(u32)+2*sizeof(void*) /* camellia_setup192 */ + +0+sizeof(int)+2*sizeof(void*) /* Camellia_Ekeygen */ + +3*2*sizeof(void*) /* Function calls. */ + ); + } return 0; } -static void +#ifdef USE_ARM_ASM + +/* Assembly implementations of Camellia. */ +extern void _gcry_camellia_arm_encrypt_block(const KEY_TABLE_TYPE keyTable, + byte *outbuf, const byte *inbuf, + const int keybits); + +extern void _gcry_camellia_arm_decrypt_block(const KEY_TABLE_TYPE keyTable, + byte *outbuf, const byte *inbuf, + const int keybits); + +static void Camellia_EncryptBlock(const int keyBitLength, + const unsigned char *plaintext, + const KEY_TABLE_TYPE keyTable, + unsigned char *cipherText) +{ + _gcry_camellia_arm_encrypt_block(keyTable, cipherText, plaintext, + keyBitLength); +} + +static void Camellia_DecryptBlock(const int keyBitLength, + const unsigned char *cipherText, + const KEY_TABLE_TYPE keyTable, + unsigned char *plaintext) +{ + _gcry_camellia_arm_decrypt_block(keyTable, plaintext, cipherText, + keyBitLength); +} + +static unsigned int +camellia_encrypt(void *c, byte *outbuf, const byte *inbuf) +{ + CAMELLIA_context *ctx = c; + Camellia_EncryptBlock(ctx->keybitlength,inbuf,ctx->keytable,outbuf); +#define CAMELLIA_encrypt_stack_burn_size (15*4) + return /*burn_stack*/ (CAMELLIA_encrypt_stack_burn_size); +} + +static unsigned int +camellia_decrypt(void *c, byte *outbuf, const byte *inbuf) +{ + CAMELLIA_context *ctx=c; + Camellia_DecryptBlock(ctx->keybitlength,inbuf,ctx->keytable,outbuf); +#define CAMELLIA_decrypt_stack_burn_size (15*4) + return /*burn_stack*/ (CAMELLIA_decrypt_stack_burn_size); +} + +#else /*USE_ARM_ASM*/ + +static unsigned int camellia_encrypt(void *c, byte *outbuf, const byte *inbuf) { CAMELLIA_context *ctx=c; Camellia_EncryptBlock(ctx->keybitlength,inbuf,ctx->keytable,outbuf); - _gcry_burn_stack - (sizeof(int)+2*sizeof(unsigned char *)+sizeof(KEY_TABLE_TYPE) - +4*sizeof(u32) - +2*sizeof(u32*)+4*sizeof(u32) - +2*2*sizeof(void*) /* Function calls. */ - ); + +#define CAMELLIA_encrypt_stack_burn_size \ + (sizeof(int)+2*sizeof(unsigned char *)+sizeof(void*/*KEY_TABLE_TYPE*/) \ + +4*sizeof(u32)+4*sizeof(u32) \ + +2*sizeof(u32*)+4*sizeof(u32) \ + +2*2*sizeof(void*) /* Function calls. */ \ + ) + + return /*burn_stack*/ (CAMELLIA_encrypt_stack_burn_size); } -static void +static unsigned int camellia_decrypt(void *c, byte *outbuf, const byte *inbuf) { CAMELLIA_context *ctx=c; Camellia_DecryptBlock(ctx->keybitlength,inbuf,ctx->keytable,outbuf); - _gcry_burn_stack - (sizeof(int)+2*sizeof(unsigned char *)+sizeof(KEY_TABLE_TYPE) - +4*sizeof(u32) - +2*sizeof(u32*)+4*sizeof(u32) - +2*2*sizeof(void*) /* Function calls. */ - ); + +#define CAMELLIA_decrypt_stack_burn_size \ + (sizeof(int)+2*sizeof(unsigned char *)+sizeof(void*/*KEY_TABLE_TYPE*/) \ + +4*sizeof(u32)+4*sizeof(u32) \ + +2*sizeof(u32*)+4*sizeof(u32) \ + +2*2*sizeof(void*) /* Function calls. */ \ + ) + + return /*burn_stack*/ (CAMELLIA_decrypt_stack_burn_size); +} + +#endif /*!USE_ARM_ASM*/ + +/* Bulk encryption of complete blocks in CTR mode. This function is only + intended for the bulk encryption feature of cipher.c. CTR is expected to be + of size CAMELLIA_BLOCK_SIZE. */ +void +_gcry_camellia_ctr_enc(void *context, unsigned char *ctr, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks) +{ + CAMELLIA_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char tmpbuf[CAMELLIA_BLOCK_SIZE]; + int burn_stack_depth = CAMELLIA_encrypt_stack_burn_size; + int i; + +#ifdef USE_AESNI_AVX2 + if (ctx->use_aesni_avx2) + { + int did_use_aesni_avx2 = 0; + + /* Process data in 32 block chunks. */ + while (nblocks >= 32) + { + _gcry_camellia_aesni_avx2_ctr_enc(ctx, outbuf, inbuf, ctr); + + nblocks -= 32; + outbuf += 32 * CAMELLIA_BLOCK_SIZE; + inbuf += 32 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx2 = 1; + } + + if (did_use_aesni_avx2) + { + int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + 16 + + 2 * sizeof(void *); + + if (burn_stack_depth < avx2_burn_stack_depth) + burn_stack_depth = avx2_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + /* TODO: use caching instead? */ + } +#endif + +#ifdef USE_AESNI_AVX + if (ctx->use_aesni_avx) + { + int did_use_aesni_avx = 0; + + /* Process data in 16 block chunks. */ + while (nblocks >= 16) + { + _gcry_camellia_aesni_avx_ctr_enc(ctx, outbuf, inbuf, ctr); + + nblocks -= 16; + outbuf += 16 * CAMELLIA_BLOCK_SIZE; + inbuf += 16 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx = 1; + } + + if (did_use_aesni_avx) + { + if (burn_stack_depth < 16 * CAMELLIA_BLOCK_SIZE + 2 * sizeof(void *)) + burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE + 2 * sizeof(void *); + } + + /* Use generic code to handle smaller chunks... */ + /* TODO: use caching instead? */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* Encrypt the counter. */ + Camellia_EncryptBlock(ctx->keybitlength, ctr, ctx->keytable, tmpbuf); + /* XOR the input with the encrypted counter and store in output. */ + buf_xor(outbuf, tmpbuf, inbuf, CAMELLIA_BLOCK_SIZE); + outbuf += CAMELLIA_BLOCK_SIZE; + inbuf += CAMELLIA_BLOCK_SIZE; + /* Increment the counter. */ + for (i = CAMELLIA_BLOCK_SIZE; i > 0; i--) + { + ctr[i-1]++; + if (ctr[i-1]) + break; + } + } + + wipememory(tmpbuf, sizeof(tmpbuf)); + _gcry_burn_stack(burn_stack_depth); +} + +/* Bulk decryption of complete blocks in CBC mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +void +_gcry_camellia_cbc_dec(void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks) +{ + CAMELLIA_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char savebuf[CAMELLIA_BLOCK_SIZE]; + int burn_stack_depth = CAMELLIA_decrypt_stack_burn_size; + +#ifdef USE_AESNI_AVX2 + if (ctx->use_aesni_avx2) + { + int did_use_aesni_avx2 = 0; + + /* Process data in 32 block chunks. */ + while (nblocks >= 32) + { + _gcry_camellia_aesni_avx2_cbc_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 32; + outbuf += 32 * CAMELLIA_BLOCK_SIZE; + inbuf += 32 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx2 = 1; + } + + if (did_use_aesni_avx2) + { + int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + 16 + + 2 * sizeof(void *); + + if (burn_stack_depth < avx2_burn_stack_depth) + burn_stack_depth = avx2_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#ifdef USE_AESNI_AVX + if (ctx->use_aesni_avx) + { + int did_use_aesni_avx = 0; + + /* Process data in 16 block chunks. */ + while (nblocks >= 16) + { + _gcry_camellia_aesni_avx_cbc_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 16; + outbuf += 16 * CAMELLIA_BLOCK_SIZE; + inbuf += 16 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx = 1; + } + + if (did_use_aesni_avx) + { + if (burn_stack_depth < 16 * CAMELLIA_BLOCK_SIZE + 2 * sizeof(void *)) + burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE + 2 * sizeof(void *); + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* INBUF is needed later and it may be identical to OUTBUF, so store + the intermediate result to SAVEBUF. */ + Camellia_DecryptBlock(ctx->keybitlength, inbuf, ctx->keytable, savebuf); + + buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, CAMELLIA_BLOCK_SIZE); + inbuf += CAMELLIA_BLOCK_SIZE; + outbuf += CAMELLIA_BLOCK_SIZE; + } + + wipememory(savebuf, sizeof(savebuf)); + _gcry_burn_stack(burn_stack_depth); +} + +/* Bulk decryption of complete blocks in CFB mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +void +_gcry_camellia_cfb_dec(void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks) +{ + CAMELLIA_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + int burn_stack_depth = CAMELLIA_decrypt_stack_burn_size; + +#ifdef USE_AESNI_AVX2 + if (ctx->use_aesni_avx2) + { + int did_use_aesni_avx2 = 0; + + /* Process data in 32 block chunks. */ + while (nblocks >= 32) + { + _gcry_camellia_aesni_avx2_cfb_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 32; + outbuf += 32 * CAMELLIA_BLOCK_SIZE; + inbuf += 32 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx2 = 1; + } + + if (did_use_aesni_avx2) + { + int avx2_burn_stack_depth = 32 * CAMELLIA_BLOCK_SIZE + 16 + + 2 * sizeof(void *); + + if (burn_stack_depth < avx2_burn_stack_depth) + burn_stack_depth = avx2_burn_stack_depth; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#ifdef USE_AESNI_AVX + if (ctx->use_aesni_avx) + { + int did_use_aesni_avx = 0; + + /* Process data in 16 block chunks. */ + while (nblocks >= 16) + { + _gcry_camellia_aesni_avx_cfb_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 16; + outbuf += 16 * CAMELLIA_BLOCK_SIZE; + inbuf += 16 * CAMELLIA_BLOCK_SIZE; + did_use_aesni_avx = 1; + } + + if (did_use_aesni_avx) + { + if (burn_stack_depth < 16 * CAMELLIA_BLOCK_SIZE + 2 * sizeof(void *)) + burn_stack_depth = 16 * CAMELLIA_BLOCK_SIZE + 2 * sizeof(void *); + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + Camellia_EncryptBlock(ctx->keybitlength, iv, ctx->keytable, iv); + buf_xor_n_copy(outbuf, iv, inbuf, CAMELLIA_BLOCK_SIZE); + outbuf += CAMELLIA_BLOCK_SIZE; + inbuf += CAMELLIA_BLOCK_SIZE; + } + + _gcry_burn_stack(burn_stack_depth); +} + +/* Run the self-tests for CAMELLIA-CTR-128, tests IV increment of bulk CTR + encryption. Returns NULL on success. */ +static const char* +selftest_ctr_128 (void) +{ + const int nblocks = 32+16+1; + const int blocksize = CAMELLIA_BLOCK_SIZE; + const int context_size = sizeof(CAMELLIA_context); + + return _gcry_selftest_helper_ctr("CAMELLIA", &camellia_setkey, + &camellia_encrypt, &_gcry_camellia_ctr_enc, nblocks, blocksize, + context_size); +} + +/* Run the self-tests for CAMELLIA-CBC-128, tests bulk CBC decryption. + Returns NULL on success. */ +static const char* +selftest_cbc_128 (void) +{ + const int nblocks = 32+16+2; + const int blocksize = CAMELLIA_BLOCK_SIZE; + const int context_size = sizeof(CAMELLIA_context); + + return _gcry_selftest_helper_cbc("CAMELLIA", &camellia_setkey, + &camellia_encrypt, &_gcry_camellia_cbc_dec, nblocks, blocksize, + context_size); +} + +/* Run the self-tests for CAMELLIA-CFB-128, tests bulk CFB decryption. + Returns NULL on success. */ +static const char* +selftest_cfb_128 (void) +{ + const int nblocks = 32+16+2; + const int blocksize = CAMELLIA_BLOCK_SIZE; + const int context_size = sizeof(CAMELLIA_context); + + return _gcry_selftest_helper_cfb("CAMELLIA", &camellia_setkey, + &camellia_encrypt, &_gcry_camellia_cfb_dec, nblocks, blocksize, + context_size); } static const char * @@ -137,40 +585,41 @@ selftest(void) { CAMELLIA_context ctx; byte scratch[16]; - + const char *r; + /* These test vectors are from RFC-3713 */ - const byte plaintext[]= + static const byte plaintext[]= { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, 0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 }; - const byte key_128[]= + static const byte key_128[]= { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, 0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10 }; - const byte ciphertext_128[]= + static const byte ciphertext_128[]= { 0x67,0x67,0x31,0x38,0x54,0x96,0x69,0x73, 0x08,0x57,0x06,0x56,0x48,0xea,0xbe,0x43 }; - const byte key_192[]= + static const byte key_192[]= { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba,0x98, 0x76,0x54,0x32,0x10,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77 }; - const byte ciphertext_192[]= + static const byte ciphertext_192[]= { 0xb4,0x99,0x34,0x01,0xb3,0xe9,0x96,0xf8, 0x4e,0xe5,0xce,0xe7,0xd7,0x9b,0x09,0xb9 }; - const byte key_256[]= + static const byte key_256[]= { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0xfe,0xdc,0xba, 0x98,0x76,0x54,0x32,0x10,0x00,0x11,0x22,0x33,0x44,0x55, 0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff }; - const byte ciphertext_256[]= + static const byte ciphertext_256[]= { 0x9a,0xcc,0x23,0x7d,0xff,0x16,0xd7,0x6c, 0x20,0xef,0x7c,0x91,0x9e,0x3a,0x75,0x09 @@ -200,6 +649,15 @@ selftest(void) if(memcmp(scratch,plaintext,sizeof(plaintext))!=0) return "CAMELLIA-256 test decryption failed."; + if ( (r = selftest_ctr_128 ()) ) + return r; + + if ( (r = selftest_cbc_128 ()) ) + return r; + + if ( (r = selftest_cfb_128 ()) ) + return r; + return NULL; } @@ -236,18 +694,21 @@ static gcry_cipher_oid_spec_t camellia256_oids[] = gcry_cipher_spec_t _gcry_cipher_spec_camellia128 = { + GCRY_CIPHER_CAMELLIA128, {0, 0}, "CAMELLIA128",NULL,camellia128_oids,CAMELLIA_BLOCK_SIZE,128, sizeof(CAMELLIA_context),camellia_setkey,camellia_encrypt,camellia_decrypt }; gcry_cipher_spec_t _gcry_cipher_spec_camellia192 = { + GCRY_CIPHER_CAMELLIA192, {0, 0}, "CAMELLIA192",NULL,camellia192_oids,CAMELLIA_BLOCK_SIZE,192, sizeof(CAMELLIA_context),camellia_setkey,camellia_encrypt,camellia_decrypt }; gcry_cipher_spec_t _gcry_cipher_spec_camellia256 = { + GCRY_CIPHER_CAMELLIA256, {0, 0}, "CAMELLIA256",NULL,camellia256_oids,CAMELLIA_BLOCK_SIZE,256, sizeof(CAMELLIA_context),camellia_setkey,camellia_encrypt,camellia_decrypt }; diff --git a/plugins/MirOTR/Libgcrypt/cipher/camellia.c b/plugins/MirOTR/Libgcrypt/cipher/camellia.c index 79cd49b7cd..e7085a7ec8 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/camellia.c +++ b/plugins/MirOTR/Libgcrypt/cipher/camellia.c @@ -14,23 +14,23 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * License along with this program; if not, see <http://www.gnu.org/licenses/>. */ /* - * Algorithm Specification + * Algorithm Specification * http://info.isl.ntt.co.jp/crypt/eng/camellia/specifications.html */ +#include <config.h> #include <string.h> #include <stdlib.h> +#include "types.h" +#include "bufhelp.h" #include "camellia.h" -/* u32 must be 32bit word */ -typedef unsigned int u32; -typedef unsigned char u8; +typedef byte u8; /* key constants */ @@ -60,17 +60,8 @@ typedef unsigned char u8; #else /* not MS-VC */ -# define GETU32(pt) \ - (((u32)(pt)[0] << 24) \ - ^ ((u32)(pt)[1] << 16) \ - ^ ((u32)(pt)[2] << 8) \ - ^ ((u32)(pt)[3])) - -# define PUTU32(ct, st) { \ - (ct)[0] = (u8)((st) >> 24); \ - (ct)[1] = (u8)((st) >> 16); \ - (ct)[2] = (u8)((st) >> 8); \ - (ct)[3] = (u8)(st); } +# define GETU32(pt) buf_get_be32(pt) +# define PUTU32(ct, st) buf_put_be32(ct, st) #endif @@ -151,6 +142,8 @@ typedef unsigned char u8; #define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) \ do { \ + yl ^= kl; \ + yr ^= kr; \ ir = CAMELLIA_SP1110(xr & 0xff) \ ^ CAMELLIA_SP0222((xr >> 24) & 0xff) \ ^ CAMELLIA_SP3033((xr >> 16) & 0xff) \ @@ -159,8 +152,6 @@ typedef unsigned char u8; ^ CAMELLIA_SP0222((xl >> 16) & 0xff) \ ^ CAMELLIA_SP3033((xl >> 8) & 0xff) \ ^ CAMELLIA_SP4404(xl & 0xff); \ - il ^= kl; \ - ir ^= kr; \ ir ^= il; \ il = CAMELLIA_RR8(il); \ il ^= ir; \ @@ -614,44 +605,6 @@ void camellia_setup128(const unsigned char *key, u32 *subkey) CamelliaSubkeyL(24) = subl(24) ^ subl(23); CamelliaSubkeyR(24) = subr(24) ^ subr(23); - /* apply the inverse of the last half of P-function */ - dw = CamelliaSubkeyL(2) ^ CamelliaSubkeyR(2), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(2) = CamelliaSubkeyL(2) ^ dw, CamelliaSubkeyL(2) = dw; - dw = CamelliaSubkeyL(3) ^ CamelliaSubkeyR(3), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(3) = CamelliaSubkeyL(3) ^ dw, CamelliaSubkeyL(3) = dw; - dw = CamelliaSubkeyL(4) ^ CamelliaSubkeyR(4), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(4) = CamelliaSubkeyL(4) ^ dw, CamelliaSubkeyL(4) = dw; - dw = CamelliaSubkeyL(5) ^ CamelliaSubkeyR(5), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(5) = CamelliaSubkeyL(5) ^ dw, CamelliaSubkeyL(5) = dw; - dw = CamelliaSubkeyL(6) ^ CamelliaSubkeyR(6), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(6) = CamelliaSubkeyL(6) ^ dw, CamelliaSubkeyL(6) = dw; - dw = CamelliaSubkeyL(7) ^ CamelliaSubkeyR(7), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(7) = CamelliaSubkeyL(7) ^ dw, CamelliaSubkeyL(7) = dw; - dw = CamelliaSubkeyL(10) ^ CamelliaSubkeyR(10), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(10) = CamelliaSubkeyL(10) ^ dw, CamelliaSubkeyL(10) = dw; - dw = CamelliaSubkeyL(11) ^ CamelliaSubkeyR(11), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(11) = CamelliaSubkeyL(11) ^ dw, CamelliaSubkeyL(11) = dw; - dw = CamelliaSubkeyL(12) ^ CamelliaSubkeyR(12), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(12) = CamelliaSubkeyL(12) ^ dw, CamelliaSubkeyL(12) = dw; - dw = CamelliaSubkeyL(13) ^ CamelliaSubkeyR(13), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(13) = CamelliaSubkeyL(13) ^ dw, CamelliaSubkeyL(13) = dw; - dw = CamelliaSubkeyL(14) ^ CamelliaSubkeyR(14), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(14) = CamelliaSubkeyL(14) ^ dw, CamelliaSubkeyL(14) = dw; - dw = CamelliaSubkeyL(15) ^ CamelliaSubkeyR(15), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(15) = CamelliaSubkeyL(15) ^ dw, CamelliaSubkeyL(15) = dw; - dw = CamelliaSubkeyL(18) ^ CamelliaSubkeyR(18), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(18) = CamelliaSubkeyL(18) ^ dw, CamelliaSubkeyL(18) = dw; - dw = CamelliaSubkeyL(19) ^ CamelliaSubkeyR(19), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(19) = CamelliaSubkeyL(19) ^ dw, CamelliaSubkeyL(19) = dw; - dw = CamelliaSubkeyL(20) ^ CamelliaSubkeyR(20), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(20) = CamelliaSubkeyL(20) ^ dw, CamelliaSubkeyL(20) = dw; - dw = CamelliaSubkeyL(21) ^ CamelliaSubkeyR(21), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(21) = CamelliaSubkeyL(21) ^ dw, CamelliaSubkeyL(21) = dw; - dw = CamelliaSubkeyL(22) ^ CamelliaSubkeyR(22), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(22) = CamelliaSubkeyL(22) ^ dw, CamelliaSubkeyL(22) = dw; - dw = CamelliaSubkeyL(23) ^ CamelliaSubkeyR(23), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(23) = CamelliaSubkeyL(23) ^ dw, CamelliaSubkeyL(23) = dw; - return; } @@ -888,56 +841,6 @@ void camellia_setup256(const unsigned char *key, u32 *subkey) CamelliaSubkeyL(32) = subl(32) ^ subl(31); CamelliaSubkeyR(32) = subr(32) ^ subr(31); - /* apply the inverse of the last half of P-function */ - dw = CamelliaSubkeyL(2) ^ CamelliaSubkeyR(2), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(2) = CamelliaSubkeyL(2) ^ dw, CamelliaSubkeyL(2) = dw; - dw = CamelliaSubkeyL(3) ^ CamelliaSubkeyR(3), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(3) = CamelliaSubkeyL(3) ^ dw, CamelliaSubkeyL(3) = dw; - dw = CamelliaSubkeyL(4) ^ CamelliaSubkeyR(4), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(4) = CamelliaSubkeyL(4) ^ dw, CamelliaSubkeyL(4) = dw; - dw = CamelliaSubkeyL(5) ^ CamelliaSubkeyR(5), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(5) = CamelliaSubkeyL(5) ^ dw, CamelliaSubkeyL(5) = dw; - dw = CamelliaSubkeyL(6) ^ CamelliaSubkeyR(6), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(6) = CamelliaSubkeyL(6) ^ dw, CamelliaSubkeyL(6) = dw; - dw = CamelliaSubkeyL(7) ^ CamelliaSubkeyR(7), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(7) = CamelliaSubkeyL(7) ^ dw, CamelliaSubkeyL(7) = dw; - dw = CamelliaSubkeyL(10) ^ CamelliaSubkeyR(10), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(10) = CamelliaSubkeyL(10) ^ dw, CamelliaSubkeyL(10) = dw; - dw = CamelliaSubkeyL(11) ^ CamelliaSubkeyR(11), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(11) = CamelliaSubkeyL(11) ^ dw, CamelliaSubkeyL(11) = dw; - dw = CamelliaSubkeyL(12) ^ CamelliaSubkeyR(12), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(12) = CamelliaSubkeyL(12) ^ dw, CamelliaSubkeyL(12) = dw; - dw = CamelliaSubkeyL(13) ^ CamelliaSubkeyR(13), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(13) = CamelliaSubkeyL(13) ^ dw, CamelliaSubkeyL(13) = dw; - dw = CamelliaSubkeyL(14) ^ CamelliaSubkeyR(14), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(14) = CamelliaSubkeyL(14) ^ dw, CamelliaSubkeyL(14) = dw; - dw = CamelliaSubkeyL(15) ^ CamelliaSubkeyR(15), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(15) = CamelliaSubkeyL(15) ^ dw, CamelliaSubkeyL(15) = dw; - dw = CamelliaSubkeyL(18) ^ CamelliaSubkeyR(18), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(18) = CamelliaSubkeyL(18) ^ dw, CamelliaSubkeyL(18) = dw; - dw = CamelliaSubkeyL(19) ^ CamelliaSubkeyR(19), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(19) = CamelliaSubkeyL(19) ^ dw, CamelliaSubkeyL(19) = dw; - dw = CamelliaSubkeyL(20) ^ CamelliaSubkeyR(20), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(20) = CamelliaSubkeyL(20) ^ dw, CamelliaSubkeyL(20) = dw; - dw = CamelliaSubkeyL(21) ^ CamelliaSubkeyR(21), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(21) = CamelliaSubkeyL(21) ^ dw, CamelliaSubkeyL(21) = dw; - dw = CamelliaSubkeyL(22) ^ CamelliaSubkeyR(22), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(22) = CamelliaSubkeyL(22) ^ dw, CamelliaSubkeyL(22) = dw; - dw = CamelliaSubkeyL(23) ^ CamelliaSubkeyR(23), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(23) = CamelliaSubkeyL(23) ^ dw, CamelliaSubkeyL(23) = dw; - dw = CamelliaSubkeyL(26) ^ CamelliaSubkeyR(26), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(26) = CamelliaSubkeyL(26) ^ dw, CamelliaSubkeyL(26) = dw; - dw = CamelliaSubkeyL(27) ^ CamelliaSubkeyR(27), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(27) = CamelliaSubkeyL(27) ^ dw, CamelliaSubkeyL(27) = dw; - dw = CamelliaSubkeyL(28) ^ CamelliaSubkeyR(28), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(28) = CamelliaSubkeyL(28) ^ dw, CamelliaSubkeyL(28) = dw; - dw = CamelliaSubkeyL(29) ^ CamelliaSubkeyR(29), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(29) = CamelliaSubkeyL(29) ^ dw, CamelliaSubkeyL(29) = dw; - dw = CamelliaSubkeyL(30) ^ CamelliaSubkeyR(30), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(30) = CamelliaSubkeyL(30) ^ dw, CamelliaSubkeyL(30) = dw; - dw = CamelliaSubkeyL(31) ^ CamelliaSubkeyR(31), dw = CAMELLIA_RL8(dw); - CamelliaSubkeyR(31) = CamelliaSubkeyL(31) ^ dw,CamelliaSubkeyL(31) = dw; - return; } @@ -958,14 +861,21 @@ void camellia_setup192(const unsigned char *key, u32 *subkey) } +#ifndef USE_ARM_ASM /** * Stuff related to camellia encryption/decryption * * "io" must be 4byte aligned and big-endian data. */ -void camellia_encrypt128(const u32 *subkey, u32 *io) +void camellia_encrypt128(const u32 *subkey, u32 *blocks) { u32 il, ir, t0, t1; + u32 io[4]; + + io[0] = blocks[0]; + io[1] = blocks[1]; + io[2] = blocks[2]; + io[3] = blocks[3]; /* pre whitening but absorb kw2*/ io[0] ^= CamelliaSubkeyL(0); @@ -1049,14 +959,25 @@ void camellia_encrypt128(const u32 *subkey, u32 *io) io[1] = io[3]; io[2] = t0; io[3] = t1; - + + blocks[0] = io[0]; + blocks[1] = io[1]; + blocks[2] = io[2]; + blocks[3] = io[3]; + return; } -void camellia_decrypt128(const u32 *subkey, u32 *io) +void camellia_decrypt128(const u32 *subkey, u32 *blocks) { u32 il,ir,t0,t1; /* temporary valiables */ - + u32 io[4]; + + io[0] = blocks[0]; + io[1] = blocks[1]; + io[2] = blocks[2]; + io[3] = blocks[3]; + /* pre whitening but absorb kw2*/ io[0] ^= CamelliaSubkeyL(24); io[1] ^= CamelliaSubkeyR(24); @@ -1140,15 +1061,26 @@ void camellia_decrypt128(const u32 *subkey, u32 *io) io[2] = t0; io[3] = t1; + blocks[0] = io[0]; + blocks[1] = io[1]; + blocks[2] = io[2]; + blocks[3] = io[3]; + return; } /** * stuff for 192 and 256bit encryption/decryption */ -void camellia_encrypt256(const u32 *subkey, u32 *io) +void camellia_encrypt256(const u32 *subkey, u32 *blocks) { u32 il,ir,t0,t1; /* temporary valiables */ + u32 io[4]; + + io[0] = blocks[0]; + io[1] = blocks[1]; + io[2] = blocks[2]; + io[3] = blocks[3]; /* pre whitening but absorb kw2*/ io[0] ^= CamelliaSubkeyL(0); @@ -1257,17 +1189,28 @@ void camellia_encrypt256(const u32 *subkey, u32 *io) io[2] = t0; io[3] = t1; + blocks[0] = io[0]; + blocks[1] = io[1]; + blocks[2] = io[2]; + blocks[3] = io[3]; + return; } -void camellia_decrypt256(const u32 *subkey, u32 *io) +void camellia_decrypt256(const u32 *subkey, u32 *blocks) { u32 il,ir,t0,t1; /* temporary valiables */ + u32 io[4]; + + io[0] = blocks[0]; + io[1] = blocks[1]; + io[2] = blocks[2]; + io[3] = blocks[3]; /* pre whitening but absorb kw2*/ io[0] ^= CamelliaSubkeyL(32); io[1] ^= CamelliaSubkeyR(32); - + /* main iteration */ CAMELLIA_ROUNDSM(io[0],io[1], CamelliaSubkeyL(31),CamelliaSubkeyR(31), @@ -1371,16 +1314,23 @@ void camellia_decrypt256(const u32 *subkey, u32 *io) io[2] = t0; io[3] = t1; + blocks[0] = io[0]; + blocks[1] = io[1]; + blocks[2] = io[2]; + blocks[3] = io[3]; + return; } +#endif /*!USE_ARM_ASM*/ + /*** * * API for compatibility */ -void Camellia_Ekeygen(const int keyBitLength, - const unsigned char *rawKey, +void Camellia_Ekeygen(const int keyBitLength, + const unsigned char *rawKey, KEY_TABLE_TYPE keyTable) { switch(keyBitLength) { @@ -1399,9 +1349,10 @@ void Camellia_Ekeygen(const int keyBitLength, } -void Camellia_EncryptBlock(const int keyBitLength, - const unsigned char *plaintext, - const KEY_TABLE_TYPE keyTable, +#ifndef USE_ARM_ASM +void Camellia_EncryptBlock(const int keyBitLength, + const unsigned char *plaintext, + const KEY_TABLE_TYPE keyTable, unsigned char *ciphertext) { u32 tmp[4]; @@ -1430,9 +1381,9 @@ void Camellia_EncryptBlock(const int keyBitLength, PUTU32(ciphertext + 12, tmp[3]); } -void Camellia_DecryptBlock(const int keyBitLength, - const unsigned char *ciphertext, - const KEY_TABLE_TYPE keyTable, +void Camellia_DecryptBlock(const int keyBitLength, + const unsigned char *ciphertext, + const KEY_TABLE_TYPE keyTable, unsigned char *plaintext) { u32 tmp[4]; @@ -1459,3 +1410,4 @@ void Camellia_DecryptBlock(const int keyBitLength, PUTU32(plaintext + 8, tmp[2]); PUTU32(plaintext + 12, tmp[3]); } +#endif /*!USE_ARM_ASM*/ diff --git a/plugins/MirOTR/Libgcrypt/cipher/camellia.h b/plugins/MirOTR/Libgcrypt/cipher/camellia.h index 4425a3a2bc..d0e3c18ed7 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/camellia.h +++ b/plugins/MirOTR/Libgcrypt/cipher/camellia.h @@ -25,11 +25,18 @@ * space of the library clean. The following macro is thus useful: * * #define CAMELLIA_EXT_SYM_PREFIX foo_ - * + * * This prefixes all external symbols with "foo_". */ #ifdef HAVE_CONFIG_H #include <config.h> +/* USE_ARM_ASM indicates whether to use ARM assembly code. */ +# undef USE_ARM_ASM +# if defined(__ARMEL__) +# ifdef HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS +# define USE_ARM_ASM 1 +# endif +# endif #endif #ifdef CAMELLIA_EXT_SYM_PREFIX #define CAMELLIA_PREFIX1(x,y) x ## y @@ -43,7 +50,7 @@ #define camellia_encrypt128 CAMELLIA_PREFIX(camellia_encrypt128) #define camellia_encrypt256 CAMELLIA_PREFIX(camellia_encrypt256) #define camellia_setup128 CAMELLIA_PREFIX(camellia_setup128) -#define camellia_setup192 CAMELLIA_PREFIX(camellia_setup192) +#define camellia_setup192 CAMELLIA_PREFIX(camellia_setup192) #define camellia_setup256 CAMELLIA_PREFIX(camellia_setup256) #endif /*CAMELLIA_EXT_SYM_PREFIX*/ @@ -60,18 +67,20 @@ typedef unsigned int KEY_TABLE_TYPE[CAMELLIA_TABLE_WORD_LEN]; void Camellia_Ekeygen(const int keyBitLength, - const unsigned char *rawKey, + const unsigned char *rawKey, KEY_TABLE_TYPE keyTable); +#ifndef USE_ARM_ASM void Camellia_EncryptBlock(const int keyBitLength, - const unsigned char *plaintext, - const KEY_TABLE_TYPE keyTable, + const unsigned char *plaintext, + const KEY_TABLE_TYPE keyTable, unsigned char *cipherText); -void Camellia_DecryptBlock(const int keyBitLength, - const unsigned char *cipherText, - const KEY_TABLE_TYPE keyTable, +void Camellia_DecryptBlock(const int keyBitLength, + const unsigned char *cipherText, + const KEY_TABLE_TYPE keyTable, unsigned char *plaintext); +#endif /*!USE_ARMV6_ASM*/ #ifdef __cplusplus diff --git a/plugins/MirOTR/Libgcrypt/cipher/cast5.c b/plugins/MirOTR/Libgcrypt/cipher/cast5.c index 333d55e91f..115e1e6241 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/cast5.c +++ b/plugins/MirOTR/Libgcrypt/cipher/cast5.c @@ -42,22 +42,47 @@ #include "g10lib.h" #include "types.h" #include "cipher.h" +#include "bithelp.h" +#include "bufhelp.h" +#include "cipher-selftest.h" + +/* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */ +#undef USE_AMD64_ASM +#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) +# define USE_AMD64_ASM 1 +#endif + +/* USE_ARM_ASM indicates whether to use ARM assembly code. */ +#undef USE_ARM_ASM +#if defined(__ARMEL__) +# ifdef HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS +# define USE_ARM_ASM 1 +# endif +#endif #define CAST5_BLOCKSIZE 8 typedef struct { u32 Km[16]; byte Kr[16]; +#ifdef USE_ARM_ASM + u32 Kr_arm_enc[16 / sizeof(u32)]; + u32 Kr_arm_dec[16 / sizeof(u32)]; +#endif } CAST5_context; static gcry_err_code_t cast_setkey (void *c, const byte *key, unsigned keylen); -static void encrypt_block (void *c, byte *outbuf, const byte *inbuf); -static void decrypt_block (void *c, byte *outbuf, const byte *inbuf); +static unsigned int encrypt_block (void *c, byte *outbuf, const byte *inbuf); +static unsigned int decrypt_block (void *c, byte *outbuf, const byte *inbuf); +#define s1 _gcry_cast5_s1to4[0] +#define s2 _gcry_cast5_s1to4[1] +#define s3 _gcry_cast5_s1to4[2] +#define s4 _gcry_cast5_s1to4[3] -static const u32 s1[256] = { +const u32 _gcry_cast5_s1to4[4][256] = { { 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d, @@ -90,8 +115,7 @@ static const u32 s1[256] = { 0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e, 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9, 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf -}; -static const u32 s2[256] = { +}, { 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb, @@ -124,8 +148,7 @@ static const u32 s2[256] = { 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa, 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9, 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1 -}; -static const u32 s3[256] = { +}, { 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e, @@ -158,8 +181,7 @@ static const u32 s3[256] = { 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d, 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a, 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783 -}; -static const u32 s4[256] = { +}, { 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15, @@ -192,7 +214,7 @@ static const u32 s4[256] = { 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04, 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282, 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2 -}; +} }; static const u32 s5[256] = { 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f, 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, @@ -331,24 +353,107 @@ static const u32 s8[256] = { }; -#if defined(__GNUC__) && defined(__i386__) -static inline u32 -rol(int n, u32 x) +#ifdef USE_AMD64_ASM + +/* Assembly implementations of CAST5. */ +extern void _gcry_cast5_amd64_encrypt_block(CAST5_context *c, byte *outbuf, + const byte *inbuf); + +extern void _gcry_cast5_amd64_decrypt_block(CAST5_context *c, byte *outbuf, + const byte *inbuf); + +/* These assembly implementations process four blocks in parallel. */ +extern void _gcry_cast5_amd64_ctr_enc(CAST5_context *ctx, byte *out, + const byte *in, byte *ctr); + +extern void _gcry_cast5_amd64_cbc_dec(CAST5_context *ctx, byte *out, + const byte *in, byte *iv); + +extern void _gcry_cast5_amd64_cfb_dec(CAST5_context *ctx, byte *out, + const byte *in, byte *iv); + +static void +do_encrypt_block (CAST5_context *context, byte *outbuf, const byte *inbuf) { - __asm__("roll %%cl,%0" - :"=r" (x) - :"0" (x),"c" (n)); - return x; + _gcry_cast5_amd64_encrypt_block (context, outbuf, inbuf); +} + +static void +do_decrypt_block (CAST5_context *context, byte *outbuf, const byte *inbuf) +{ + _gcry_cast5_amd64_decrypt_block (context, outbuf, inbuf); +} + +static unsigned int +encrypt_block (void *context , byte *outbuf, const byte *inbuf) +{ + CAST5_context *c = (CAST5_context *) context; + do_encrypt_block (c, outbuf, inbuf); + return /*burn_stack*/ (2*8); +} + +static unsigned int +decrypt_block (void *context, byte *outbuf, const byte *inbuf) +{ + CAST5_context *c = (CAST5_context *) context; + _gcry_cast5_amd64_decrypt_block (c, outbuf, inbuf); + return /*burn_stack*/ (2*8); } -#else -#define rol(n,x) ( ((x) << (n)) | ((x) >> (32-(n))) ) -#endif -#define F1(D,m,r) ( (I = ((m) + (D))), (I=rol((r),I)), \ +#elif defined(USE_ARM_ASM) + +/* ARM assembly implementations of CAST5. */ +extern void _gcry_cast5_arm_encrypt_block(CAST5_context *c, byte *outbuf, + const byte *inbuf); + +extern void _gcry_cast5_arm_decrypt_block(CAST5_context *c, byte *outbuf, + const byte *inbuf); + +/* These assembly implementations process two blocks in parallel. */ +extern void _gcry_cast5_arm_ctr_enc(CAST5_context *ctx, byte *out, + const byte *in, byte *ctr); + +extern void _gcry_cast5_arm_cbc_dec(CAST5_context *ctx, byte *out, + const byte *in, byte *iv); + +extern void _gcry_cast5_arm_cfb_dec(CAST5_context *ctx, byte *out, + const byte *in, byte *iv); + +static void +do_encrypt_block (CAST5_context *context, byte *outbuf, const byte *inbuf) +{ + _gcry_cast5_arm_encrypt_block (context, outbuf, inbuf); +} + +static void +do_decrypt_block (CAST5_context *context, byte *outbuf, const byte *inbuf) +{ + _gcry_cast5_arm_decrypt_block (context, outbuf, inbuf); +} + +static unsigned int +encrypt_block (void *context , byte *outbuf, const byte *inbuf) +{ + CAST5_context *c = (CAST5_context *) context; + do_encrypt_block (c, outbuf, inbuf); + return /*burn_stack*/ (10*4); +} + +static unsigned int +decrypt_block (void *context, byte *outbuf, const byte *inbuf) +{ + CAST5_context *c = (CAST5_context *) context; + do_decrypt_block (c, outbuf, inbuf); + return /*burn_stack*/ (10*4); +} + +#else /*USE_ARM_ASM*/ + +#define F1(D,m,r) ( (I = ((m) + (D))), (I=rol(I,(r))), \ (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff]) ) -#define F2(D,m,r) ( (I = ((m) ^ (D))), (I=rol((r),I)), \ +#define F2(D,m,r) ( (I = ((m) ^ (D))), (I=rol(I,(r))), \ (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff]) ) -#define F3(D,m,r) ( (I = ((m) - (D))), (I=rol((r),I)), \ +#define F3(D,m,r) ( (I = ((m) - (D))), (I=rol(I,(r))), \ (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff]) ) static void @@ -365,8 +470,8 @@ do_encrypt_block( CAST5_context *c, byte *outbuf, const byte *inbuf ) /* (L0,R0) <-- (m1...m64). (Split the plaintext into left and * right 32-bit halves L0 = m1...m32 and R0 = m33...m64.) */ - l = inbuf[0] << 24 | inbuf[1] << 16 | inbuf[2] << 8 | inbuf[3]; - r = inbuf[4] << 24 | inbuf[5] << 16 | inbuf[6] << 8 | inbuf[7]; + l = buf_get_be32(inbuf + 0); + r = buf_get_be32(inbuf + 4); /* (16 rounds) for i from 1 to 16, compute Li and Ri as follows: * Li = Ri-1; @@ -395,22 +500,16 @@ do_encrypt_block( CAST5_context *c, byte *outbuf, const byte *inbuf ) /* c1...c64 <-- (R16,L16). (Exchange final blocks L16, R16 and * concatenate to form the ciphertext.) */ - outbuf[0] = (r >> 24) & 0xff; - outbuf[1] = (r >> 16) & 0xff; - outbuf[2] = (r >> 8) & 0xff; - outbuf[3] = r & 0xff; - outbuf[4] = (l >> 24) & 0xff; - outbuf[5] = (l >> 16) & 0xff; - outbuf[6] = (l >> 8) & 0xff; - outbuf[7] = l & 0xff; + buf_put_be32(outbuf + 0, r); + buf_put_be32(outbuf + 4, l); } -static void +static unsigned int encrypt_block (void *context , byte *outbuf, const byte *inbuf) { CAST5_context *c = (CAST5_context *) context; do_encrypt_block (c, outbuf, inbuf); - _gcry_burn_stack (20+4*sizeof(void*)); + return /*burn_stack*/ (20+4*sizeof(void*)); } @@ -425,8 +524,8 @@ do_decrypt_block (CAST5_context *c, byte *outbuf, const byte *inbuf ) Km = c->Km; Kr = c->Kr; - l = inbuf[0] << 24 | inbuf[1] << 16 | inbuf[2] << 8 | inbuf[3]; - r = inbuf[4] << 24 | inbuf[5] << 16 | inbuf[6] << 8 | inbuf[7]; + l = buf_get_be32(inbuf + 0); + r = buf_get_be32(inbuf + 4); t = l; l = r; r = t ^ F1(r, Km[15], Kr[15]); t = l; l = r; r = t ^ F3(r, Km[14], Kr[14]); @@ -445,22 +544,251 @@ do_decrypt_block (CAST5_context *c, byte *outbuf, const byte *inbuf ) t = l; l = r; r = t ^ F2(r, Km[ 1], Kr[ 1]); t = l; l = r; r = t ^ F1(r, Km[ 0], Kr[ 0]); - outbuf[0] = (r >> 24) & 0xff; - outbuf[1] = (r >> 16) & 0xff; - outbuf[2] = (r >> 8) & 0xff; - outbuf[3] = r & 0xff; - outbuf[4] = (l >> 24) & 0xff; - outbuf[5] = (l >> 16) & 0xff; - outbuf[6] = (l >> 8) & 0xff; - outbuf[7] = l & 0xff; + buf_put_be32(outbuf + 0, r); + buf_put_be32(outbuf + 4, l); } -static void +static unsigned int decrypt_block (void *context, byte *outbuf, const byte *inbuf) { CAST5_context *c = (CAST5_context *) context; do_decrypt_block (c, outbuf, inbuf); - _gcry_burn_stack (20+4*sizeof(void*)); + return /*burn_stack*/ (20+4*sizeof(void*)); +} + +#endif /*!USE_ARM_ASM*/ + + +/* Bulk encryption of complete blocks in CTR mode. This function is only + intended for the bulk encryption feature of cipher.c. CTR is expected to be + of size CAST5_BLOCKSIZE. */ +void +_gcry_cast5_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks) +{ + CAST5_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char tmpbuf[CAST5_BLOCKSIZE]; + int burn_stack_depth = (20 + 4 * sizeof(void*)) + 2 * CAST5_BLOCKSIZE; + + int i; + +#ifdef USE_AMD64_ASM + { + if (nblocks >= 4) + burn_stack_depth += 8 * sizeof(void*); + + /* Process data in 4 block chunks. */ + while (nblocks >= 4) + { + _gcry_cast5_amd64_ctr_enc(ctx, outbuf, inbuf, ctr); + + nblocks -= 4; + outbuf += 4 * CAST5_BLOCKSIZE; + inbuf += 4 * CAST5_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + /* TODO: use caching instead? */ + } +#elif defined(USE_ARM_ASM) + { + /* Process data in 2 block chunks. */ + while (nblocks >= 2) + { + _gcry_cast5_arm_ctr_enc(ctx, outbuf, inbuf, ctr); + + nblocks -= 2; + outbuf += 2 * CAST5_BLOCKSIZE; + inbuf += 2 * CAST5_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + /* TODO: use caching instead? */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* Encrypt the counter. */ + do_encrypt_block(ctx, tmpbuf, ctr); + /* XOR the input with the encrypted counter and store in output. */ + buf_xor(outbuf, tmpbuf, inbuf, CAST5_BLOCKSIZE); + outbuf += CAST5_BLOCKSIZE; + inbuf += CAST5_BLOCKSIZE; + /* Increment the counter. */ + for (i = CAST5_BLOCKSIZE; i > 0; i--) + { + ctr[i-1]++; + if (ctr[i-1]) + break; + } + } + + wipememory(tmpbuf, sizeof(tmpbuf)); + _gcry_burn_stack(burn_stack_depth); +} + + +/* Bulk decryption of complete blocks in CBC mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +void +_gcry_cast5_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks) +{ + CAST5_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char savebuf[CAST5_BLOCKSIZE]; + int burn_stack_depth = (20 + 4 * sizeof(void*)) + 2 * CAST5_BLOCKSIZE; + +#ifdef USE_AMD64_ASM + { + if (nblocks >= 4) + burn_stack_depth += 8 * sizeof(void*); + + /* Process data in 4 block chunks. */ + while (nblocks >= 4) + { + _gcry_cast5_amd64_cbc_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 4; + outbuf += 4 * CAST5_BLOCKSIZE; + inbuf += 4 * CAST5_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#elif defined(USE_ARM_ASM) + { + /* Process data in 2 block chunks. */ + while (nblocks >= 2) + { + _gcry_cast5_arm_cbc_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 2; + outbuf += 2 * CAST5_BLOCKSIZE; + inbuf += 2 * CAST5_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* INBUF is needed later and it may be identical to OUTBUF, so store + the intermediate result to SAVEBUF. */ + do_decrypt_block (ctx, savebuf, inbuf); + + buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, CAST5_BLOCKSIZE); + inbuf += CAST5_BLOCKSIZE; + outbuf += CAST5_BLOCKSIZE; + } + + wipememory(savebuf, sizeof(savebuf)); + _gcry_burn_stack(burn_stack_depth); +} + +/* Bulk decryption of complete blocks in CFB mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +void +_gcry_cast5_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks) +{ + CAST5_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + int burn_stack_depth = (20 + 4 * sizeof(void*)) + 2 * CAST5_BLOCKSIZE; + +#ifdef USE_AMD64_ASM + { + if (nblocks >= 4) + burn_stack_depth += 8 * sizeof(void*); + + /* Process data in 4 block chunks. */ + while (nblocks >= 4) + { + _gcry_cast5_amd64_cfb_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 4; + outbuf += 4 * CAST5_BLOCKSIZE; + inbuf += 4 * CAST5_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#elif defined(USE_ARM_ASM) + { + /* Process data in 2 block chunks. */ + while (nblocks >= 2) + { + _gcry_cast5_arm_cfb_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 2; + outbuf += 2 * CAST5_BLOCKSIZE; + inbuf += 2 * CAST5_BLOCKSIZE; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + do_encrypt_block(ctx, iv, iv); + buf_xor_n_copy(outbuf, iv, inbuf, CAST5_BLOCKSIZE); + outbuf += CAST5_BLOCKSIZE; + inbuf += CAST5_BLOCKSIZE; + } + + _gcry_burn_stack(burn_stack_depth); +} + + +/* Run the self-tests for CAST5-CTR, tests IV increment of bulk CTR + encryption. Returns NULL on success. */ +static const char * +selftest_ctr (void) +{ + const int nblocks = 4+1; + const int blocksize = CAST5_BLOCKSIZE; + const int context_size = sizeof(CAST5_context); + + return _gcry_selftest_helper_ctr("CAST5", &cast_setkey, + &encrypt_block, &_gcry_cast5_ctr_enc, nblocks, blocksize, + context_size); +} + + +/* Run the self-tests for CAST5-CBC, tests bulk CBC decryption. + Returns NULL on success. */ +static const char * +selftest_cbc (void) +{ + const int nblocks = 4+2; + const int blocksize = CAST5_BLOCKSIZE; + const int context_size = sizeof(CAST5_context); + + return _gcry_selftest_helper_cbc("CAST5", &cast_setkey, + &encrypt_block, &_gcry_cast5_cbc_dec, nblocks, blocksize, + context_size); +} + + +/* Run the self-tests for CAST5-CFB, tests bulk CBC decryption. + Returns NULL on success. */ +static const char * +selftest_cfb (void) +{ + const int nblocks = 4+2; + const int blocksize = CAST5_BLOCKSIZE; + const int context_size = sizeof(CAST5_context); + + return _gcry_selftest_helper_cfb("CAST5", &cast_setkey, + &encrypt_block, &_gcry_cast5_cfb_dec, nblocks, blocksize, + context_size); } @@ -468,11 +796,15 @@ static const char* selftest(void) { CAST5_context c; - byte key[16] = { 0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, + static const byte key[16] = + { 0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A }; - byte plain[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }; - byte cipher[8]= { 0x23, 0x8B, 0x4F, 0xE5, 0x84, 0x7E, 0x44, 0xB2 }; + static const byte plain[8] = + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }; + static const byte cipher[8] = + { 0x23, 0x8B, 0x4F, 0xE5, 0x84, 0x7E, 0x44, 0xB2 }; byte buffer[8]; + const char *r; cast_setkey( &c, key, 16 ); encrypt_block( &c, buffer, plain ); @@ -507,6 +839,16 @@ selftest(void) } #endif + + if ( (r = selftest_cbc ()) ) + return r; + + if ( (r = selftest_cfb ()) ) + return r; + + if ( (r = selftest_ctr ()) ) + return r; + return NULL; } @@ -569,7 +911,7 @@ do_cast_setkey( CAST5_context *c, const byte *key, unsigned keylen ) u32 z[4]; u32 k[16]; - if( !initialized ) + if( !initialized ) { initialized = 1; selftest_failed = selftest(); @@ -582,10 +924,10 @@ do_cast_setkey( CAST5_context *c, const byte *key, unsigned keylen ) if( keylen != 16 ) return GPG_ERR_INV_KEYLEN; - x[0] = key[0] << 24 | key[1] << 16 | key[2] << 8 | key[3]; - x[1] = key[4] << 24 | key[5] << 16 | key[6] << 8 | key[7]; - x[2] = key[8] << 24 | key[9] << 16 | key[10] << 8 | key[11]; - x[3] = key[12] << 24 | key[13] << 16 | key[14] << 8 | key[15]; + x[0] = buf_get_be32(key + 0); + x[1] = buf_get_be32(key + 4); + x[2] = buf_get_be32(key + 8); + x[3] = buf_get_be32(key + 12); key_schedule( x, z, k ); for(i=0; i < 16; i++ ) @@ -594,9 +936,35 @@ do_cast_setkey( CAST5_context *c, const byte *key, unsigned keylen ) for(i=0; i < 16; i++ ) c->Kr[i] = k[i] & 0x1f; - memset(&x,0, sizeof x); - memset(&z,0, sizeof z); - memset(&k,0, sizeof k); +#ifdef USE_ARM_ASM + for (i = 0; i < 4; i++) + { + byte Kr_arm[4]; + + /* Convert rotate left to rotate right and add shift left + * by 2. */ + Kr_arm[0] = ((32 - c->Kr[4 * i + 0]) - 2) & 0x1f; + Kr_arm[1] = ((32 - c->Kr[4 * i + 1]) - 2) & 0x1f; + Kr_arm[2] = ((32 - c->Kr[4 * i + 2]) - 2) & 0x1f; + Kr_arm[3] = ((32 - c->Kr[4 * i + 3]) - 2) & 0x1f; + + /* Endian friendly store. */ + c->Kr_arm_enc[i] = Kr_arm[0] | + (Kr_arm[1] << 8) | + (Kr_arm[2] << 16) | + (Kr_arm[3] << 24); + c->Kr_arm_dec[i] = Kr_arm[3] | + (Kr_arm[2] << 8) | + (Kr_arm[1] << 16) | + (Kr_arm[0] << 24); + + wipememory(Kr_arm, sizeof(Kr_arm)); + } +#endif + + wipememory(x, sizeof x); + wipememory(z, sizeof z); + wipememory(k, sizeof k); #undef xi #undef zi @@ -608,13 +976,13 @@ cast_setkey (void *context, const byte *key, unsigned keylen ) { CAST5_context *c = (CAST5_context *) context; gcry_err_code_t rc = do_cast_setkey (c, key, keylen); - _gcry_burn_stack (96+7*sizeof(void*)); return rc; } gcry_cipher_spec_t _gcry_cipher_spec_cast5 = { + GCRY_CIPHER_CAST5, {0, 0}, "CAST5", NULL, NULL, CAST5_BLOCKSIZE, 128, sizeof (CAST5_context), cast_setkey, encrypt_block, decrypt_block }; diff --git a/plugins/MirOTR/Libgcrypt/cipher/cipher-aeswrap.c b/plugins/MirOTR/Libgcrypt/cipher/cipher-aeswrap.c new file mode 100644 index 0000000000..50ac10736b --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/cipher-aeswrap.c @@ -0,0 +1,210 @@ +/* cipher-aeswrap.c - Generic AESWRAP mode implementation + * Copyright (C) 2009, 2011 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "g10lib.h" +#include "cipher.h" +#include "ath.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + + +/* Perform the AES-Wrap algorithm as specified by RFC3394. We + implement this as a mode usable with any cipher algorithm of + blocksize 128. */ +gcry_err_code_t +_gcry_cipher_aeswrap_encrypt (gcry_cipher_hd_t c, + byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen ) +{ + int j, x; + size_t n, i; + unsigned char *r, *a, *b; + unsigned char t[8]; + unsigned int burn, nburn; + +#if MAX_BLOCKSIZE < 8 +#error Invalid block size +#endif + /* We require a cipher with a 128 bit block length. */ + if (c->spec->blocksize != 16) + return GPG_ERR_INV_LENGTH; + + /* The output buffer must be able to hold the input data plus one + additional block. */ + if (outbuflen < inbuflen + 8) + return GPG_ERR_BUFFER_TOO_SHORT; + /* Input data must be multiple of 64 bits. */ + if (inbuflen % 8) + return GPG_ERR_INV_ARG; + + n = inbuflen / 8; + + /* We need at least two 64 bit blocks. */ + if (n < 2) + return GPG_ERR_INV_ARG; + + burn = 0; + + r = outbuf; + a = outbuf; /* We store A directly in OUTBUF. */ + b = c->u_ctr.ctr; /* B is also used to concatenate stuff. */ + + /* If an IV has been set we use that IV as the Alternative Initial + Value; if it has not been set we use the standard value. */ + if (c->marks.iv) + memcpy (a, c->u_iv.iv, 8); + else + memset (a, 0xa6, 8); + + /* Copy the inbuf to the outbuf. */ + memmove (r+8, inbuf, inbuflen); + + memset (t, 0, sizeof t); /* t := 0. */ + + for (j = 0; j <= 5; j++) + { + for (i = 1; i <= n; i++) + { + /* B := AES_k( A | R[i] ) */ + memcpy (b, a, 8); + memcpy (b+8, r+i*8, 8); + nburn = c->spec->encrypt (&c->context.c, b, b); + burn = nburn > burn ? nburn : burn; + /* t := t + 1 */ + for (x = 7; x >= 0; x--) + { + t[x]++; + if (t[x]) + break; + } + /* A := MSB_64(B) ^ t */ + buf_xor(a, b, t, 8); + /* R[i] := LSB_64(B) */ + memcpy (r+i*8, b+8, 8); + } + } + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} + +/* Perform the AES-Unwrap algorithm as specified by RFC3394. We + implement this as a mode usable with any cipher algorithm of + blocksize 128. */ +gcry_err_code_t +_gcry_cipher_aeswrap_decrypt (gcry_cipher_hd_t c, + byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen) +{ + int j, x; + size_t n, i; + unsigned char *r, *a, *b; + unsigned char t[8]; + unsigned int burn, nburn; + +#if MAX_BLOCKSIZE < 8 +#error Invalid block size +#endif + /* We require a cipher with a 128 bit block length. */ + if (c->spec->blocksize != 16) + return GPG_ERR_INV_LENGTH; + + /* The output buffer must be able to hold the input data minus one + additional block. Fixme: The caller has more restrictive checks + - we may want to fix them for this mode. */ + if (outbuflen + 8 < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + /* Input data must be multiple of 64 bits. */ + if (inbuflen % 8) + return GPG_ERR_INV_ARG; + + n = inbuflen / 8; + + /* We need at least three 64 bit blocks. */ + if (n < 3) + return GPG_ERR_INV_ARG; + + burn = 0; + + r = outbuf; + a = c->lastiv; /* We use c->LASTIV as buffer for A. */ + b = c->u_ctr.ctr; /* B is also used to concatenate stuff. */ + + /* Copy the inbuf to the outbuf and save A. */ + memcpy (a, inbuf, 8); + memmove (r, inbuf+8, inbuflen-8); + n--; /* Reduce to actual number of data blocks. */ + + /* t := 6 * n */ + i = n * 6; /* The range is valid because: n = inbuflen / 8 - 1. */ + for (x=0; x < 8 && x < sizeof (i); x++) + t[7-x] = i >> (8*x); + for (; x < 8; x++) + t[7-x] = 0; + + for (j = 5; j >= 0; j--) + { + for (i = n; i >= 1; i--) + { + /* B := AES_k^1( (A ^ t)| R[i] ) */ + buf_xor(b, a, t, 8); + memcpy (b+8, r+(i-1)*8, 8); + nburn = c->spec->decrypt (&c->context.c, b, b); + burn = nburn > burn ? nburn : burn; + /* t := t - 1 */ + for (x = 7; x >= 0; x--) + { + t[x]--; + if (t[x] != 0xff) + break; + } + /* A := MSB_64(B) */ + memcpy (a, b, 8); + /* R[i] := LSB_64(B) */ + memcpy (r+(i-1)*8, b+8, 8); + } + } + + /* If an IV has been set we compare against this Alternative Initial + Value; if it has not been set we compare against the standard IV. */ + if (c->marks.iv) + j = memcmp (a, c->u_iv.iv, 8); + else + { + for (j=0, x=0; x < 8; x++) + if (a[x] != 0xa6) + { + j=1; + break; + } + } + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return j? GPG_ERR_CHECKSUM : 0; +} diff --git a/plugins/MirOTR/Libgcrypt/cipher/cipher-cbc.c b/plugins/MirOTR/Libgcrypt/cipher/cipher-cbc.c new file mode 100644 index 0000000000..4b929daab4 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/cipher-cbc.c @@ -0,0 +1,205 @@ +/* cipher-cbc.c - Generic CBC mode implementation + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 + * 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "g10lib.h" +#include "cipher.h" +#include "ath.h" +#include "./cipher-internal.h" +#include "bufhelp.h" + + + +gcry_err_code_t +_gcry_cipher_cbc_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + size_t n; + unsigned char *ivp; + int i; + size_t blocksize = c->spec->blocksize; + gcry_cipher_encrypt_t enc_fn = c->spec->encrypt; + size_t nblocks = inbuflen / blocksize; + unsigned int burn, nburn; + + if (outbuflen < ((c->flags & GCRY_CIPHER_CBC_MAC)? blocksize : inbuflen)) + return GPG_ERR_BUFFER_TOO_SHORT; + + if ((inbuflen % blocksize) + && !(inbuflen > blocksize + && (c->flags & GCRY_CIPHER_CBC_CTS))) + return GPG_ERR_INV_LENGTH; + + burn = 0; + + if ((c->flags & GCRY_CIPHER_CBC_CTS) && inbuflen > blocksize) + { + if ((inbuflen % blocksize) == 0) + nblocks--; + } + + if (c->bulk.cbc_enc) + { + c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks, + (c->flags & GCRY_CIPHER_CBC_MAC)); + inbuf += nblocks * blocksize; + if (!(c->flags & GCRY_CIPHER_CBC_MAC)) + outbuf += nblocks * blocksize; + } + else + { + ivp = c->u_iv.iv; + + for (n=0; n < nblocks; n++ ) + { + buf_xor (outbuf, inbuf, ivp, blocksize); + nburn = enc_fn ( &c->context.c, outbuf, outbuf ); + burn = nburn > burn ? nburn : burn; + ivp = outbuf; + inbuf += blocksize; + if (!(c->flags & GCRY_CIPHER_CBC_MAC)) + outbuf += blocksize; + } + + if (ivp != c->u_iv.iv) + buf_cpy (c->u_iv.iv, ivp, blocksize ); + } + + if ((c->flags & GCRY_CIPHER_CBC_CTS) && inbuflen > blocksize) + { + /* We have to be careful here, since outbuf might be equal to + inbuf. */ + size_t restbytes; + unsigned char b; + + if ((inbuflen % blocksize) == 0) + restbytes = blocksize; + else + restbytes = inbuflen % blocksize; + + outbuf -= blocksize; + for (ivp = c->u_iv.iv, i = 0; i < restbytes; i++) + { + b = inbuf[i]; + outbuf[blocksize + i] = outbuf[i]; + outbuf[i] = b ^ *ivp++; + } + for (; i < blocksize; i++) + outbuf[i] = 0 ^ *ivp++; + + nburn = enc_fn (&c->context.c, outbuf, outbuf); + burn = nburn > burn ? nburn : burn; + buf_cpy (c->u_iv.iv, outbuf, blocksize); + } + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_cbc_decrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + size_t n; + int i; + size_t blocksize = c->spec->blocksize; + gcry_cipher_decrypt_t dec_fn = c->spec->decrypt; + size_t nblocks = inbuflen / blocksize; + unsigned int burn, nburn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + if ((inbuflen % blocksize) + && !(inbuflen > blocksize + && (c->flags & GCRY_CIPHER_CBC_CTS))) + return GPG_ERR_INV_LENGTH; + + burn = 0; + + if ((c->flags & GCRY_CIPHER_CBC_CTS) && inbuflen > blocksize) + { + nblocks--; + if ((inbuflen % blocksize) == 0) + nblocks--; + buf_cpy (c->lastiv, c->u_iv.iv, blocksize); + } + + if (c->bulk.cbc_dec) + { + c->bulk.cbc_dec (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); + inbuf += nblocks * blocksize; + outbuf += nblocks * blocksize; + } + else + { + for (n=0; n < nblocks; n++ ) + { + /* Because outbuf and inbuf might be the same, we must not overwrite + the original ciphertext block. We use LASTIV as intermediate + storage here because it is not used otherwise. */ + nburn = dec_fn ( &c->context.c, c->lastiv, inbuf ); + burn = nburn > burn ? nburn : burn; + buf_xor_n_copy_2(outbuf, c->lastiv, c->u_iv.iv, inbuf, blocksize); + inbuf += blocksize; + outbuf += blocksize; + } + } + + if ((c->flags & GCRY_CIPHER_CBC_CTS) && inbuflen > blocksize) + { + size_t restbytes; + + if ((inbuflen % blocksize) == 0) + restbytes = blocksize; + else + restbytes = inbuflen % blocksize; + + buf_cpy (c->lastiv, c->u_iv.iv, blocksize ); /* Save Cn-2. */ + buf_cpy (c->u_iv.iv, inbuf + blocksize, restbytes ); /* Save Cn. */ + + nburn = dec_fn ( &c->context.c, outbuf, inbuf ); + burn = nburn > burn ? nburn : burn; + buf_xor(outbuf, outbuf, c->u_iv.iv, restbytes); + + buf_cpy (outbuf + blocksize, outbuf, restbytes); + for(i=restbytes; i < blocksize; i++) + c->u_iv.iv[i] = outbuf[i]; + nburn = dec_fn (&c->context.c, outbuf, c->u_iv.iv); + burn = nburn > burn ? nburn : burn; + buf_xor(outbuf, outbuf, c->lastiv, blocksize); + /* c->lastiv is now really lastlastiv, does this matter? */ + } + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} diff --git a/plugins/MirOTR/Libgcrypt/cipher/cipher-ccm.c b/plugins/MirOTR/Libgcrypt/cipher/cipher-ccm.c new file mode 100644 index 0000000000..8ef29b272e --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/cipher-ccm.c @@ -0,0 +1,442 @@ +/* cipher-ccm.c - CTR mode with CBC-MAC mode implementation + * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "g10lib.h" +#include "cipher.h" +#include "ath.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + +/* We need a 64 bit type for this code. */ +#ifdef HAVE_U64_TYPEDEF + + +#define set_burn(burn, nburn) do { \ + unsigned int __nburn = (nburn); \ + (burn) = (burn) > __nburn ? (burn) : __nburn; } while (0) + + +static unsigned int +do_cbc_mac (gcry_cipher_hd_t c, const unsigned char *inbuf, size_t inlen, + int do_padding) +{ + const unsigned int blocksize = 16; + gcry_cipher_encrypt_t enc_fn = c->spec->encrypt; + unsigned char tmp[16]; + unsigned int burn = 0; + unsigned int unused = c->u_mode.ccm.mac_unused; + size_t nblocks; + + if (inlen == 0 && (unused == 0 || !do_padding)) + return 0; + + do + { + if (inlen + unused < blocksize || unused > 0) + { + for (; inlen && unused < blocksize; inlen--) + c->u_mode.ccm.macbuf[unused++] = *inbuf++; + } + if (!inlen) + { + if (!do_padding) + break; + + while (unused < blocksize) + c->u_mode.ccm.macbuf[unused++] = 0; + } + + if (unused > 0) + { + /* Process one block from macbuf. */ + buf_xor(c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.macbuf, blocksize); + set_burn (burn, enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv )); + + unused = 0; + } + + if (c->bulk.cbc_enc) + { + nblocks = inlen / blocksize; + c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, tmp, inbuf, nblocks, 1); + inbuf += nblocks * blocksize; + inlen -= nblocks * blocksize; + + wipememory (tmp, sizeof(tmp)); + } + else + { + while (inlen >= blocksize) + { + buf_xor(c->u_iv.iv, c->u_iv.iv, inbuf, blocksize); + + set_burn (burn, enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv )); + + inlen -= blocksize; + inbuf += blocksize; + } + } + } + while (inlen > 0); + + c->u_mode.ccm.mac_unused = unused; + + if (burn) + burn += 4 * sizeof(void *); + + return burn; +} + + +gcry_err_code_t +_gcry_cipher_ccm_set_nonce (gcry_cipher_hd_t c, const unsigned char *nonce, + size_t noncelen) +{ + size_t L = 15 - noncelen; + size_t L_; + + L_ = L - 1; + + if (!nonce) + return GPG_ERR_INV_ARG; + /* Length field must be 2, 3, ..., or 8. */ + if (L < 2 || L > 8) + return GPG_ERR_INV_LENGTH; + + /* Reset state */ + memset (&c->u_mode, 0, sizeof(c->u_mode)); + memset (&c->marks, 0, sizeof(c->marks)); + memset (&c->u_iv, 0, sizeof(c->u_iv)); + memset (&c->u_ctr, 0, sizeof(c->u_ctr)); + memset (c->lastiv, 0, sizeof(c->lastiv)); + c->unused = 0; + + /* Setup CTR */ + c->u_ctr.ctr[0] = L_; + memcpy (&c->u_ctr.ctr[1], nonce, noncelen); + memset (&c->u_ctr.ctr[1 + noncelen], 0, L); + + /* Setup IV */ + c->u_iv.iv[0] = L_; + memcpy (&c->u_iv.iv[1], nonce, noncelen); + /* Add (8 * M_ + 64 * flags) to iv[0] and set iv[noncelen + 1 ... 15] later + in set_aad. */ + memset (&c->u_iv.iv[1 + noncelen], 0, L); + + c->u_mode.ccm.nonce = 1; + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_ccm_set_lengths (gcry_cipher_hd_t c, u64 encryptlen, u64 aadlen, + u64 taglen) +{ + unsigned int burn = 0; + unsigned char b0[16]; + size_t noncelen = 15 - (c->u_iv.iv[0] + 1); + u64 M = taglen; + u64 M_; + int i; + + M_ = (M - 2) / 2; + + /* Authentication field must be 4, 6, 8, 10, 12, 14 or 16. */ + if ((M_ * 2 + 2) != M || M < 4 || M > 16) + return GPG_ERR_INV_LENGTH; + if (!c->u_mode.ccm.nonce || c->marks.tag) + return GPG_ERR_INV_STATE; + if (c->u_mode.ccm.lengths) + return GPG_ERR_INV_STATE; + + c->u_mode.ccm.authlen = taglen; + c->u_mode.ccm.encryptlen = encryptlen; + c->u_mode.ccm.aadlen = aadlen; + + /* Complete IV setup. */ + c->u_iv.iv[0] += (aadlen > 0) * 64 + M_ * 8; + for (i = 16 - 1; i >= 1 + noncelen; i--) + { + c->u_iv.iv[i] = encryptlen & 0xff; + encryptlen >>= 8; + } + + memcpy (b0, c->u_iv.iv, 16); + memset (c->u_iv.iv, 0, 16); + + set_burn (burn, do_cbc_mac (c, b0, 16, 0)); + + if (aadlen == 0) + { + /* Do nothing. */ + } + else if (aadlen > 0 && aadlen <= (unsigned int)0xfeff) + { + b0[0] = (aadlen >> 8) & 0xff; + b0[1] = aadlen & 0xff; + set_burn (burn, do_cbc_mac (c, b0, 2, 0)); + } + else if (aadlen > 0xfeff && aadlen <= (unsigned int)0xffffffff) + { + b0[0] = 0xff; + b0[1] = 0xfe; + buf_put_be32(&b0[2], aadlen); + set_burn (burn, do_cbc_mac (c, b0, 6, 0)); + } + else if (aadlen > (unsigned int)0xffffffff) + { + b0[0] = 0xff; + b0[1] = 0xff; + buf_put_be64(&b0[2], aadlen); + set_burn (burn, do_cbc_mac (c, b0, 10, 0)); + } + + /* Generate S_0 and increase counter. */ + set_burn (burn, c->spec->encrypt ( &c->context.c, c->u_mode.ccm.s0, + c->u_ctr.ctr )); + c->u_ctr.ctr[15]++; + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + c->u_mode.ccm.lengths = 1; + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_ccm_authenticate (gcry_cipher_hd_t c, const unsigned char *abuf, + size_t abuflen) +{ + unsigned int burn; + + if (abuflen > 0 && !abuf) + return GPG_ERR_INV_ARG; + if (!c->u_mode.ccm.nonce || !c->u_mode.ccm.lengths || c->marks.tag) + return GPG_ERR_INV_STATE; + if (abuflen > c->u_mode.ccm.aadlen) + return GPG_ERR_INV_LENGTH; + + c->u_mode.ccm.aadlen -= abuflen; + burn = do_cbc_mac (c, abuf, abuflen, c->u_mode.ccm.aadlen == 0); + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_ccm_tag (gcry_cipher_hd_t c, unsigned char *outbuf, + size_t outbuflen, int check) +{ + unsigned int burn; + + if (!outbuf || outbuflen == 0) + return GPG_ERR_INV_ARG; + /* Tag length must be same as initial authlen. */ + if (c->u_mode.ccm.authlen != outbuflen) + return GPG_ERR_INV_LENGTH; + if (!c->u_mode.ccm.nonce || !c->u_mode.ccm.lengths || c->u_mode.ccm.aadlen > 0) + return GPG_ERR_INV_STATE; + /* Initial encrypt length must match with length of actual data processed. */ + if (c->u_mode.ccm.encryptlen > 0) + return GPG_ERR_UNFINISHED; + + if (!c->marks.tag) + { + burn = do_cbc_mac (c, NULL, 0, 1); /* Perform final padding. */ + + /* Add S_0 */ + buf_xor (c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.s0, 16); + + wipememory (c->u_ctr.ctr, 16); + wipememory (c->u_mode.ccm.s0, 16); + wipememory (c->u_mode.ccm.macbuf, 16); + + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + c->marks.tag = 1; + } + + if (!check) + { + memcpy (outbuf, c->u_iv.iv, outbuflen); + return GPG_ERR_NO_ERROR; + } + else + { + return buf_eq_const(outbuf, c->u_iv.iv, outbuflen) ? + GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM; + } +} + + +gcry_err_code_t +_gcry_cipher_ccm_get_tag (gcry_cipher_hd_t c, unsigned char *outtag, + size_t taglen) +{ + return _gcry_cipher_ccm_tag (c, outtag, taglen, 0); +} + + +gcry_err_code_t +_gcry_cipher_ccm_check_tag (gcry_cipher_hd_t c, const unsigned char *intag, + size_t taglen) +{ + return _gcry_cipher_ccm_tag (c, (unsigned char *)intag, taglen, 1); +} + + +gcry_err_code_t +_gcry_cipher_ccm_encrypt (gcry_cipher_hd_t c, unsigned char *outbuf, + size_t outbuflen, const unsigned char *inbuf, + size_t inbuflen) +{ + unsigned int burn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (!c->u_mode.ccm.nonce || c->marks.tag || !c->u_mode.ccm.lengths || + c->u_mode.ccm.aadlen > 0) + return GPG_ERR_INV_STATE; + if (inbuflen > c->u_mode.ccm.encryptlen) + return GPG_ERR_INV_LENGTH; + + c->u_mode.ccm.encryptlen -= inbuflen; + burn = do_cbc_mac (c, inbuf, inbuflen, 0); + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + return _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); +} + + +gcry_err_code_t +_gcry_cipher_ccm_decrypt (gcry_cipher_hd_t c, unsigned char *outbuf, + size_t outbuflen, const unsigned char *inbuf, + size_t inbuflen) +{ + gcry_err_code_t err; + unsigned int burn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (!c->u_mode.ccm.nonce || c->marks.tag || !c->u_mode.ccm.lengths || + c->u_mode.ccm.aadlen > 0) + return GPG_ERR_INV_STATE; + if (inbuflen > c->u_mode.ccm.encryptlen) + return GPG_ERR_INV_LENGTH; + + err = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + if (err) + return err; + + c->u_mode.ccm.encryptlen -= inbuflen; + burn = do_cbc_mac (c, outbuf, inbuflen, 0); + if (burn) + _gcry_burn_stack (burn + sizeof(void *) * 5); + + return err; +} + +#else + +/* + * Provide dummy functions so that we avoid adding too much #ifdefs in + * cipher.c. + */ + +gcry_err_code_t +_gcry_cipher_ccm_encrypt(gcry_cipher_hd_t c, unsigned char *outbuf, + size_t outbuflen, const unsigned char *inbuf, + size_t inbuflen) +{ + (void)c; + (void)outbuf; + (void)outbuflen; + (void)inbuf; + (void)inbuflen; + return GPG_ERR_NOT_SUPPORTED; +} + +gcry_err_code_t +_gcry_cipher_ccm_decrypt(gcry_cipher_hd_t c, unsigned char *outbuf, + size_t outbuflen, const unsigned char *inbuf, + size_t inbuflen) +{ + (void)c; + (void)outbuf; + (void)outbuflen; + (void)inbuf; + (void)inbuflen; + return GPG_ERR_NOT_SUPPORTED; +} + +gcry_err_code_t +_gcry_cipher_ccm_set_nonce(gcry_cipher_hd_t c, const unsigned char *nonce, + size_t noncelen) +{ + (void)c; + (void)nonce; + (void)noncelen; + return GPG_ERR_NOT_SUPPORTED; +} + +gcry_err_code_t +_gcry_cipher_ccm_authenticate(gcry_cipher_hd_t c, const unsigned char *abuf, + size_t abuflen) +{ + (void)c; + (void)abuf; + (void)abuflen; + return GPG_ERR_NOT_SUPPORTED; +} + +gcry_err_code_t +_gcry_cipher_ccm_get_tag(gcry_cipher_hd_t c, unsigned char *outtag, + size_t taglen) +{ + (void)c; + (void)outtag; + (void)taglen; + return GPG_ERR_NOT_SUPPORTED; +} + +gcry_err_code_t +_gcry_cipher_ccm_check_tag(gcry_cipher_hd_t c, const unsigned char *intag, + size_t taglen) +{ + (void)c; + (void)intag; + (void)taglen; + return GPG_ERR_NOT_SUPPORTED; +} + +#endif /*HAVE_U64_TYPEDEF*/ diff --git a/plugins/MirOTR/Libgcrypt/cipher/cipher-cfb.c b/plugins/MirOTR/Libgcrypt/cipher/cipher-cfb.c new file mode 100644 index 0000000000..8539f548ca --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/cipher-cfb.c @@ -0,0 +1,226 @@ +/* cipher-cfb.c - Generic CFB mode implementation + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 + * 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "g10lib.h" +#include "cipher.h" +#include "ath.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + + +gcry_err_code_t +_gcry_cipher_cfb_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + unsigned char *ivp; + gcry_cipher_encrypt_t enc_fn = c->spec->encrypt; + size_t blocksize = c->spec->blocksize; + size_t blocksize_x_2 = blocksize + blocksize; + unsigned int burn, nburn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + if ( inbuflen <= c->unused ) + { + /* Short enough to be encoded by the remaining XOR mask. */ + /* XOR the input with the IV and store input into IV. */ + ivp = c->u_iv.iv + blocksize - c->unused; + buf_xor_2dst(outbuf, ivp, inbuf, inbuflen); + c->unused -= inbuflen; + return 0; + } + + burn = 0; + + if ( c->unused ) + { + /* XOR the input with the IV and store input into IV */ + inbuflen -= c->unused; + ivp = c->u_iv.iv + blocksize - c->unused; + buf_xor_2dst(outbuf, ivp, inbuf, c->unused); + outbuf += c->unused; + inbuf += c->unused; + c->unused = 0; + } + + /* Now we can process complete blocks. We use a loop as long as we + have at least 2 blocks and use conditions for the rest. This + also allows to use a bulk encryption function if available. */ + if (inbuflen >= blocksize_x_2 && c->bulk.cfb_enc) + { + size_t nblocks = inbuflen / blocksize; + c->bulk.cfb_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); + outbuf += nblocks * blocksize; + inbuf += nblocks * blocksize; + inbuflen -= nblocks * blocksize; + } + else + { + while ( inbuflen >= blocksize_x_2 ) + { + /* Encrypt the IV. */ + nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + burn = nburn > burn ? nburn : burn; + /* XOR the input with the IV and store input into IV. */ + buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize); + outbuf += blocksize; + inbuf += blocksize; + inbuflen -= blocksize; + } + } + + if ( inbuflen >= blocksize ) + { + /* Save the current IV and then encrypt the IV. */ + buf_cpy( c->lastiv, c->u_iv.iv, blocksize ); + nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + burn = nburn > burn ? nburn : burn; + /* XOR the input with the IV and store input into IV */ + buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize); + outbuf += blocksize; + inbuf += blocksize; + inbuflen -= blocksize; + } + if ( inbuflen ) + { + /* Save the current IV and then encrypt the IV. */ + buf_cpy( c->lastiv, c->u_iv.iv, blocksize ); + nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + burn = nburn > burn ? nburn : burn; + c->unused = blocksize; + /* Apply the XOR. */ + c->unused -= inbuflen; + buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, inbuflen); + outbuf += inbuflen; + inbuf += inbuflen; + inbuflen = 0; + } + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_cfb_decrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + unsigned char *ivp; + gcry_cipher_encrypt_t enc_fn = c->spec->encrypt; + size_t blocksize = c->spec->blocksize; + size_t blocksize_x_2 = blocksize + blocksize; + unsigned int burn, nburn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + if (inbuflen <= c->unused) + { + /* Short enough to be encoded by the remaining XOR mask. */ + /* XOR the input with the IV and store input into IV. */ + ivp = c->u_iv.iv + blocksize - c->unused; + buf_xor_n_copy(outbuf, ivp, inbuf, inbuflen); + c->unused -= inbuflen; + return 0; + } + + burn = 0; + + if (c->unused) + { + /* XOR the input with the IV and store input into IV. */ + inbuflen -= c->unused; + ivp = c->u_iv.iv + blocksize - c->unused; + buf_xor_n_copy(outbuf, ivp, inbuf, c->unused); + outbuf += c->unused; + inbuf += c->unused; + c->unused = 0; + } + + /* Now we can process complete blocks. We use a loop as long as we + have at least 2 blocks and use conditions for the rest. This + also allows to use a bulk encryption function if available. */ + if (inbuflen >= blocksize_x_2 && c->bulk.cfb_dec) + { + size_t nblocks = inbuflen / blocksize; + c->bulk.cfb_dec (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); + outbuf += nblocks * blocksize; + inbuf += nblocks * blocksize; + inbuflen -= nblocks * blocksize; + } + else + { + while (inbuflen >= blocksize_x_2 ) + { + /* Encrypt the IV. */ + nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + burn = nburn > burn ? nburn : burn; + /* XOR the input with the IV and store input into IV. */ + buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize); + outbuf += blocksize; + inbuf += blocksize; + inbuflen -= blocksize; + } + } + + if (inbuflen >= blocksize ) + { + /* Save the current IV and then encrypt the IV. */ + buf_cpy ( c->lastiv, c->u_iv.iv, blocksize); + nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + burn = nburn > burn ? nburn : burn; + /* XOR the input with the IV and store input into IV */ + buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize); + outbuf += blocksize; + inbuf += blocksize; + inbuflen -= blocksize; + } + + if (inbuflen) + { + /* Save the current IV and then encrypt the IV. */ + buf_cpy ( c->lastiv, c->u_iv.iv, blocksize ); + nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + burn = nburn > burn ? nburn : burn; + c->unused = blocksize; + /* Apply the XOR. */ + c->unused -= inbuflen; + buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, inbuflen); + outbuf += inbuflen; + inbuf += inbuflen; + inbuflen = 0; + } + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} diff --git a/plugins/MirOTR/Libgcrypt/cipher/cipher-cmac.c b/plugins/MirOTR/Libgcrypt/cipher/cipher-cmac.c new file mode 100644 index 0000000000..25d5db2604 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/cipher-cmac.c @@ -0,0 +1,238 @@ +/* cmac.c - CMAC, Cipher-based MAC. + * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "g10lib.h" +#include "cipher.h" +#include "cipher-internal.h" +#include "bufhelp.h" + + +#define set_burn(burn, nburn) do { \ + unsigned int __nburn = (nburn); \ + (burn) = (burn) > __nburn ? (burn) : __nburn; } while (0) + + +static void +cmac_write (gcry_cipher_hd_t c, const byte * inbuf, size_t inlen) +{ + gcry_cipher_encrypt_t enc_fn = c->spec->encrypt; + const unsigned int blocksize = c->spec->blocksize; + byte outbuf[MAX_BLOCKSIZE]; + unsigned int burn = 0; + unsigned int nblocks; + + if (!inlen || !inbuf) + return; + + /* Last block is needed for cmac_final. */ + if (c->unused + inlen <= blocksize) + { + for (; inlen && c->unused < blocksize; inlen--) + c->lastiv[c->unused++] = *inbuf++; + return; + } + + if (c->unused) + { + for (; inlen && c->unused < blocksize; inlen--) + c->lastiv[c->unused++] = *inbuf++; + + buf_xor (c->u_iv.iv, c->u_iv.iv, c->lastiv, blocksize); + set_burn (burn, enc_fn (&c->context.c, c->u_iv.iv, c->u_iv.iv)); + + c->unused = 0; + } + + if (c->bulk.cbc_enc && inlen > blocksize) + { + nblocks = inlen / blocksize; + nblocks -= (nblocks * blocksize == inlen); + + c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks, 1); + inbuf += nblocks * blocksize; + inlen -= nblocks * blocksize; + + wipememory (outbuf, sizeof (outbuf)); + } + else + while (inlen > blocksize) + { + buf_xor (c->u_iv.iv, c->u_iv.iv, inbuf, blocksize); + set_burn (burn, enc_fn (&c->context.c, c->u_iv.iv, c->u_iv.iv)); + inlen -= blocksize; + inbuf += blocksize; + } + + /* Make sure that last block is passed to cmac_final. */ + if (inlen == 0) + BUG (); + + for (; inlen && c->unused < blocksize; inlen--) + c->lastiv[c->unused++] = *inbuf++; + + if (burn) + _gcry_burn_stack (burn + 4 * sizeof (void *)); +} + + +static void +cmac_generate_subkeys (gcry_cipher_hd_t c) +{ + const unsigned int blocksize = c->spec->blocksize; + byte rb, carry, t, bi; + unsigned int burn; + int i, j; + union + { + size_t _aligned; + byte buf[MAX_BLOCKSIZE]; + } u; + + if (MAX_BLOCKSIZE < blocksize) + BUG (); + + /* encrypt zero block */ + memset (u.buf, 0, blocksize); + burn = c->spec->encrypt (&c->context.c, u.buf, u.buf); + + /* Currently supported blocksizes are 16 and 8. */ + rb = blocksize == 16 ? 0x87 : 0x1B /*blocksize == 8 */ ; + + for (j = 0; j < 2; j++) + { + /* Generate subkeys K1 and K2 */ + carry = 0; + for (i = blocksize - 1; i >= 0; i--) + { + bi = u.buf[i]; + t = carry | (bi << 1); + carry = bi >> 7; + u.buf[i] = t & 0xff; + c->u_mode.cmac.subkeys[j][i] = u.buf[i]; + } + u.buf[blocksize - 1] ^= carry ? rb : 0; + c->u_mode.cmac.subkeys[j][blocksize - 1] = u.buf[blocksize - 1]; + } + + wipememory (&u, sizeof (u)); + if (burn) + _gcry_burn_stack (burn + 4 * sizeof (void *)); +} + + +static void +cmac_final (gcry_cipher_hd_t c) +{ + const unsigned int blocksize = c->spec->blocksize; + unsigned int count = c->unused; + unsigned int burn; + byte *subkey; + + if (count == blocksize) + subkey = c->u_mode.cmac.subkeys[0]; /* K1 */ + else + { + subkey = c->u_mode.cmac.subkeys[1]; /* K2 */ + c->lastiv[count++] = 0x80; + while (count < blocksize) + c->lastiv[count++] = 0; + } + + buf_xor (c->lastiv, c->lastiv, subkey, blocksize); + + buf_xor (c->u_iv.iv, c->u_iv.iv, c->lastiv, blocksize); + burn = c->spec->encrypt (&c->context.c, c->u_iv.iv, c->u_iv.iv); + if (burn) + _gcry_burn_stack (burn + 4 * sizeof (void *)); + + c->unused = 0; +} + + +static gcry_err_code_t +cmac_tag (gcry_cipher_hd_t c, unsigned char *tag, size_t taglen, int check) +{ + if (!tag || taglen == 0 || taglen > c->spec->blocksize) + return GPG_ERR_INV_ARG; + + if (!c->u_mode.cmac.tag) + { + cmac_final (c); + c->u_mode.cmac.tag = 1; + } + + if (!check) + { + memcpy (tag, c->u_iv.iv, taglen); + return GPG_ERR_NO_ERROR; + } + else + { + return buf_eq_const (tag, c->u_iv.iv, taglen) ? + GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM; + } +} + + +gcry_err_code_t +_gcry_cipher_cmac_authenticate (gcry_cipher_hd_t c, + const unsigned char *abuf, size_t abuflen) +{ + if (abuflen > 0 && !abuf) + return GPG_ERR_INV_ARG; + if (c->u_mode.cmac.tag) + return GPG_ERR_INV_STATE; + /* To support new blocksize, update cmac_generate_subkeys() then add new + blocksize here. */ + if (c->spec->blocksize != 16 && c->spec->blocksize != 8) + return GPG_ERR_INV_CIPHER_MODE; + + cmac_write (c, abuf, abuflen); + + return GPG_ERR_NO_ERROR; +} + + +gcry_err_code_t +_gcry_cipher_cmac_get_tag (gcry_cipher_hd_t c, + unsigned char *outtag, size_t taglen) +{ + return cmac_tag (c, outtag, taglen, 0); +} + + +gcry_err_code_t +_gcry_cipher_cmac_check_tag (gcry_cipher_hd_t c, + const unsigned char *intag, size_t taglen) +{ + return cmac_tag (c, (unsigned char *) intag, taglen, 1); +} + +gcry_err_code_t +_gcry_cipher_cmac_set_subkeys (gcry_cipher_hd_t c) +{ + cmac_generate_subkeys (c); + + return GPG_ERR_NO_ERROR; +} diff --git a/plugins/MirOTR/Libgcrypt/cipher/cipher-ctr.c b/plugins/MirOTR/Libgcrypt/cipher/cipher-ctr.c new file mode 100644 index 0000000000..1e7133c9cf --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/cipher-ctr.c @@ -0,0 +1,111 @@ +/* cipher-ctr.c - Generic CTR mode implementation + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 + * 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "g10lib.h" +#include "cipher.h" +#include "ath.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + + +gcry_err_code_t +_gcry_cipher_ctr_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + size_t n; + int i; + gcry_cipher_encrypt_t enc_fn = c->spec->encrypt; + unsigned int blocksize = c->spec->blocksize; + size_t nblocks; + unsigned int burn, nburn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + burn = 0; + + /* First process a left over encrypted counter. */ + if (c->unused) + { + gcry_assert (c->unused < blocksize); + i = blocksize - c->unused; + n = c->unused > inbuflen ? inbuflen : c->unused; + buf_xor(outbuf, inbuf, &c->lastiv[i], n); + c->unused -= n; + inbuf += n; + outbuf += n; + inbuflen -= n; + } + + /* Use a bulk method if available. */ + nblocks = inbuflen / blocksize; + if (nblocks && c->bulk.ctr_enc) + { + c->bulk.ctr_enc (&c->context.c, c->u_ctr.ctr, outbuf, inbuf, nblocks); + inbuf += nblocks * blocksize; + outbuf += nblocks * blocksize; + inbuflen -= nblocks * blocksize; + } + + /* If we don't have a bulk method use the standard method. We also + use this method for the a remaining partial block. */ + if (inbuflen) + { + unsigned char tmp[MAX_BLOCKSIZE]; + + do { + nburn = enc_fn (&c->context.c, tmp, c->u_ctr.ctr); + burn = nburn > burn ? nburn : burn; + + for (i = blocksize; i > 0; i--) + { + c->u_ctr.ctr[i-1]++; + if (c->u_ctr.ctr[i-1] != 0) + break; + } + + n = blocksize < inbuflen ? blocksize : inbuflen; + buf_xor(outbuf, inbuf, tmp, n); + + inbuflen -= n; + outbuf += n; + inbuf += n; + } while (inbuflen); + + /* Save the unused bytes of the counter. */ + c->unused = blocksize - n; + if (c->unused) + buf_cpy (c->lastiv+n, tmp+n, c->unused); + + wipememory (tmp, sizeof tmp); + } + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} diff --git a/plugins/MirOTR/Libgcrypt/cipher/cipher-gcm.c b/plugins/MirOTR/Libgcrypt/cipher/cipher-gcm.c new file mode 100644 index 0000000000..457e337ac3 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/cipher-gcm.c @@ -0,0 +1,1180 @@ +/* cipher-gcm.c - Generic Galois Counter Mode implementation + * Copyright (C) 2013 Dmitry Eremin-Solenikov + * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "g10lib.h" +#include "cipher.h" +#include "ath.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + +#ifdef GCM_USE_TABLES +static const u16 gcmR[256] = { + 0x0000, 0x01c2, 0x0384, 0x0246, 0x0708, 0x06ca, 0x048c, 0x054e, + 0x0e10, 0x0fd2, 0x0d94, 0x0c56, 0x0918, 0x08da, 0x0a9c, 0x0b5e, + 0x1c20, 0x1de2, 0x1fa4, 0x1e66, 0x1b28, 0x1aea, 0x18ac, 0x196e, + 0x1230, 0x13f2, 0x11b4, 0x1076, 0x1538, 0x14fa, 0x16bc, 0x177e, + 0x3840, 0x3982, 0x3bc4, 0x3a06, 0x3f48, 0x3e8a, 0x3ccc, 0x3d0e, + 0x3650, 0x3792, 0x35d4, 0x3416, 0x3158, 0x309a, 0x32dc, 0x331e, + 0x2460, 0x25a2, 0x27e4, 0x2626, 0x2368, 0x22aa, 0x20ec, 0x212e, + 0x2a70, 0x2bb2, 0x29f4, 0x2836, 0x2d78, 0x2cba, 0x2efc, 0x2f3e, + 0x7080, 0x7142, 0x7304, 0x72c6, 0x7788, 0x764a, 0x740c, 0x75ce, + 0x7e90, 0x7f52, 0x7d14, 0x7cd6, 0x7998, 0x785a, 0x7a1c, 0x7bde, + 0x6ca0, 0x6d62, 0x6f24, 0x6ee6, 0x6ba8, 0x6a6a, 0x682c, 0x69ee, + 0x62b0, 0x6372, 0x6134, 0x60f6, 0x65b8, 0x647a, 0x663c, 0x67fe, + 0x48c0, 0x4902, 0x4b44, 0x4a86, 0x4fc8, 0x4e0a, 0x4c4c, 0x4d8e, + 0x46d0, 0x4712, 0x4554, 0x4496, 0x41d8, 0x401a, 0x425c, 0x439e, + 0x54e0, 0x5522, 0x5764, 0x56a6, 0x53e8, 0x522a, 0x506c, 0x51ae, + 0x5af0, 0x5b32, 0x5974, 0x58b6, 0x5df8, 0x5c3a, 0x5e7c, 0x5fbe, + 0xe100, 0xe0c2, 0xe284, 0xe346, 0xe608, 0xe7ca, 0xe58c, 0xe44e, + 0xef10, 0xeed2, 0xec94, 0xed56, 0xe818, 0xe9da, 0xeb9c, 0xea5e, + 0xfd20, 0xfce2, 0xfea4, 0xff66, 0xfa28, 0xfbea, 0xf9ac, 0xf86e, + 0xf330, 0xf2f2, 0xf0b4, 0xf176, 0xf438, 0xf5fa, 0xf7bc, 0xf67e, + 0xd940, 0xd882, 0xdac4, 0xdb06, 0xde48, 0xdf8a, 0xddcc, 0xdc0e, + 0xd750, 0xd692, 0xd4d4, 0xd516, 0xd058, 0xd19a, 0xd3dc, 0xd21e, + 0xc560, 0xc4a2, 0xc6e4, 0xc726, 0xc268, 0xc3aa, 0xc1ec, 0xc02e, + 0xcb70, 0xcab2, 0xc8f4, 0xc936, 0xcc78, 0xcdba, 0xcffc, 0xce3e, + 0x9180, 0x9042, 0x9204, 0x93c6, 0x9688, 0x974a, 0x950c, 0x94ce, + 0x9f90, 0x9e52, 0x9c14, 0x9dd6, 0x9898, 0x995a, 0x9b1c, 0x9ade, + 0x8da0, 0x8c62, 0x8e24, 0x8fe6, 0x8aa8, 0x8b6a, 0x892c, 0x88ee, + 0x83b0, 0x8272, 0x8034, 0x81f6, 0x84b8, 0x857a, 0x873c, 0x86fe, + 0xa9c0, 0xa802, 0xaa44, 0xab86, 0xaec8, 0xaf0a, 0xad4c, 0xac8e, + 0xa7d0, 0xa612, 0xa454, 0xa596, 0xa0d8, 0xa11a, 0xa35c, 0xa29e, + 0xb5e0, 0xb422, 0xb664, 0xb7a6, 0xb2e8, 0xb32a, 0xb16c, 0xb0ae, + 0xbbf0, 0xba32, 0xb874, 0xb9b6, 0xbcf8, 0xbd3a, 0xbf7c, 0xbebe, +}; + +#ifdef GCM_TABLES_USE_U64 +static void +bshift (u64 * b0, u64 * b1) +{ + u64 t[2], mask; + + t[0] = *b0; + t[1] = *b1; + mask = t[1] & 1 ? 0xe1 : 0; + mask <<= 56; + + *b1 = (t[1] >> 1) ^ (t[0] << 63); + *b0 = (t[0] >> 1) ^ mask; +} + +static void +do_fillM (unsigned char *h, u64 *M) +{ + int i, j; + + M[0 + 0] = 0; + M[0 + 16] = 0; + + M[8 + 0] = buf_get_be64 (h + 0); + M[8 + 16] = buf_get_be64 (h + 8); + + for (i = 4; i > 0; i /= 2) + { + M[i + 0] = M[2 * i + 0]; + M[i + 16] = M[2 * i + 16]; + + bshift (&M[i], &M[i + 16]); + } + + for (i = 2; i < 16; i *= 2) + for (j = 1; j < i; j++) + { + M[(i + j) + 0] = M[i + 0] ^ M[j + 0]; + M[(i + j) + 16] = M[i + 16] ^ M[j + 16]; + } +} + +static inline unsigned int +do_ghash (unsigned char *result, const unsigned char *buf, const u64 *gcmM) +{ + u64 V[2]; + u64 tmp[2]; + const u64 *M; + u64 T; + u32 A; + int i; + + buf_xor (V, result, buf, 16); + V[0] = be_bswap64 (V[0]); + V[1] = be_bswap64 (V[1]); + + /* First round can be manually tweaked based on fact that 'tmp' is zero. */ + i = 15; + + M = &gcmM[(V[1] & 0xf)]; + V[1] >>= 4; + tmp[0] = (M[0] >> 4) ^ ((u64) gcmR[(M[16] & 0xf) << 4] << 48); + tmp[1] = (M[16] >> 4) ^ (M[0] << 60); + tmp[0] ^= gcmM[(V[1] & 0xf) + 0]; + tmp[1] ^= gcmM[(V[1] & 0xf) + 16]; + V[1] >>= 4; + + --i; + while (1) + { + M = &gcmM[(V[1] & 0xf)]; + V[1] >>= 4; + + A = tmp[1] & 0xff; + T = tmp[0]; + tmp[0] = (T >> 8) ^ ((u64) gcmR[A] << 48) ^ gcmM[(V[1] & 0xf) + 0]; + tmp[1] = (T << 56) ^ (tmp[1] >> 8) ^ gcmM[(V[1] & 0xf) + 16]; + + tmp[0] ^= (M[0] >> 4) ^ ((u64) gcmR[(M[16] & 0xf) << 4] << 48); + tmp[1] ^= (M[16] >> 4) ^ (M[0] << 60); + + if (i == 0) + break; + else if (i == 8) + V[1] = V[0]; + else + V[1] >>= 4; + --i; + } + + buf_put_be64 (result + 0, tmp[0]); + buf_put_be64 (result + 8, tmp[1]); + + return (sizeof(V) + sizeof(T) + sizeof(tmp) + + sizeof(int)*2 + sizeof(void*)*5); +} + +#else + +static void +bshift (u32 * M, int i) +{ + u32 t[4], mask; + + t[0] = M[i * 4 + 0]; + t[1] = M[i * 4 + 1]; + t[2] = M[i * 4 + 2]; + t[3] = M[i * 4 + 3]; + mask = t[3] & 1 ? 0xe1 : 0; + + M[i * 4 + 3] = (t[3] >> 1) ^ (t[2] << 31); + M[i * 4 + 2] = (t[2] >> 1) ^ (t[1] << 31); + M[i * 4 + 1] = (t[1] >> 1) ^ (t[0] << 31); + M[i * 4 + 0] = (t[0] >> 1) ^ (mask << 24); +} + +static void +do_fillM (unsigned char *h, u32 *M) +{ + int i, j; + + M[0 * 4 + 0] = 0; + M[0 * 4 + 1] = 0; + M[0 * 4 + 2] = 0; + M[0 * 4 + 3] = 0; + + M[8 * 4 + 0] = buf_get_be32 (h + 0); + M[8 * 4 + 1] = buf_get_be32 (h + 4); + M[8 * 4 + 2] = buf_get_be32 (h + 8); + M[8 * 4 + 3] = buf_get_be32 (h + 12); + + for (i = 4; i > 0; i /= 2) + { + M[i * 4 + 0] = M[2 * i * 4 + 0]; + M[i * 4 + 1] = M[2 * i * 4 + 1]; + M[i * 4 + 2] = M[2 * i * 4 + 2]; + M[i * 4 + 3] = M[2 * i * 4 + 3]; + + bshift (M, i); + } + + for (i = 2; i < 16; i *= 2) + for (j = 1; j < i; j++) + { + M[(i + j) * 4 + 0] = M[i * 4 + 0] ^ M[j * 4 + 0]; + M[(i + j) * 4 + 1] = M[i * 4 + 1] ^ M[j * 4 + 1]; + M[(i + j) * 4 + 2] = M[i * 4 + 2] ^ M[j * 4 + 2]; + M[(i + j) * 4 + 3] = M[i * 4 + 3] ^ M[j * 4 + 3]; + } +} + +static inline unsigned int +do_ghash (unsigned char *result, const unsigned char *buf, const u32 *gcmM) +{ + byte V[16]; + u32 tmp[4]; + u32 v; + const u32 *M, *m; + u32 T[3]; + int i; + + buf_xor (V, result, buf, 16); /* V is big-endian */ + + /* First round can be manually tweaked based on fact that 'tmp' is zero. */ + i = 15; + + v = V[i]; + M = &gcmM[(v & 0xf) * 4]; + v = (v & 0xf0) >> 4; + m = &gcmM[v * 4]; + v = V[--i]; + + tmp[0] = (M[0] >> 4) ^ ((u64) gcmR[(M[3] << 4) & 0xf0] << 16) ^ m[0]; + tmp[1] = (M[1] >> 4) ^ (M[0] << 28) ^ m[1]; + tmp[2] = (M[2] >> 4) ^ (M[1] << 28) ^ m[2]; + tmp[3] = (M[3] >> 4) ^ (M[2] << 28) ^ m[3]; + + while (1) + { + M = &gcmM[(v & 0xf) * 4]; + v = (v & 0xf0) >> 4; + m = &gcmM[v * 4]; + + T[0] = tmp[0]; + T[1] = tmp[1]; + T[2] = tmp[2]; + tmp[0] = (T[0] >> 8) ^ ((u32) gcmR[tmp[3] & 0xff] << 16) ^ m[0]; + tmp[1] = (T[0] << 24) ^ (tmp[1] >> 8) ^ m[1]; + tmp[2] = (T[1] << 24) ^ (tmp[2] >> 8) ^ m[2]; + tmp[3] = (T[2] << 24) ^ (tmp[3] >> 8) ^ m[3]; + + tmp[0] ^= (M[0] >> 4) ^ ((u64) gcmR[(M[3] << 4) & 0xf0] << 16); + tmp[1] ^= (M[1] >> 4) ^ (M[0] << 28); + tmp[2] ^= (M[2] >> 4) ^ (M[1] << 28); + tmp[3] ^= (M[3] >> 4) ^ (M[2] << 28); + + if (i == 0) + break; + + v = V[--i]; + } + + buf_put_be32 (result + 0, tmp[0]); + buf_put_be32 (result + 4, tmp[1]); + buf_put_be32 (result + 8, tmp[2]); + buf_put_be32 (result + 12, tmp[3]); + + return (sizeof(V) + sizeof(T) + sizeof(tmp) + + sizeof(int)*2 + sizeof(void*)*6); +} +#endif /* !HAVE_U64_TYPEDEF || SIZEOF_UNSIGNED_LONG != 8 */ + +#define fillM(c, h) do_fillM (h, c->u_mode.gcm.gcm_table) +#define GHASH(c, result, buf) do_ghash (result, buf, c->u_mode.gcm.gcm_table) + +#else + +static unsigned long +bshift (unsigned long *b) +{ + unsigned long c; + int i; + c = b[3] & 1; + for (i = 3; i > 0; i--) + { + b[i] = (b[i] >> 1) | (b[i - 1] << 31); + } + b[i] >>= 1; + return c; +} + +static unsigned int +do_ghash (unsigned char *hsub, unsigned char *result, const unsigned char *buf) +{ + unsigned long V[4]; + int i, j; + byte *p; + +#ifdef WORDS_BIGENDIAN + p = result; +#else + unsigned long T[4]; + + buf_xor (V, result, buf, 16); + for (i = 0; i < 4; i++) + { + V[i] = (V[i] & 0x00ff00ff) << 8 | (V[i] & 0xff00ff00) >> 8; + V[i] = (V[i] & 0x0000ffff) << 16 | (V[i] & 0xffff0000) >> 16; + } + p = (byte *) T; +#endif + + memset (p, 0, 16); + + for (i = 0; i < 16; i++) + { + for (j = 0x80; j; j >>= 1) + { + if (hsub[i] & j) + buf_xor (p, p, V, 16); + if (bshift (V)) + V[0] ^= 0xe1000000; + } + } +#ifndef WORDS_BIGENDIAN + for (i = 0, p = (byte *) T; i < 16; i += 4, p += 4) + { + result[i + 0] = p[3]; + result[i + 1] = p[2]; + result[i + 2] = p[1]; + result[i + 3] = p[0]; + } +#endif + + return (sizeof(V) + sizeof(T) + sizeof(int)*2 + sizeof(void*)*5); +} + +#define fillM(c, h) do { } while (0) +#define GHASH(c, result, buf) do_ghash (c->u_mode.gcm.u_ghash_key.key, result, buf) + +#endif /* !GCM_USE_TABLES */ + + +#ifdef GCM_USE_INTEL_PCLMUL +/* + Intel PCLMUL ghash based on white paper: + "Intel® Carry-Less Multiplication Instruction and its Usage for Computing the + GCM Mode - Rev 2.01"; Shay Gueron, Michael E. Kounavis. + */ +static inline void gfmul_pclmul(void) +{ + /* Input: XMM0 and XMM1, Output: XMM1. Input XMM0 stays unmodified. + Input must be converted to little-endian. + */ + asm volatile (/* gfmul, xmm0 has operator a and xmm1 has operator b. */ + "pshufd $78, %%xmm0, %%xmm2\n\t" + "pshufd $78, %%xmm1, %%xmm4\n\t" + "pxor %%xmm0, %%xmm2\n\t" /* xmm2 holds a0+a1 */ + "pxor %%xmm1, %%xmm4\n\t" /* xmm4 holds b0+b1 */ + + "movdqa %%xmm0, %%xmm3\n\t" + "pclmulqdq $0, %%xmm1, %%xmm3\n\t" /* xmm3 holds a0*b0 */ + "movdqa %%xmm0, %%xmm6\n\t" + "pclmulqdq $17, %%xmm1, %%xmm6\n\t" /* xmm6 holds a1*b1 */ + "movdqa %%xmm3, %%xmm5\n\t" + "pclmulqdq $0, %%xmm2, %%xmm4\n\t" /* xmm4 holds (a0+a1)*(b0+b1) */ + + "pxor %%xmm6, %%xmm5\n\t" /* xmm5 holds a0*b0+a1*b1 */ + "pxor %%xmm5, %%xmm4\n\t" /* xmm4 holds a0*b0+a1*b1+(a0+a1)*(b0+b1) */ + "movdqa %%xmm4, %%xmm5\n\t" + "psrldq $8, %%xmm4\n\t" + "pslldq $8, %%xmm5\n\t" + "pxor %%xmm5, %%xmm3\n\t" + "pxor %%xmm4, %%xmm6\n\t" /* <xmm6:xmm3> holds the result of the + carry-less multiplication of xmm0 + by xmm1 */ + + /* shift the result by one bit position to the left cope for + the fact that bits are reversed */ + "movdqa %%xmm3, %%xmm4\n\t" + "movdqa %%xmm6, %%xmm5\n\t" + "pslld $1, %%xmm3\n\t" + "pslld $1, %%xmm6\n\t" + "psrld $31, %%xmm4\n\t" + "psrld $31, %%xmm5\n\t" + "movdqa %%xmm4, %%xmm1\n\t" + "pslldq $4, %%xmm5\n\t" + "pslldq $4, %%xmm4\n\t" + "psrldq $12, %%xmm1\n\t" + "por %%xmm4, %%xmm3\n\t" + "por %%xmm5, %%xmm6\n\t" + "por %%xmm6, %%xmm1\n\t" + + /* first phase of the reduction */ + "movdqa %%xmm3, %%xmm6\n\t" + "movdqa %%xmm3, %%xmm7\n\t" + "pslld $31, %%xmm6\n\t" /* packed right shifting << 31 */ + "movdqa %%xmm3, %%xmm5\n\t" + "pslld $30, %%xmm7\n\t" /* packed right shifting shift << 30 */ + "pslld $25, %%xmm5\n\t" /* packed right shifting shift << 25 */ + "pxor %%xmm7, %%xmm6\n\t" /* xor the shifted versions */ + "pxor %%xmm5, %%xmm6\n\t" + "movdqa %%xmm6, %%xmm7\n\t" + "pslldq $12, %%xmm6\n\t" + "psrldq $4, %%xmm7\n\t" + "pxor %%xmm6, %%xmm3\n\t" /* first phase of the reduction + complete */ + + /* second phase of the reduction */ + "movdqa %%xmm3, %%xmm2\n\t" + "movdqa %%xmm3, %%xmm4\n\t" + "psrld $1, %%xmm2\n\t" /* packed left shifting >> 1 */ + "movdqa %%xmm3, %%xmm5\n\t" + "psrld $2, %%xmm4\n\t" /* packed left shifting >> 2 */ + "psrld $7, %%xmm5\n\t" /* packed left shifting >> 7 */ + "pxor %%xmm4, %%xmm2\n\t" /* xor the shifted versions */ + "pxor %%xmm5, %%xmm2\n\t" + "pxor %%xmm7, %%xmm2\n\t" + "pxor %%xmm2, %%xmm3\n\t" + "pxor %%xmm3, %%xmm1\n\t" /* the result is in xmm1 */ + ::: "cc" ); +} + +#ifdef __x86_64__ +static inline void gfmul_pclmul_aggr4(void) +{ + /* Input: + H¹: XMM0 X_i : XMM6 + H²: XMM8 X_(i-1) : XMM3 + H³: XMM9 X_(i-2) : XMM2 + H⁴: XMM10 X_(i-3)⊕Y_(i-4): XMM1 + Output: + Y_i: XMM1 + Inputs XMM0 stays unmodified. + Input must be converted to little-endian. + */ + asm volatile (/* perform clmul and merge results... */ + "pshufd $78, %%xmm10, %%xmm11\n\t" + "pshufd $78, %%xmm1, %%xmm12\n\t" + "pxor %%xmm10, %%xmm11\n\t" /* xmm11 holds 4:a0+a1 */ + "pxor %%xmm1, %%xmm12\n\t" /* xmm12 holds 4:b0+b1 */ + + "pshufd $78, %%xmm9, %%xmm13\n\t" + "pshufd $78, %%xmm2, %%xmm14\n\t" + "pxor %%xmm9, %%xmm13\n\t" /* xmm13 holds 3:a0+a1 */ + "pxor %%xmm2, %%xmm14\n\t" /* xmm14 holds 3:b0+b1 */ + + "pshufd $78, %%xmm8, %%xmm5\n\t" + "pshufd $78, %%xmm3, %%xmm15\n\t" + "pxor %%xmm8, %%xmm5\n\t" /* xmm1 holds 2:a0+a1 */ + "pxor %%xmm3, %%xmm15\n\t" /* xmm2 holds 2:b0+b1 */ + + "movdqa %%xmm10, %%xmm4\n\t" + "movdqa %%xmm9, %%xmm7\n\t" + "pclmulqdq $0, %%xmm1, %%xmm4\n\t" /* xmm4 holds 4:a0*b0 */ + "pclmulqdq $0, %%xmm2, %%xmm7\n\t" /* xmm7 holds 3:a0*b0 */ + "pclmulqdq $17, %%xmm10, %%xmm1\n\t" /* xmm1 holds 4:a1*b1 */ + "pclmulqdq $17, %%xmm9, %%xmm2\n\t" /* xmm9 holds 3:a1*b1 */ + "pclmulqdq $0, %%xmm11, %%xmm12\n\t" /* xmm12 holds 4:(a0+a1)*(b0+b1) */ + "pclmulqdq $0, %%xmm13, %%xmm14\n\t" /* xmm14 holds 3:(a0+a1)*(b0+b1) */ + + "pshufd $78, %%xmm0, %%xmm10\n\t" + "pshufd $78, %%xmm6, %%xmm11\n\t" + "pxor %%xmm0, %%xmm10\n\t" /* xmm10 holds 1:a0+a1 */ + "pxor %%xmm6, %%xmm11\n\t" /* xmm11 holds 1:b0+b1 */ + + "pxor %%xmm4, %%xmm7\n\t" /* xmm7 holds 3+4:a0*b0 */ + "pxor %%xmm2, %%xmm1\n\t" /* xmm1 holds 3+4:a1*b1 */ + "pxor %%xmm14, %%xmm12\n\t" /* xmm12 holds 3+4:(a0+a1)*(b0+b1) */ + + "movdqa %%xmm8, %%xmm13\n\t" + "pclmulqdq $0, %%xmm3, %%xmm13\n\t" /* xmm13 holds 2:a0*b0 */ + "pclmulqdq $17, %%xmm8, %%xmm3\n\t" /* xmm3 holds 2:a1*b1 */ + "pclmulqdq $0, %%xmm5, %%xmm15\n\t" /* xmm15 holds 2:(a0+a1)*(b0+b1) */ + + "pxor %%xmm13, %%xmm7\n\t" /* xmm7 holds 2+3+4:a0*b0 */ + "pxor %%xmm3, %%xmm1\n\t" /* xmm1 holds 2+3+4:a1*b1 */ + "pxor %%xmm15, %%xmm12\n\t" /* xmm12 holds 2+3+4:(a0+a1)*(b0+b1) */ + + "movdqa %%xmm0, %%xmm3\n\t" + "pclmulqdq $0, %%xmm6, %%xmm3\n\t" /* xmm3 holds 1:a0*b0 */ + "pclmulqdq $17, %%xmm0, %%xmm6\n\t" /* xmm6 holds 1:a1*b1 */ + "movdqa %%xmm11, %%xmm4\n\t" + "pclmulqdq $0, %%xmm10, %%xmm4\n\t" /* xmm4 holds 1:(a0+a1)*(b0+b1) */ + + "pxor %%xmm7, %%xmm3\n\t" /* xmm3 holds 1+2+3+4:a0*b0 */ + "pxor %%xmm1, %%xmm6\n\t" /* xmm6 holds 1+2+3+4:a1*b1 */ + "pxor %%xmm12, %%xmm4\n\t" /* xmm4 holds 1+2+3+4:(a0+a1)*(b0+b1) */ + + /* aggregated reduction... */ + "movdqa %%xmm3, %%xmm5\n\t" + "pxor %%xmm6, %%xmm5\n\t" /* xmm5 holds a0*b0+a1*b1 */ + "pxor %%xmm5, %%xmm4\n\t" /* xmm4 holds a0*b0+a1*b1+(a0+a1)*(b0+b1) */ + "movdqa %%xmm4, %%xmm5\n\t" + "psrldq $8, %%xmm4\n\t" + "pslldq $8, %%xmm5\n\t" + "pxor %%xmm5, %%xmm3\n\t" + "pxor %%xmm4, %%xmm6\n\t" /* <xmm6:xmm3> holds the result of the + carry-less multiplication of xmm0 + by xmm1 */ + + /* shift the result by one bit position to the left cope for + the fact that bits are reversed */ + "movdqa %%xmm3, %%xmm4\n\t" + "movdqa %%xmm6, %%xmm5\n\t" + "pslld $1, %%xmm3\n\t" + "pslld $1, %%xmm6\n\t" + "psrld $31, %%xmm4\n\t" + "psrld $31, %%xmm5\n\t" + "movdqa %%xmm4, %%xmm1\n\t" + "pslldq $4, %%xmm5\n\t" + "pslldq $4, %%xmm4\n\t" + "psrldq $12, %%xmm1\n\t" + "por %%xmm4, %%xmm3\n\t" + "por %%xmm5, %%xmm6\n\t" + "por %%xmm6, %%xmm1\n\t" + + /* first phase of the reduction */ + "movdqa %%xmm3, %%xmm6\n\t" + "movdqa %%xmm3, %%xmm7\n\t" + "pslld $31, %%xmm6\n\t" /* packed right shifting << 31 */ + "movdqa %%xmm3, %%xmm5\n\t" + "pslld $30, %%xmm7\n\t" /* packed right shifting shift << 30 */ + "pslld $25, %%xmm5\n\t" /* packed right shifting shift << 25 */ + "pxor %%xmm7, %%xmm6\n\t" /* xor the shifted versions */ + "pxor %%xmm5, %%xmm6\n\t" + "movdqa %%xmm6, %%xmm7\n\t" + "pslldq $12, %%xmm6\n\t" + "psrldq $4, %%xmm7\n\t" + "pxor %%xmm6, %%xmm3\n\t" /* first phase of the reduction + complete */ + + /* second phase of the reduction */ + "movdqa %%xmm3, %%xmm2\n\t" + "movdqa %%xmm3, %%xmm4\n\t" + "psrld $1, %%xmm2\n\t" /* packed left shifting >> 1 */ + "movdqa %%xmm3, %%xmm5\n\t" + "psrld $2, %%xmm4\n\t" /* packed left shifting >> 2 */ + "psrld $7, %%xmm5\n\t" /* packed left shifting >> 7 */ + "pxor %%xmm4, %%xmm2\n\t" /* xor the shifted versions */ + "pxor %%xmm5, %%xmm2\n\t" + "pxor %%xmm7, %%xmm2\n\t" + "pxor %%xmm2, %%xmm3\n\t" + "pxor %%xmm3, %%xmm1\n\t" /* the result is in xmm1 */ + :::"cc"); +} +#endif + +#endif /*GCM_USE_INTEL_PCLMUL*/ + + +static unsigned int +ghash (gcry_cipher_hd_t c, byte *result, const byte *buf, + size_t nblocks) +{ + const unsigned int blocksize = GCRY_GCM_BLOCK_LEN; + unsigned int burn; + + if (nblocks == 0) + return 0; + + if (0) + ; +#ifdef GCM_USE_INTEL_PCLMUL + else if (c->u_mode.gcm.use_intel_pclmul) + { + static const unsigned char be_mask[16] __attribute__ ((aligned (16))) = + { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + + /* Preload hash and H1. */ + asm volatile ("movdqu %[hash], %%xmm1\n\t" + "movdqa %[hsub], %%xmm0\n\t" + "pshufb %[be_mask], %%xmm1\n\t" /* be => le */ + : + : [hash] "m" (*result), [be_mask] "m" (*be_mask), + [hsub] "m" (*c->u_mode.gcm.u_ghash_key.key)); + +#ifdef __x86_64__ + if (nblocks >= 4) + { + do + { + asm volatile ("movdqa %[be_mask], %%xmm4\n\t" + "movdqu 0*16(%[buf]), %%xmm5\n\t" + "movdqu 1*16(%[buf]), %%xmm2\n\t" + "movdqu 2*16(%[buf]), %%xmm3\n\t" + "movdqu 3*16(%[buf]), %%xmm6\n\t" + "pshufb %%xmm4, %%xmm5\n\t" /* be => le */ + + /* Load H2, H3, H4. */ + "movdqu 2*16(%[h_234]), %%xmm10\n\t" + "movdqu 1*16(%[h_234]), %%xmm9\n\t" + "movdqu 0*16(%[h_234]), %%xmm8\n\t" + + "pxor %%xmm5, %%xmm1\n\t" + "pshufb %%xmm4, %%xmm2\n\t" /* be => le */ + "pshufb %%xmm4, %%xmm3\n\t" /* be => le */ + "pshufb %%xmm4, %%xmm6\n\t" /* be => le */ + : + : [buf] "r" (buf), [be_mask] "m" (*be_mask), + [h_234] "r" (c->u_mode.gcm.gcm_table)); + + gfmul_pclmul_aggr4 (); + + buf += 4 * blocksize; + nblocks -= 4; + } + while (nblocks >= 4); + + /* Clear used x86-64/XMM registers. */ + asm volatile( "pxor %%xmm8, %%xmm8\n\t" + "pxor %%xmm9, %%xmm9\n\t" + "pxor %%xmm10, %%xmm10\n\t" + "pxor %%xmm11, %%xmm11\n\t" + "pxor %%xmm12, %%xmm12\n\t" + "pxor %%xmm13, %%xmm13\n\t" + "pxor %%xmm14, %%xmm14\n\t" + "pxor %%xmm15, %%xmm15\n\t" + ::: "cc" ); + } +#endif + + while (nblocks--) + { + asm volatile ("movdqu %[buf], %%xmm2\n\t" + "pshufb %[be_mask], %%xmm2\n\t" /* be => le */ + "pxor %%xmm2, %%xmm1\n\t" + : + : [buf] "m" (*buf), [be_mask] "m" (*be_mask)); + + gfmul_pclmul (); + + buf += blocksize; + } + + /* Store hash. */ + asm volatile ("pshufb %[be_mask], %%xmm1\n\t" /* be => le */ + "movdqu %%xmm1, %[hash]\n\t" + : [hash] "=m" (*result) + : [be_mask] "m" (*be_mask)); + + /* Clear used registers. */ + asm volatile( "pxor %%xmm0, %%xmm0\n\t" + "pxor %%xmm1, %%xmm1\n\t" + "pxor %%xmm2, %%xmm2\n\t" + "pxor %%xmm3, %%xmm3\n\t" + "pxor %%xmm4, %%xmm4\n\t" + "pxor %%xmm5, %%xmm5\n\t" + "pxor %%xmm6, %%xmm6\n\t" + "pxor %%xmm7, %%xmm7\n\t" + ::: "cc" ); + burn = 0; + } +#endif + else + { + while (nblocks) + { + burn = GHASH (c, result, buf); + buf += blocksize; + nblocks--; + } + } + + return burn + (burn ? 5*sizeof(void*) : 0); +} + + +static void +setupM (gcry_cipher_hd_t c, byte *h) +{ + if (0) + ; +#ifdef GCM_USE_INTEL_PCLMUL + else if (_gcry_get_hw_features () & HWF_INTEL_PCLMUL) + { + u64 tmp[2]; + + c->u_mode.gcm.use_intel_pclmul = 1; + + /* Swap endianness of hsub. */ + tmp[0] = buf_get_be64(c->u_mode.gcm.u_ghash_key.key + 8); + tmp[1] = buf_get_be64(c->u_mode.gcm.u_ghash_key.key + 0); + buf_cpy (c->u_mode.gcm.u_ghash_key.key, tmp, GCRY_GCM_BLOCK_LEN); + +#ifdef __x86_64__ + asm volatile ("movdqu %[h_1], %%xmm0\n\t" + "movdqa %%xmm0, %%xmm1\n\t" + : + : [h_1] "m" (*tmp)); + + gfmul_pclmul (); /* H•H => H² */ + + asm volatile ("movdqu %%xmm1, 0*16(%[h_234])\n\t" + "movdqa %%xmm1, %%xmm8\n\t" + : + : [h_234] "r" (c->u_mode.gcm.gcm_table) + : "memory"); + + gfmul_pclmul (); /* H•H² => H³ */ + + asm volatile ("movdqa %%xmm8, %%xmm0\n\t" + "movdqu %%xmm1, 1*16(%[h_234])\n\t" + "movdqa %%xmm8, %%xmm1\n\t" + : + : [h_234] "r" (c->u_mode.gcm.gcm_table) + : "memory"); + + gfmul_pclmul (); /* H²•H² => H⁴ */ + + asm volatile ("movdqu %%xmm1, 2*16(%[h_234])\n\t" + : + : [h_234] "r" (c->u_mode.gcm.gcm_table) + : "memory"); + + /* Clear used registers. */ + asm volatile( "pxor %%xmm0, %%xmm0\n\t" + "pxor %%xmm1, %%xmm1\n\t" + "pxor %%xmm2, %%xmm2\n\t" + "pxor %%xmm3, %%xmm3\n\t" + "pxor %%xmm4, %%xmm4\n\t" + "pxor %%xmm5, %%xmm5\n\t" + "pxor %%xmm6, %%xmm6\n\t" + "pxor %%xmm7, %%xmm7\n\t" + "pxor %%xmm8, %%xmm8\n\t" + ::: "cc" ); +#endif + + wipememory (tmp, sizeof(tmp)); + } +#endif + else + fillM (c, h); +} + + +static inline void +gcm_bytecounter_add (u32 ctr[2], size_t add) +{ + if (sizeof(add) > sizeof(u32)) + { + u32 high_add = ((add >> 31) >> 1) & 0xffffffff; + ctr[1] += high_add; + } + + ctr[0] += add; + if (ctr[0] >= add) + return; + ++ctr[1]; +} + + +static inline u32 +gcm_add32_be128 (byte *ctr, unsigned int add) +{ + /* 'ctr' must be aligned to four bytes. */ + const unsigned int blocksize = GCRY_GCM_BLOCK_LEN; + u32 *pval = (u32 *)(void *)(ctr + blocksize - sizeof(u32)); + u32 val; + + val = be_bswap32(*pval) + add; + *pval = be_bswap32(val); + + return val; /* return result as host-endian value */ +} + + +static inline int +gcm_check_datalen (u32 ctr[2]) +{ + /* len(plaintext) <= 2^39-256 bits == 2^36-32 bytes == 2^32-2 blocks */ + if (ctr[1] > 0xfU) + return 0; + if (ctr[1] < 0xfU) + return 1; + + if (ctr[0] <= 0xffffffe0U) + return 1; + + return 0; +} + + +static inline int +gcm_check_aadlen_or_ivlen (u32 ctr[2]) +{ + /* len(aad/iv) <= 2^64-1 bits ~= 2^61-1 bytes */ + if (ctr[1] > 0x1fffffffU) + return 0; + if (ctr[1] < 0x1fffffffU) + return 1; + + if (ctr[0] <= 0xffffffffU) + return 1; + + return 0; +} + + +static void +do_ghash_buf(gcry_cipher_hd_t c, byte *hash, const byte *buf, + size_t buflen, int do_padding) +{ + unsigned int blocksize = GCRY_GCM_BLOCK_LEN; + unsigned int unused = c->u_mode.gcm.mac_unused; + size_t nblocks, n; + unsigned int burn = 0; + + if (buflen == 0 && (unused == 0 || !do_padding)) + return; + + do + { + if (buflen + unused < blocksize || unused > 0) + { + n = blocksize - unused; + n = n < buflen ? n : buflen; + + buf_cpy (&c->u_mode.gcm.macbuf[unused], buf, n); + + unused += n; + buf += n; + buflen -= n; + } + if (!buflen) + { + if (!do_padding) + break; + + while (unused < blocksize) + c->u_mode.gcm.macbuf[unused++] = 0; + } + + if (unused > 0) + { + gcry_assert (unused == blocksize); + + /* Process one block from macbuf. */ + burn = ghash (c, hash, c->u_mode.gcm.macbuf, 1); + unused = 0; + } + + nblocks = buflen / blocksize; + + if (nblocks) + { + burn = ghash (c, hash, buf, nblocks); + buf += blocksize * nblocks; + buflen -= blocksize * nblocks; + } + } + while (buflen > 0); + + c->u_mode.gcm.mac_unused = unused; + + if (burn) + _gcry_burn_stack (burn); +} + + +gcry_err_code_t +_gcry_cipher_gcm_encrypt (gcry_cipher_hd_t c, + byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen) +{ + static const unsigned char zerobuf[MAX_BLOCKSIZE]; + gcry_err_code_t err; + + if (c->spec->blocksize != GCRY_GCM_BLOCK_LEN) + return GPG_ERR_CIPHER_ALGO; + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (c->u_mode.gcm.datalen_over_limits) + return GPG_ERR_INV_LENGTH; + if (c->marks.tag || c->u_mode.gcm.ghash_data_finalized) + return GPG_ERR_INV_STATE; + + if (!c->marks.iv) + _gcry_cipher_gcm_setiv (c, zerobuf, GCRY_GCM_BLOCK_LEN); + + if (c->u_mode.gcm.disallow_encryption_because_of_setiv_in_fips_mode) + return GPG_ERR_INV_STATE; + + if (!c->u_mode.gcm.ghash_aad_finalized) + { + /* Start of encryption marks end of AAD stream. */ + do_ghash_buf(c, c->u_mode.gcm.u_tag.tag, NULL, 0, 1); + c->u_mode.gcm.ghash_aad_finalized = 1; + } + + gcm_bytecounter_add(c->u_mode.gcm.datalen, inbuflen); + if (!gcm_check_datalen(c->u_mode.gcm.datalen)) + { + c->u_mode.gcm.datalen_over_limits = 1; + return GPG_ERR_INV_LENGTH; + } + + err = _gcry_cipher_ctr_encrypt(c, outbuf, outbuflen, inbuf, inbuflen); + if (err != 0) + return err; + + do_ghash_buf(c, c->u_mode.gcm.u_tag.tag, outbuf, inbuflen, 0); + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_gcm_decrypt (gcry_cipher_hd_t c, + byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen) +{ + static const unsigned char zerobuf[MAX_BLOCKSIZE]; + + if (c->spec->blocksize != GCRY_GCM_BLOCK_LEN) + return GPG_ERR_CIPHER_ALGO; + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if (c->u_mode.gcm.datalen_over_limits) + return GPG_ERR_INV_LENGTH; + if (c->marks.tag || c->u_mode.gcm.ghash_data_finalized) + return GPG_ERR_INV_STATE; + + if (!c->marks.iv) + _gcry_cipher_gcm_setiv (c, zerobuf, GCRY_GCM_BLOCK_LEN); + + if (!c->u_mode.gcm.ghash_aad_finalized) + { + /* Start of decryption marks end of AAD stream. */ + do_ghash_buf(c, c->u_mode.gcm.u_tag.tag, NULL, 0, 1); + c->u_mode.gcm.ghash_aad_finalized = 1; + } + + gcm_bytecounter_add(c->u_mode.gcm.datalen, inbuflen); + if (!gcm_check_datalen(c->u_mode.gcm.datalen)) + { + c->u_mode.gcm.datalen_over_limits = 1; + return GPG_ERR_INV_LENGTH; + } + + do_ghash_buf(c, c->u_mode.gcm.u_tag.tag, inbuf, inbuflen, 0); + + return _gcry_cipher_ctr_encrypt(c, outbuf, outbuflen, inbuf, inbuflen); +} + + +gcry_err_code_t +_gcry_cipher_gcm_authenticate (gcry_cipher_hd_t c, + const byte * aadbuf, size_t aadbuflen) +{ + static const unsigned char zerobuf[MAX_BLOCKSIZE]; + + if (c->spec->blocksize != GCRY_GCM_BLOCK_LEN) + return GPG_ERR_CIPHER_ALGO; + if (c->u_mode.gcm.datalen_over_limits) + return GPG_ERR_INV_LENGTH; + if (c->marks.tag || c->u_mode.gcm.ghash_aad_finalized || + c->u_mode.gcm.ghash_data_finalized) + return GPG_ERR_INV_STATE; + + if (!c->marks.iv) + _gcry_cipher_gcm_setiv (c, zerobuf, GCRY_GCM_BLOCK_LEN); + + gcm_bytecounter_add(c->u_mode.gcm.aadlen, aadbuflen); + if (!gcm_check_aadlen_or_ivlen(c->u_mode.gcm.aadlen)) + { + c->u_mode.gcm.datalen_over_limits = 1; + return GPG_ERR_INV_LENGTH; + } + + do_ghash_buf(c, c->u_mode.gcm.u_tag.tag, aadbuf, aadbuflen, 0); + + return 0; +} + + +void +_gcry_cipher_gcm_setkey (gcry_cipher_hd_t c) +{ + memset (c->u_mode.gcm.u_ghash_key.key, 0, GCRY_GCM_BLOCK_LEN); + + c->spec->encrypt (&c->context.c, c->u_mode.gcm.u_ghash_key.key, + c->u_mode.gcm.u_ghash_key.key); + setupM (c, c->u_mode.gcm.u_ghash_key.key); +} + + +static gcry_err_code_t +_gcry_cipher_gcm_initiv (gcry_cipher_hd_t c, const byte *iv, size_t ivlen) +{ + memset (c->u_mode.gcm.aadlen, 0, sizeof(c->u_mode.gcm.aadlen)); + memset (c->u_mode.gcm.datalen, 0, sizeof(c->u_mode.gcm.datalen)); + memset (c->u_mode.gcm.u_tag.tag, 0, GCRY_GCM_BLOCK_LEN); + c->u_mode.gcm.datalen_over_limits = 0; + c->u_mode.gcm.ghash_data_finalized = 0; + c->u_mode.gcm.ghash_aad_finalized = 0; + + if (ivlen == 0) + return GPG_ERR_INV_LENGTH; + + if (ivlen != GCRY_GCM_BLOCK_LEN - 4) + { + u32 iv_bytes[2] = {0, 0}; + u32 bitlengths[2][2]; + + memset(c->u_ctr.ctr, 0, GCRY_GCM_BLOCK_LEN); + + gcm_bytecounter_add(iv_bytes, ivlen); + if (!gcm_check_aadlen_or_ivlen(iv_bytes)) + { + c->u_mode.gcm.datalen_over_limits = 1; + return GPG_ERR_INV_LENGTH; + } + + do_ghash_buf(c, c->u_ctr.ctr, iv, ivlen, 1); + + /* iv length, 64-bit */ + bitlengths[1][1] = be_bswap32(iv_bytes[0] << 3); + bitlengths[1][0] = be_bswap32((iv_bytes[0] >> 29) | + (iv_bytes[1] << 3)); + /* zeros, 64-bit */ + bitlengths[0][1] = 0; + bitlengths[0][0] = 0; + + do_ghash_buf(c, c->u_ctr.ctr, (byte*)bitlengths, GCRY_GCM_BLOCK_LEN, 1); + + wipememory (iv_bytes, sizeof iv_bytes); + wipememory (bitlengths, sizeof bitlengths); + } + else + { + /* 96-bit IV is handled differently. */ + memcpy (c->u_ctr.ctr, iv, ivlen); + c->u_ctr.ctr[12] = c->u_ctr.ctr[13] = c->u_ctr.ctr[14] = 0; + c->u_ctr.ctr[15] = 1; + } + + c->spec->encrypt (&c->context.c, c->u_mode.gcm.tagiv, c->u_ctr.ctr); + + gcm_add32_be128 (c->u_ctr.ctr, 1); + + c->unused = 0; + c->marks.iv = 1; + c->marks.tag = 0; + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_gcm_setiv (gcry_cipher_hd_t c, const byte *iv, size_t ivlen) +{ + c->marks.iv = 0; + c->marks.tag = 0; + c->u_mode.gcm.disallow_encryption_because_of_setiv_in_fips_mode = 0; + + if (fips_mode ()) + { + /* Direct invocation of GCM setiv in FIPS mode disables encryption. */ + c->u_mode.gcm.disallow_encryption_because_of_setiv_in_fips_mode = 1; + } + + return _gcry_cipher_gcm_initiv (c, iv, ivlen); +} + + +#if 0 && TODO +void +_gcry_cipher_gcm_geniv (gcry_cipher_hd_t c, + byte *ivout, size_t ivoutlen, const byte *nonce, + size_t noncelen) +{ + /* nonce: user provided part (might be null) */ + /* noncelen: check if proper length (if nonce not null) */ + /* ivout: iv used to initialize gcm, output to user */ + /* ivoutlen: check correct size */ + byte iv[IVLEN]; + + if (!ivout) + return GPG_ERR_INV_ARG; + if (ivoutlen != IVLEN) + return GPG_ERR_INV_LENGTH; + if (nonce != NULL && !is_nonce_ok_len(noncelen)) + return GPG_ERR_INV_ARG; + + gcm_generate_iv(iv, nonce, noncelen); + + c->marks.iv = 0; + c->marks.tag = 0; + c->u_mode.gcm.disallow_encryption_because_of_setiv_in_fips_mode = 0; + + _gcry_cipher_gcm_initiv (c, iv, IVLEN); + + buf_cpy(ivout, iv, IVLEN); + wipememory(iv, sizeof(iv)); +} +#endif + + +static gcry_err_code_t +_gcry_cipher_gcm_tag (gcry_cipher_hd_t c, + byte * outbuf, size_t outbuflen, int check) +{ + if (outbuflen < GCRY_GCM_BLOCK_LEN) + return GPG_ERR_BUFFER_TOO_SHORT; + if (c->u_mode.gcm.datalen_over_limits) + return GPG_ERR_INV_LENGTH; + + if (!c->marks.tag) + { + u32 bitlengths[2][2]; + + /* aad length */ + bitlengths[0][1] = be_bswap32(c->u_mode.gcm.aadlen[0] << 3); + bitlengths[0][0] = be_bswap32((c->u_mode.gcm.aadlen[0] >> 29) | + (c->u_mode.gcm.aadlen[1] << 3)); + /* data length */ + bitlengths[1][1] = be_bswap32(c->u_mode.gcm.datalen[0] << 3); + bitlengths[1][0] = be_bswap32((c->u_mode.gcm.datalen[0] >> 29) | + (c->u_mode.gcm.datalen[1] << 3)); + + /* Finalize data-stream. */ + do_ghash_buf(c, c->u_mode.gcm.u_tag.tag, NULL, 0, 1); + c->u_mode.gcm.ghash_aad_finalized = 1; + c->u_mode.gcm.ghash_data_finalized = 1; + + /* Add bitlengths to tag. */ + do_ghash_buf(c, c->u_mode.gcm.u_tag.tag, (byte*)bitlengths, + GCRY_GCM_BLOCK_LEN, 1); + buf_xor (c->u_mode.gcm.u_tag.tag, c->u_mode.gcm.tagiv, + c->u_mode.gcm.u_tag.tag, GCRY_GCM_BLOCK_LEN); + c->marks.tag = 1; + + wipememory (bitlengths, sizeof (bitlengths)); + wipememory (c->u_mode.gcm.macbuf, GCRY_GCM_BLOCK_LEN); + wipememory (c->u_mode.gcm.tagiv, GCRY_GCM_BLOCK_LEN); + wipememory (c->u_mode.gcm.aadlen, sizeof (c->u_mode.gcm.aadlen)); + wipememory (c->u_mode.gcm.datalen, sizeof (c->u_mode.gcm.datalen)); + } + + if (!check) + { + memcpy (outbuf, c->u_mode.gcm.u_tag.tag, outbuflen); + return GPG_ERR_NO_ERROR; + } + else + { + return buf_eq_const(outbuf, c->u_mode.gcm.u_tag.tag, outbuflen) ? + GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM; + } + + return 0; +} + + +gcry_err_code_t +_gcry_cipher_gcm_get_tag (gcry_cipher_hd_t c, unsigned char *outtag, + size_t taglen) +{ + /* Outputting authentication tag is part of encryption. */ + if (c->u_mode.gcm.disallow_encryption_because_of_setiv_in_fips_mode) + return GPG_ERR_INV_STATE; + + return _gcry_cipher_gcm_tag (c, outtag, taglen, 0); +} + +gcry_err_code_t +_gcry_cipher_gcm_check_tag (gcry_cipher_hd_t c, const unsigned char *intag, + size_t taglen) +{ + return _gcry_cipher_gcm_tag (c, (unsigned char *) intag, taglen, 1); +} diff --git a/plugins/MirOTR/Libgcrypt/cipher/cipher-internal.h b/plugins/MirOTR/Libgcrypt/cipher/cipher-internal.h new file mode 100644 index 0000000000..cdac445fb9 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/cipher-internal.h @@ -0,0 +1,322 @@ +/* cipher-internal.h - Internal defs for cipher.c + * Copyright (C) 2011 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef G10_CIPHER_INTERNAL_H +#define G10_CIPHER_INTERNAL_H + +/* The maximum supported size of a block in bytes. */ +#define MAX_BLOCKSIZE 16 + +/* Magic values for the context structure. */ +#define CTX_MAGIC_NORMAL 0x24091964 +#define CTX_MAGIC_SECURE 0x46919042 + +/* Try to use 16 byte aligned cipher context for better performance. + We use the aligned attribute, thus it is only possible to implement + this with gcc. */ +#undef NEED_16BYTE_ALIGNED_CONTEXT +#ifdef HAVE_GCC_ATTRIBUTE_ALIGNED +# define NEED_16BYTE_ALIGNED_CONTEXT 1 +#endif + +/* Undef this symbol to trade GCM speed for 256 bytes of memory per context */ +#define GCM_USE_TABLES 1 + + +/* GCM_USE_INTEL_PCLMUL inidicates whether to compile GCM with Intel PCLMUL + code. */ +#undef GCM_USE_INTEL_PCLMUL +#if defined(ENABLE_PCLMUL_SUPPORT) && defined(GCM_USE_TABLES) +# if ((defined(__i386__) && SIZEOF_UNSIGNED_LONG == 4) || defined(__x86_64__)) +# if __GNUC__ >= 4 +# define GCM_USE_INTEL_PCLMUL 1 +# endif +# endif +#endif /* GCM_USE_INTEL_PCLMUL */ + + +/* A VIA processor with the Padlock engine as well as the Intel AES_NI + instructions require an alignment of most data on a 16 byte + boundary. Because we trick out the compiler while allocating the + context, the align attribute as used in rijndael.c does not work on + its own. Thus we need to make sure that the entire context + structure is a aligned on that boundary. We achieve this by + defining a new type and use that instead of our usual alignment + type. */ +typedef union +{ + PROPERLY_ALIGNED_TYPE foo; +#ifdef NEED_16BYTE_ALIGNED_CONTEXT + char bar[16] __attribute__ ((aligned (16))); +#endif + char c[1]; +} cipher_context_alignment_t; + + +/* The handle structure. */ +struct gcry_cipher_handle +{ + int magic; + size_t actual_handle_size; /* Allocated size of this handle. */ + size_t handle_offset; /* Offset to the malloced block. */ + gcry_cipher_spec_t *spec; + + /* The algorithm id. This is a hack required because the module + interface does not easily allow to retrieve this value. */ + int algo; + + /* A structure with function pointers for bulk operations. Due to + limitations of the module system (we don't want to change the + API) we need to keep these function pointers here. The cipher + open function intializes them and the actual encryption routines + use them if they are not NULL. */ + struct { + void (*cfb_enc)(void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks); + void (*cfb_dec)(void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks); + void (*cbc_enc)(void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks, int cbc_mac); + void (*cbc_dec)(void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks); + void (*ctr_enc)(void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks); + } bulk; + + + int mode; + unsigned int flags; + + struct { + unsigned int key:1; /* Set to 1 if a key has been set. */ + unsigned int iv:1; /* Set to 1 if a IV has been set. */ + unsigned int tag:1; /* Set to 1 if a tag is finalized. */ + } marks; + + /* The initialization vector. For best performance we make sure + that it is properly aligned. In particular some implementations + of bulk operations expect an 16 byte aligned IV. IV is also used + to store CBC-MAC in CCM mode; counter IV is stored in U_CTR. */ + union { + cipher_context_alignment_t iv_align; + unsigned char iv[MAX_BLOCKSIZE]; + } u_iv; + + /* The counter for CTR mode. This field is also used by AESWRAP and + thus we can't use the U_IV union. */ + union { + cipher_context_alignment_t iv_align; + unsigned char ctr[MAX_BLOCKSIZE]; + } u_ctr; + + /* Space to save an IV or CTR for chaining operations. */ + unsigned char lastiv[MAX_BLOCKSIZE]; + int unused; /* Number of unused bytes in LASTIV. */ + + union { +#ifdef HAVE_U64_TYPEDEF + /* Mode specific storage for CCM mode. */ + struct { + u64 encryptlen; + u64 aadlen; + unsigned int authlen; + + /* Space to save partial input lengths for MAC. */ + unsigned char macbuf[GCRY_CCM_BLOCK_LEN]; + int mac_unused; /* Number of unprocessed bytes in MACBUF. */ + + unsigned char s0[GCRY_CCM_BLOCK_LEN]; + + unsigned int nonce:1;/* Set to 1 if nonce has been set. */ + unsigned int lengths:1; /* Set to 1 if CCM length parameters has been + processed. */ + } ccm; +#endif + + /* Mode specific storage for CMAC mode. */ + struct { + unsigned int tag:1; /* Set to 1 if tag has been finalized. */ + + /* Subkeys for tag creation, not cleared by gcry_cipher_reset. */ + unsigned char subkeys[2][MAX_BLOCKSIZE]; + } cmac; + + /* Mode specific storage for GCM mode. */ + struct { + /* The interim tag for GCM mode. */ + union { + cipher_context_alignment_t iv_align; + unsigned char tag[MAX_BLOCKSIZE]; + } u_tag; + + /* Space to save partial input lengths for MAC. */ + unsigned char macbuf[GCRY_CCM_BLOCK_LEN]; + int mac_unused; /* Number of unprocessed bytes in MACBUF. */ + + /* byte counters for GCM */ + u32 aadlen[2]; + u32 datalen[2]; + + /* encrypted tag counter */ + unsigned char tagiv[MAX_BLOCKSIZE]; + + unsigned int ghash_data_finalized:1; + unsigned int ghash_aad_finalized:1; + + unsigned int datalen_over_limits:1; + unsigned int disallow_encryption_because_of_setiv_in_fips_mode:1; + + /* --- Following members are not cleared in gcry_cipher_reset --- */ + + /* GHASH multiplier from key. */ + union { + cipher_context_alignment_t iv_align; + unsigned char key[MAX_BLOCKSIZE]; + } u_ghash_key; + +#ifdef GCM_USE_INTEL_PCLMUL + /* Use Intel PCLMUL instructions for accelerated GHASH. */ + unsigned int use_intel_pclmul:1; +#endif + + /* Pre-calculated table for GCM. */ +#ifdef GCM_USE_TABLES + #if defined(HAVE_U64_TYPEDEF) && (SIZEOF_UNSIGNED_LONG == 8 \ + || defined(__x86_64__)) + #define GCM_TABLES_USE_U64 1 + u64 gcm_table[2 * 16]; + #else + #undef GCM_TABLES_USE_U64 + u32 gcm_table[4 * 16]; + #endif +#endif + } gcm; + } u_mode; + + /* What follows are two contexts of the cipher in use. The first + one needs to be aligned well enough for the cipher operation + whereas the second one is a copy created by cipher_setkey and + used by cipher_reset. That second copy has no need for proper + aligment because it is only accessed by memcpy. */ + cipher_context_alignment_t context; +}; + + +/*-- cipher-cbc.c --*/ +gcry_err_code_t _gcry_cipher_cbc_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_cbc_decrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); + +/*-- cipher-cfb.c --*/ +gcry_err_code_t _gcry_cipher_cfb_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_cfb_decrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); + + +/*-- cipher-ofb.c --*/ +gcry_err_code_t _gcry_cipher_ofb_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); + +/*-- cipher-ctr.c --*/ +gcry_err_code_t _gcry_cipher_ctr_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); + + +/*-- cipher-aeswrap.c --*/ +gcry_err_code_t _gcry_cipher_aeswrap_encrypt +/* */ (gcry_cipher_hd_t c, + byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_aeswrap_decrypt +/* */ (gcry_cipher_hd_t c, + byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen); + + +/*-- cipher-ccm.c --*/ +gcry_err_code_t _gcry_cipher_ccm_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_ccm_decrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_ccm_set_nonce +/* */ (gcry_cipher_hd_t c, const unsigned char *nonce, + size_t noncelen); +gcry_err_code_t _gcry_cipher_ccm_authenticate +/* */ (gcry_cipher_hd_t c, const unsigned char *abuf, size_t abuflen); +#ifdef HAVE_U64_TYPEDEF +gcry_err_code_t _gcry_cipher_ccm_set_lengths +/* */ (gcry_cipher_hd_t c, u64 encryptedlen, u64 aadlen, u64 taglen); +#endif +gcry_err_code_t _gcry_cipher_ccm_get_tag +/* */ (gcry_cipher_hd_t c, + unsigned char *outtag, size_t taglen); +gcry_err_code_t _gcry_cipher_ccm_check_tag +/* */ (gcry_cipher_hd_t c, + const unsigned char *intag, size_t taglen); + + +/*-- cipher-gcm.c --*/ +gcry_err_code_t _gcry_cipher_gcm_encrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_gcm_decrypt +/* */ (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen); +gcry_err_code_t _gcry_cipher_gcm_setiv +/* */ (gcry_cipher_hd_t c, + const unsigned char *iv, size_t ivlen); +gcry_err_code_t _gcry_cipher_gcm_authenticate +/* */ (gcry_cipher_hd_t c, + const unsigned char *aadbuf, size_t aadbuflen); +gcry_err_code_t _gcry_cipher_gcm_get_tag +/* */ (gcry_cipher_hd_t c, + unsigned char *outtag, size_t taglen); +gcry_err_code_t _gcry_cipher_gcm_check_tag +/* */ (gcry_cipher_hd_t c, + const unsigned char *intag, size_t taglen); +void _gcry_cipher_gcm_setkey +/* */ (gcry_cipher_hd_t c); + + +#endif /*G10_CIPHER_INTERNAL_H*/ diff --git a/plugins/MirOTR/Libgcrypt/cipher/cipher-ofb.c b/plugins/MirOTR/Libgcrypt/cipher/cipher-ofb.c new file mode 100644 index 0000000000..3842774f58 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/cipher-ofb.c @@ -0,0 +1,96 @@ +/* cipher-ofb.c - Generic OFB mode implementation + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 + * 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "g10lib.h" +#include "cipher.h" +#include "ath.h" +#include "bufhelp.h" +#include "./cipher-internal.h" + + +gcry_err_code_t +_gcry_cipher_ofb_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) +{ + unsigned char *ivp; + gcry_cipher_encrypt_t enc_fn = c->spec->encrypt; + size_t blocksize = c->spec->blocksize; + unsigned int burn, nburn; + + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + + if ( inbuflen <= c->unused ) + { + /* Short enough to be encoded by the remaining XOR mask. */ + /* XOR the input with the IV */ + ivp = c->u_iv.iv + blocksize - c->unused; + buf_xor(outbuf, ivp, inbuf, inbuflen); + c->unused -= inbuflen; + return 0; + } + + burn = 0; + + if( c->unused ) + { + inbuflen -= c->unused; + ivp = c->u_iv.iv + blocksize - c->unused; + buf_xor(outbuf, ivp, inbuf, c->unused); + outbuf += c->unused; + inbuf += c->unused; + c->unused = 0; + } + + /* Now we can process complete blocks. */ + while ( inbuflen >= blocksize ) + { + /* Encrypt the IV (and save the current one). */ + nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + burn = nburn > burn ? nburn : burn; + buf_xor(outbuf, c->u_iv.iv, inbuf, blocksize); + outbuf += blocksize; + inbuf += blocksize; + inbuflen -= blocksize; + } + if ( inbuflen ) + { /* process the remaining bytes */ + nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); + burn = nburn > burn ? nburn : burn; + c->unused = blocksize; + c->unused -= inbuflen; + buf_xor(outbuf, c->u_iv.iv, inbuf, inbuflen); + outbuf += inbuflen; + inbuf += inbuflen; + inbuflen = 0; + } + + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); + + return 0; +} diff --git a/plugins/MirOTR/Libgcrypt/cipher/cipher-selftest.c b/plugins/MirOTR/Libgcrypt/cipher/cipher-selftest.c new file mode 100644 index 0000000000..bb33d94243 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/cipher-selftest.c @@ -0,0 +1,470 @@ +/* cipher-selftest.c - Helper functions for bulk encryption selftests. + * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#ifdef HAVE_SYSLOG +# include <syslog.h> +#endif /*HAVE_SYSLOG*/ + +#include "types.h" +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" +#include "cipher-selftest.h" + +#ifdef HAVE_STDINT_H +# include <stdint.h> /* uintptr_t */ +#elif defined(HAVE_INTTYPES_H) +# include <inttypes.h> +#else +/* In this case, uintptr_t is provided by config.h. */ +#endif + +/* Helper macro to force alignment to 16 bytes. */ +#ifdef HAVE_GCC_ATTRIBUTE_ALIGNED +# define ATTR_ALIGNED_16 __attribute__ ((aligned (16))) +#else +# define ATTR_ALIGNED_16 +#endif + + +/* Run the self-tests for <block cipher>-CBC-<block size>, tests bulk CBC + decryption. Returns NULL on success. */ +const char * +_gcry_selftest_helper_cbc (const char *cipher, gcry_cipher_setkey_t setkey_func, + gcry_cipher_encrypt_t encrypt_one, + gcry_cipher_bulk_cbc_dec_t bulk_cbc_dec, + const int nblocks, const int blocksize, + const int context_size) +{ + int i, offs; + unsigned char *ctx, *plaintext, *plaintext2, *ciphertext, *iv, *iv2, *mem; + unsigned int ctx_aligned_size, memsize; + + static const unsigned char key[16] ATTR_ALIGNED_16 = { + 0x66,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, + 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x22 + }; + + /* Allocate buffers, align first two elements to 16 bytes and latter to + block size. */ + ctx_aligned_size = context_size + 15; + ctx_aligned_size -= ctx_aligned_size & 0xf; + + memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 3) + 16; + + mem = xtrycalloc (1, memsize); + if (!mem) + return "failed to allocate memory"; + + offs = (16 - ((uintptr_t)mem & 15)) & 15; + ctx = (void*)(mem + offs); + iv = ctx + ctx_aligned_size; + iv2 = iv + blocksize; + plaintext = iv2 + blocksize; + plaintext2 = plaintext + nblocks * blocksize; + ciphertext = plaintext2 + nblocks * blocksize; + + /* Initialize ctx */ + setkey_func (ctx, key, sizeof(key)); + + /* Test single block code path */ + memset (iv, 0x4e, blocksize); + memset (iv2, 0x4e, blocksize); + for (i = 0; i < blocksize; i++) + plaintext[i] = i; + + /* CBC manually. */ + buf_xor (ciphertext, iv, plaintext, blocksize); + encrypt_one (ctx, ciphertext, ciphertext); + memcpy (iv, ciphertext, blocksize); + + /* CBC decrypt. */ + bulk_cbc_dec (ctx, iv2, plaintext2, ciphertext, 1); + if (memcmp (plaintext2, plaintext, blocksize)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CBC-%d test failed (plaintext mismatch)", cipher, + blocksize * 8); +#endif + return "selftest for CBC failed - see syslog for details"; + } + + if (memcmp (iv2, iv, blocksize)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CBC-%d test failed (IV mismatch)", cipher, blocksize * 8); +#endif + return "selftest for CBC failed - see syslog for details"; + } + + /* Test parallelized code paths */ + memset (iv, 0x5f, blocksize); + memset (iv2, 0x5f, blocksize); + + for (i = 0; i < nblocks * blocksize; i++) + plaintext[i] = i; + + /* Create CBC ciphertext manually. */ + for (i = 0; i < nblocks * blocksize; i+=blocksize) + { + buf_xor (&ciphertext[i], iv, &plaintext[i], blocksize); + encrypt_one (ctx, &ciphertext[i], &ciphertext[i]); + memcpy (iv, &ciphertext[i], blocksize); + } + + /* Decrypt using bulk CBC and compare result. */ + bulk_cbc_dec (ctx, iv2, plaintext2, ciphertext, nblocks); + + if (memcmp (plaintext2, plaintext, nblocks * blocksize)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CBC-%d test failed (plaintext mismatch, parallel path)", + cipher, blocksize * 8); +#endif + return "selftest for CBC failed - see syslog for details"; + } + if (memcmp (iv2, iv, blocksize)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CBC-%d test failed (IV mismatch, parallel path)", + cipher, blocksize * 8); +#endif + return "selftest for CBC failed - see syslog for details"; + } + + xfree (mem); + return NULL; +} + +/* Run the self-tests for <block cipher>-CFB-<block size>, tests bulk CFB + decryption. Returns NULL on success. */ +const char * +_gcry_selftest_helper_cfb (const char *cipher, gcry_cipher_setkey_t setkey_func, + gcry_cipher_encrypt_t encrypt_one, + gcry_cipher_bulk_cfb_dec_t bulk_cfb_dec, + const int nblocks, const int blocksize, + const int context_size) +{ + int i, offs; + unsigned char *ctx, *plaintext, *plaintext2, *ciphertext, *iv, *iv2, *mem; + unsigned int ctx_aligned_size, memsize; + + static const unsigned char key[16] ATTR_ALIGNED_16 = { + 0x11,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, + 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x33 + }; + + /* Allocate buffers, align first two elements to 16 bytes and latter to + block size. */ + ctx_aligned_size = context_size + 15; + ctx_aligned_size -= ctx_aligned_size & 0xf; + + memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 3) + 16; + + mem = xtrycalloc (1, memsize); + if (!mem) + return "failed to allocate memory"; + + offs = (16 - ((uintptr_t)mem & 15)) & 15; + ctx = (void*)(mem + offs); + iv = ctx + ctx_aligned_size; + iv2 = iv + blocksize; + plaintext = iv2 + blocksize; + plaintext2 = plaintext + nblocks * blocksize; + ciphertext = plaintext2 + nblocks * blocksize; + + /* Initialize ctx */ + setkey_func (ctx, key, sizeof(key)); + + /* Test single block code path */ + memset(iv, 0xd3, blocksize); + memset(iv2, 0xd3, blocksize); + for (i = 0; i < blocksize; i++) + plaintext[i] = i; + + /* CFB manually. */ + encrypt_one (ctx, ciphertext, iv); + buf_xor_2dst (iv, ciphertext, plaintext, blocksize); + + /* CFB decrypt. */ + bulk_cfb_dec (ctx, iv2, plaintext2, ciphertext, 1); + if (memcmp(plaintext2, plaintext, blocksize)) + { + xfree(mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CFB-%d test failed (plaintext mismatch)", cipher, + blocksize * 8); +#endif + return "selftest for CFB failed - see syslog for details"; + } + + if (memcmp(iv2, iv, blocksize)) + { + xfree(mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CFB-%d test failed (IV mismatch)", cipher, blocksize * 8); +#endif + return "selftest for CFB failed - see syslog for details"; + } + + /* Test parallelized code paths */ + memset(iv, 0xe6, blocksize); + memset(iv2, 0xe6, blocksize); + + for (i = 0; i < nblocks * blocksize; i++) + plaintext[i] = i; + + /* Create CFB ciphertext manually. */ + for (i = 0; i < nblocks * blocksize; i+=blocksize) + { + encrypt_one (ctx, &ciphertext[i], iv); + buf_xor_2dst (iv, &ciphertext[i], &plaintext[i], blocksize); + } + + /* Decrypt using bulk CBC and compare result. */ + bulk_cfb_dec (ctx, iv2, plaintext2, ciphertext, nblocks); + + if (memcmp(plaintext2, plaintext, nblocks * blocksize)) + { + xfree(mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CFB-%d test failed (plaintext mismatch, parallel path)", + cipher, blocksize * 8); +#endif + return "selftest for CFB failed - see syslog for details"; + } + if (memcmp(iv2, iv, blocksize)) + { + xfree(mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CFB-%d test failed (IV mismatch, parallel path)", cipher, + blocksize * 8); +#endif + return "selftest for CFB failed - see syslog for details"; + } + + xfree(mem); + return NULL; +} + +/* Run the self-tests for <block cipher>-CTR-<block size>, tests IV increment + of bulk CTR encryption. Returns NULL on success. */ +const char * +_gcry_selftest_helper_ctr (const char *cipher, gcry_cipher_setkey_t setkey_func, + gcry_cipher_encrypt_t encrypt_one, + gcry_cipher_bulk_ctr_enc_t bulk_ctr_enc, + const int nblocks, const int blocksize, + const int context_size) +{ + int i, j, offs, diff; + unsigned char *ctx, *plaintext, *plaintext2, *ciphertext, *ciphertext2, + *iv, *iv2, *mem; + unsigned int ctx_aligned_size, memsize; + + static const unsigned char key[16] ATTR_ALIGNED_16 = { + 0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, + 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21 + }; + + /* Allocate buffers, align first two elements to 16 bytes and latter to + block size. */ + ctx_aligned_size = context_size + 15; + ctx_aligned_size -= ctx_aligned_size & 0xf; + + memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 4) + 16; + + mem = xtrycalloc (1, memsize); + if (!mem) + return "failed to allocate memory"; + + offs = (16 - ((uintptr_t)mem & 15)) & 15; + ctx = (void*)(mem + offs); + iv = ctx + ctx_aligned_size; + iv2 = iv + blocksize; + plaintext = iv2 + blocksize; + plaintext2 = plaintext + nblocks * blocksize; + ciphertext = plaintext2 + nblocks * blocksize; + ciphertext2 = ciphertext + nblocks * blocksize; + + /* Initialize ctx */ + setkey_func (ctx, key, sizeof(key)); + + /* Test single block code path */ + memset (iv, 0xff, blocksize); + for (i = 0; i < blocksize; i++) + plaintext[i] = i; + + /* CTR manually. */ + encrypt_one (ctx, ciphertext, iv); + for (i = 0; i < blocksize; i++) + ciphertext[i] ^= plaintext[i]; + for (i = blocksize; i > 0; i--) + { + iv[i-1]++; + if (iv[i-1]) + break; + } + + memset (iv2, 0xff, blocksize); + bulk_ctr_enc (ctx, iv2, plaintext2, ciphertext, 1); + + if (memcmp (plaintext2, plaintext, blocksize)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CTR-%d test failed (plaintext mismatch)", cipher, + blocksize * 8); +#endif + return "selftest for CTR failed - see syslog for details"; + } + + if (memcmp (iv2, iv, blocksize)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CTR-%d test failed (IV mismatch)", cipher, + blocksize * 8); +#endif + return "selftest for CTR failed - see syslog for details"; + } + + /* Test bulk encryption with typical IV. */ + memset(iv, 0x57, blocksize-4); + iv[blocksize-1] = 1; + iv[blocksize-2] = 0; + iv[blocksize-3] = 0; + iv[blocksize-4] = 0; + memset(iv2, 0x57, blocksize-4); + iv2[blocksize-1] = 1; + iv2[blocksize-2] = 0; + iv2[blocksize-3] = 0; + iv2[blocksize-4] = 0; + + for (i = 0; i < blocksize * nblocks; i++) + plaintext2[i] = plaintext[i] = i; + + /* Create CTR ciphertext manually. */ + for (i = 0; i < blocksize * nblocks; i+=blocksize) + { + encrypt_one (ctx, &ciphertext[i], iv); + for (j = 0; j < blocksize; j++) + ciphertext[i+j] ^= plaintext[i+j]; + for (j = blocksize; j > 0; j--) + { + iv[j-1]++; + if (iv[j-1]) + break; + } + } + + bulk_ctr_enc (ctx, iv2, ciphertext2, plaintext2, nblocks); + + if (memcmp (ciphertext2, ciphertext, blocksize * nblocks)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CTR-%d test failed (ciphertext mismatch, bulk)", cipher, + blocksize * 8); +#endif + return "selftest for CTR failed - see syslog for details"; + } + if (memcmp(iv2, iv, blocksize)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CTR-%d test failed (IV mismatch, bulk)", cipher, + blocksize * 8); +#endif + return "selftest for CTR failed - see syslog for details"; + } + + /* Test parallelized code paths (check counter overflow handling) */ + for (diff = 0; diff < nblocks; diff++) { + memset(iv, 0xff, blocksize); + iv[blocksize-1] -= diff; + iv[0] = iv[1] = 0; + iv[2] = 0x07; + + for (i = 0; i < blocksize * nblocks; i++) + plaintext[i] = i; + + /* Create CTR ciphertext manually. */ + for (i = 0; i < blocksize * nblocks; i+=blocksize) + { + encrypt_one (ctx, &ciphertext[i], iv); + for (j = 0; j < blocksize; j++) + ciphertext[i+j] ^= plaintext[i+j]; + for (j = blocksize; j > 0; j--) + { + iv[j-1]++; + if (iv[j-1]) + break; + } + } + + /* Decrypt using bulk CTR and compare result. */ + memset(iv2, 0xff, blocksize); + iv2[blocksize-1] -= diff; + iv2[0] = iv2[1] = 0; + iv2[2] = 0x07; + + bulk_ctr_enc (ctx, iv2, plaintext2, ciphertext, nblocks); + + if (memcmp (plaintext2, plaintext, blocksize * nblocks)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CTR-%d test failed (plaintext mismatch, diff: %d)", cipher, + blocksize * 8, diff); +#endif + return "selftest for CTR failed - see syslog for details"; + } + if (memcmp(iv2, iv, blocksize)) + { + xfree (mem); +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "%s-CTR-%d test failed (IV mismatch, diff: %d)", cipher, + blocksize * 8, diff); +#endif + return "selftest for CTR failed - see syslog for details"; + } + } + + xfree (mem); + return NULL; +} diff --git a/plugins/MirOTR/Libgcrypt/cipher/cipher-selftest.h b/plugins/MirOTR/Libgcrypt/cipher/cipher-selftest.h new file mode 100644 index 0000000000..3a0fe98f60 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/cipher-selftest.h @@ -0,0 +1,67 @@ +/* cipher-selftest.h - Helper functions for bulk encryption selftests. + * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef G10_SELFTEST_HELP_H +#define G10_SELFTEST_HELP_H + +#include <config.h> +#include "types.h" +#include "g10lib.h" +#include "cipher.h" + +typedef void (*gcry_cipher_bulk_cbc_dec_t)(void *context, unsigned char *iv, + void *outbuf_arg, + const void *inbuf_arg, + size_t nblocks); + +typedef void (*gcry_cipher_bulk_cfb_dec_t)(void *context, unsigned char *iv, + void *outbuf_arg, + const void *inbuf_arg, + size_t nblocks); + +typedef void (*gcry_cipher_bulk_ctr_enc_t)(void *context, unsigned char *iv, + void *outbuf_arg, + const void *inbuf_arg, + size_t nblocks); + +/* Helper function for bulk CBC decryption selftest */ +const char * +_gcry_selftest_helper_cbc (const char *cipher, gcry_cipher_setkey_t setkey, + gcry_cipher_encrypt_t encrypt_one, + gcry_cipher_bulk_cbc_dec_t bulk_cbc_dec, + const int nblocks, const int blocksize, + const int context_size); + +/* Helper function for bulk CFB decryption selftest */ +const char * +_gcry_selftest_helper_cfb (const char *cipher, gcry_cipher_setkey_t setkey, + gcry_cipher_encrypt_t encrypt_one, + gcry_cipher_bulk_cfb_dec_t bulk_cfb_dec, + const int nblocks, const int blocksize, + const int context_size); + +/* Helper function for bulk CTR encryption selftest */ +const char * +_gcry_selftest_helper_ctr (const char *cipher, gcry_cipher_setkey_t setkey, + gcry_cipher_encrypt_t encrypt_one, + gcry_cipher_bulk_ctr_enc_t bulk_ctr_enc, + const int nblocks, const int blocksize, + const int context_size); + +#endif /*G10_SELFTEST_HELP_H*/ diff --git a/plugins/MirOTR/Libgcrypt/cipher/cipher.c b/plugins/MirOTR/Libgcrypt/cipher/cipher.c index f692159e2e..8c5a0b4ed8 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/cipher.c +++ b/plugins/MirOTR/Libgcrypt/cipher/cipher.c @@ -1,6 +1,7 @@ /* cipher.c - cipher dispatcher * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 - * 2005, 2007, 2008, 2010 Free Software Foundation, Inc. + * 2005, 2007, 2008, 2009, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH * * This file is part of Libgcrypt. * @@ -27,465 +28,195 @@ #include "g10lib.h" #include "cipher.h" #include "ath.h" +#include "./cipher-internal.h" -#define MAX_BLOCKSIZE 16 -#define TABLE_SIZE 14 -#define CTX_MAGIC_NORMAL 0x24091964 -#define CTX_MAGIC_SECURE 0x46919042 - -#undef NEED_16BYTE_ALIGNED_CONTEXT -#if defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4 && defined (__GNUC__) -#define NEED_16BYTE_ALIGNED_CONTEXT 1 -#endif - -/* A dummy extraspec so that we do not need to tests the extraspec - field from the module specification against NULL and instead - directly test the respective fields of extraspecs. */ -static cipher_extra_spec_t dummy_extra_spec; /* This is the list of the default ciphers, which are included in libgcrypt. */ -static struct cipher_table_entry -{ - gcry_cipher_spec_t *cipher; - cipher_extra_spec_t *extraspec; - unsigned int algorithm; - int fips_allowed; -} cipher_table[] = +static gcry_cipher_spec_t *cipher_list[] = { #if USE_BLOWFISH - { &_gcry_cipher_spec_blowfish, - &dummy_extra_spec, GCRY_CIPHER_BLOWFISH }, + &_gcry_cipher_spec_blowfish, #endif #if USE_DES - { &_gcry_cipher_spec_des, - &dummy_extra_spec, GCRY_CIPHER_DES }, - { &_gcry_cipher_spec_tripledes, - &_gcry_cipher_extraspec_tripledes, GCRY_CIPHER_3DES, 1 }, + &_gcry_cipher_spec_des, + &_gcry_cipher_spec_tripledes, #endif #if USE_ARCFOUR - { &_gcry_cipher_spec_arcfour, - &dummy_extra_spec, GCRY_CIPHER_ARCFOUR }, + &_gcry_cipher_spec_arcfour, #endif #if USE_CAST5 - { &_gcry_cipher_spec_cast5, - &dummy_extra_spec, GCRY_CIPHER_CAST5 }, + &_gcry_cipher_spec_cast5, #endif #if USE_AES - { &_gcry_cipher_spec_aes, - &_gcry_cipher_extraspec_aes, GCRY_CIPHER_AES, 1 }, - { &_gcry_cipher_spec_aes192, - &_gcry_cipher_extraspec_aes192, GCRY_CIPHER_AES192, 1 }, - { &_gcry_cipher_spec_aes256, - &_gcry_cipher_extraspec_aes256, GCRY_CIPHER_AES256, 1 }, + &_gcry_cipher_spec_aes, + &_gcry_cipher_spec_aes192, + &_gcry_cipher_spec_aes256, #endif #if USE_TWOFISH - { &_gcry_cipher_spec_twofish, - &dummy_extra_spec, GCRY_CIPHER_TWOFISH }, - { &_gcry_cipher_spec_twofish128, - &dummy_extra_spec, GCRY_CIPHER_TWOFISH128 }, + &_gcry_cipher_spec_twofish, + &_gcry_cipher_spec_twofish128, #endif #if USE_SERPENT - { &_gcry_cipher_spec_serpent128, - &dummy_extra_spec, GCRY_CIPHER_SERPENT128 }, - { &_gcry_cipher_spec_serpent192, - &dummy_extra_spec, GCRY_CIPHER_SERPENT192 }, - { &_gcry_cipher_spec_serpent256, - &dummy_extra_spec, GCRY_CIPHER_SERPENT256 }, + &_gcry_cipher_spec_serpent128, + &_gcry_cipher_spec_serpent192, + &_gcry_cipher_spec_serpent256, #endif #if USE_RFC2268 - { &_gcry_cipher_spec_rfc2268_40, - &dummy_extra_spec, GCRY_CIPHER_RFC2268_40 }, + &_gcry_cipher_spec_rfc2268_40, + &_gcry_cipher_spec_rfc2268_128, #endif #if USE_SEED - { &_gcry_cipher_spec_seed, - &dummy_extra_spec, GCRY_CIPHER_SEED }, + &_gcry_cipher_spec_seed, #endif #if USE_CAMELLIA - { &_gcry_cipher_spec_camellia128, - &dummy_extra_spec, GCRY_CIPHER_CAMELLIA128 }, - { &_gcry_cipher_spec_camellia192, - &dummy_extra_spec, GCRY_CIPHER_CAMELLIA192 }, - { &_gcry_cipher_spec_camellia256, - &dummy_extra_spec, GCRY_CIPHER_CAMELLIA256 }, + &_gcry_cipher_spec_camellia128, + &_gcry_cipher_spec_camellia192, + &_gcry_cipher_spec_camellia256, +#endif +#ifdef USE_IDEA + &_gcry_cipher_spec_idea, #endif - { NULL } +#if USE_SALSA20 + &_gcry_cipher_spec_salsa20, + &_gcry_cipher_spec_salsa20r12, +#endif +#if USE_GOST28147 + &_gcry_cipher_spec_gost28147, +#endif + NULL }; -/* List of registered ciphers. */ -static gcry_module_t ciphers_registered; - -/* This is the lock protecting CIPHERS_REGISTERED. */ -static ath_mutex_t ciphers_registered_lock = ATH_MUTEX_INITIALIZER; - -/* Flag to check wether the default ciphers have already been - registered. */ -static int default_ciphers_registered; - -/* Convenient macro for registering the default ciphers. */ -#define REGISTER_DEFAULT_CIPHERS \ - do \ - { \ - ath_mutex_lock (&ciphers_registered_lock); \ - if (! default_ciphers_registered) \ - { \ - cipher_register_default (); \ - default_ciphers_registered = 1; \ - } \ - ath_mutex_unlock (&ciphers_registered_lock); \ - } \ - while (0) - - -/* A VIA processor with the Padlock engine requires an alignment of - most data on a 16 byte boundary. Because we trick out the compiler - while allocating the context, the align attribute as used in - rijndael.c does not work on its own. Thus we need to make sure - that the entire context structure is a aligned on that boundary. - We achieve this by defining a new type and use that instead of our - usual alignment type. */ -typedef union -{ - PROPERLY_ALIGNED_TYPE foo; -#ifdef NEED_16BYTE_ALIGNED_CONTEXT - char bar[16] __attribute__ ((aligned (16))); -#endif - char c[1]; -} cipher_context_alignment_t; - - -/* The handle structure. */ -struct gcry_cipher_handle -{ - int magic; - size_t actual_handle_size; /* Allocated size of this handle. */ - size_t handle_offset; /* Offset to the malloced block. */ - gcry_cipher_spec_t *cipher; - cipher_extra_spec_t *extraspec; - gcry_module_t module; - - /* The algorithm id. This is a hack required because the module - interface does not easily allow to retrieve this value. */ - int algo; - - /* A structure with function pointers for bulk operations. Due to - limitations of the module system (we don't want to change the - API) we need to keep these function pointers here. The cipher - open function intializes them and the actual encryption routines - use them if they are not NULL. */ - struct { - void (*cfb_enc)(void *context, unsigned char *iv, - void *outbuf_arg, const void *inbuf_arg, - unsigned int nblocks); - void (*cfb_dec)(void *context, unsigned char *iv, - void *outbuf_arg, const void *inbuf_arg, - unsigned int nblocks); - void (*cbc_enc)(void *context, unsigned char *iv, - void *outbuf_arg, const void *inbuf_arg, - unsigned int nblocks, int cbc_mac); - void (*cbc_dec)(void *context, unsigned char *iv, - void *outbuf_arg, const void *inbuf_arg, - unsigned int nblocks); - } bulk; - - - int mode; - unsigned int flags; - - struct { - unsigned int key:1; /* Set to 1 if a key has been set. */ - unsigned int iv:1; /* Set to 1 if a IV has been set. */ - } marks; - - /* The initialization vector. To help code optimization we make - sure that it is aligned on an unsigned long and u32 boundary. */ - union { - unsigned long dummy_iv; - u32 dummy_u32_iv; - unsigned char iv[MAX_BLOCKSIZE]; - } u_iv; - - unsigned char lastiv[MAX_BLOCKSIZE]; - int unused; /* Number of unused bytes in the IV. */ - - unsigned char ctr[MAX_BLOCKSIZE]; /* For Counter (CTR) mode. */ - - - /* What follows are two contexts of the cipher in use. The first - one needs to be aligned well enough for the cipher operation - whereas the second one is a copy created by cipher_setkey and - used by cipher_reset. That second copy has no need for proper - aligment because it is only accessed by memcpy. */ - cipher_context_alignment_t context; -}; -/* These dummy functions are used in case a cipher implementation - refuses to provide it's own functions. */ - -static gcry_err_code_t -dummy_setkey (void *c, const unsigned char *key, unsigned int keylen) +static int +map_algo (int algo) { - (void)c; - (void)key; - (void)keylen; - return GPG_ERR_NO_ERROR; + return algo; } -static void -dummy_encrypt_block (void *c, - unsigned char *outbuf, const unsigned char *inbuf) -{ - (void)c; - (void)outbuf; - (void)inbuf; - BUG(); -} -static void -dummy_decrypt_block (void *c, - unsigned char *outbuf, const unsigned char *inbuf) +/* Return the spec structure for the cipher algorithm ALGO. For + an unknown algorithm NULL is returned. */ +static gcry_cipher_spec_t * +spec_from_algo (int algo) { - (void)c; - (void)outbuf; - (void)inbuf; - BUG(); -} + int idx; + gcry_cipher_spec_t *spec; -static void -dummy_encrypt_stream (void *c, - unsigned char *outbuf, const unsigned char *inbuf, - unsigned int n) -{ - (void)c; - (void)outbuf; - (void)inbuf; - (void)n; - BUG(); -} + algo = map_algo (algo); -static void -dummy_decrypt_stream (void *c, - unsigned char *outbuf, const unsigned char *inbuf, - unsigned int n) -{ - (void)c; - (void)outbuf; - (void)inbuf; - (void)n; - BUG(); + for (idx = 0; (spec = cipher_list[idx]); idx++) + if (algo == spec->algo) + return spec; + return NULL; } - -/* Internal function. Register all the ciphers included in - CIPHER_TABLE. Note, that this function gets only used by the macro - REGISTER_DEFAULT_CIPHERS which protects it using a mutex. */ -static void -cipher_register_default (void) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - int i; - - for (i = 0; !err && cipher_table[i].cipher; i++) - { - if (! cipher_table[i].cipher->setkey) - cipher_table[i].cipher->setkey = dummy_setkey; - if (! cipher_table[i].cipher->encrypt) - cipher_table[i].cipher->encrypt = dummy_encrypt_block; - if (! cipher_table[i].cipher->decrypt) - cipher_table[i].cipher->decrypt = dummy_decrypt_block; - if (! cipher_table[i].cipher->stencrypt) - cipher_table[i].cipher->stencrypt = dummy_encrypt_stream; - if (! cipher_table[i].cipher->stdecrypt) - cipher_table[i].cipher->stdecrypt = dummy_decrypt_stream; - - if ( fips_mode () && !cipher_table[i].fips_allowed ) - continue; - - err = _gcry_module_add (&ciphers_registered, - cipher_table[i].algorithm, - (void *) cipher_table[i].cipher, - (void *) cipher_table[i].extraspec, - NULL); - } - - if (err) - BUG (); -} -/* Internal callback function. Used via _gcry_module_lookup. */ -static int -gcry_cipher_lookup_func_name (void *spec, void *data) +/* Lookup a cipher's spec by its name. */ +static gcry_cipher_spec_t * +spec_from_name (const char *name) { - gcry_cipher_spec_t *cipher = (gcry_cipher_spec_t *) spec; - char *name = (char *) data; - const char **aliases = cipher->aliases; - int i, ret = !_stricmp (name, cipher->name); + gcry_cipher_spec_t *spec; + int idx; + const char **aliases; - if (aliases) - for (i = 0; aliases[i] && (! ret); i++) - ret = !_stricmp (name, aliases[i]); - - return ret; -} - -/* Internal callback function. Used via _gcry_module_lookup. */ -static int -gcry_cipher_lookup_func_oid (void *spec, void *data) -{ - gcry_cipher_spec_t *cipher = (gcry_cipher_spec_t *) spec; - char *oid = (char *) data; - gcry_cipher_oid_spec_t *oid_specs = cipher->oids; - int ret = 0, i; - - if (oid_specs) - for (i = 0; oid_specs[i].oid && (! ret); i++) - if (!_stricmp (oid, oid_specs[i].oid)) - ret = 1; + for (idx=0; (spec = cipher_list[idx]); idx++) + { + if (!stricmp (name, spec->name)) + return spec; + if (spec->aliases) + { + for (aliases = spec->aliases; *aliases; aliases++) + if (!stricmp (name, *aliases)) + return spec; + } + } - return ret; + return NULL; } -/* Internal function. Lookup a cipher entry by it's name. */ -static gcry_module_t -gcry_cipher_lookup_name (const char *name) -{ - gcry_module_t cipher; - - cipher = _gcry_module_lookup (ciphers_registered, (void *) name, - gcry_cipher_lookup_func_name); - - return cipher; -} -/* Internal function. Lookup a cipher entry by it's oid. */ -static gcry_module_t -gcry_cipher_lookup_oid (const char *oid) +/* Lookup a cipher's spec by its OID. */ +static gcry_cipher_spec_t * +spec_from_oid (const char *oid) { - gcry_module_t cipher; - - cipher = _gcry_module_lookup (ciphers_registered, (void *) oid, - gcry_cipher_lookup_func_oid); - - return cipher; -} + gcry_cipher_spec_t *spec; + gcry_cipher_oid_spec_t *oid_specs; + int idx, j; -/* Register a new cipher module whose specification can be found in - CIPHER. On success, a new algorithm ID is stored in ALGORITHM_ID - and a pointer representhing this module is stored in MODULE. */ -gcry_error_t -_gcry_cipher_register (gcry_cipher_spec_t *cipher, - cipher_extra_spec_t *extraspec, - int *algorithm_id, - gcry_module_t *module) -{ - gcry_err_code_t err = 0; - gcry_module_t mod; - - /* We do not support module loading in fips mode. */ - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - ath_mutex_lock (&ciphers_registered_lock); - err = _gcry_module_add (&ciphers_registered, 0, - (void *)cipher, - (void *)(extraspec? extraspec : &dummy_extra_spec), - &mod); - ath_mutex_unlock (&ciphers_registered_lock); - - if (! err) + for (idx=0; (spec = cipher_list[idx]); idx++) { - *module = mod; - *algorithm_id = mod->mod_id; + oid_specs = spec->oids; + if (oid_specs) + { + for (j = 0; oid_specs[j].oid; j++) + if (!stricmp (oid, oid_specs[j].oid)) + return spec; + } } - return gcry_error (err); + return NULL; } -/* Unregister the cipher identified by MODULE, which must have been - registered with gcry_cipher_register. */ -void -gcry_cipher_unregister (gcry_module_t module) -{ - ath_mutex_lock (&ciphers_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&ciphers_registered_lock); -} -/* Locate the OID in the oid table and return the index or -1 when not - found. An opitonal "oid." or "OID." prefix in OID is ignored, the - OID is expected to be in standard IETF dotted notation. The - internal algorithm number is returned in ALGORITHM unless it - ispassed as NULL. A pointer to the specification of the module - implementing this algorithm is return in OID_SPEC unless passed as - NULL.*/ -static int -search_oid (const char *oid, int *algorithm, gcry_cipher_oid_spec_t *oid_spec) +/* Locate the OID in the oid table and return the spec or NULL if not + found. An optional "oid." or "OID." prefix in OID is ignored, the + OID is expected to be in standard IETF dotted notation. A pointer + to the OID specification of the module implementing this algorithm + is return in OID_SPEC unless passed as NULL.*/ +static gcry_cipher_spec_t * +search_oid (const char *oid, gcry_cipher_oid_spec_t *oid_spec) { - gcry_module_t module; - int ret = 0; + gcry_cipher_spec_t *spec; + int i; if (oid && ((! strncmp (oid, "oid.", 4)) || (! strncmp (oid, "OID.", 4)))) oid += 4; - module = gcry_cipher_lookup_oid (oid); - if (module) + spec = spec_from_oid (oid); + if (spec && spec->oids) { - gcry_cipher_spec_t *cipher = module->spec; - int i; - - for (i = 0; cipher->oids[i].oid && !ret; i++) - if (!_stricmp (oid, cipher->oids[i].oid)) + for (i = 0; spec->oids[i].oid; i++) + if (!stricmp (oid, spec->oids[i].oid)) { - if (algorithm) - *algorithm = module->mod_id; if (oid_spec) - *oid_spec = cipher->oids[i]; - ret = 1; + *oid_spec = spec->oids[i]; + return spec; } - _gcry_module_release (module); } - return ret; + return NULL; } + /* Map STRING to the cipher algorithm identifier. Returns the algorithm ID of the cipher for the given name or 0 if the name is not known. It is valid to pass NULL for STRING which results in a return value of 0. */ int -gcry_cipher_map_name (const char *string) +_gcry_cipher_map_name (const char *string) { - gcry_module_t cipher; - int ret, algorithm = 0; + gcry_cipher_spec_t *spec; - if (! string) + if (!string) return 0; - REGISTER_DEFAULT_CIPHERS; - /* If the string starts with a digit (optionally prefixed with either "OID." or "oid."), we first look into our table of ASN.1 object identifiers to figure out the algorithm */ - ath_mutex_lock (&ciphers_registered_lock); + spec = search_oid (string, NULL); + if (spec) + return spec->algo; - ret = search_oid (string, &algorithm, NULL); - if (! ret) - { - cipher = gcry_cipher_lookup_name (string); - if (cipher) - { - algorithm = cipher->mod_id; - _gcry_module_release (cipher); - } - } + spec = spec_from_name (string); + if (spec) + return spec->algo; - ath_mutex_unlock (&ciphers_registered_lock); - - return algorithm; + return 0; } @@ -494,80 +225,48 @@ gcry_cipher_map_name (const char *string) with that OID or 0 if no mode is known. Passing NULL for string yields a return value of 0. */ int -gcry_cipher_mode_from_oid (const char *string) +_gcry_cipher_mode_from_oid (const char *string) { + gcry_cipher_spec_t *spec; gcry_cipher_oid_spec_t oid_spec; - int ret = 0, mode = 0; if (!string) return 0; - ath_mutex_lock (&ciphers_registered_lock); - ret = search_oid (string, NULL, &oid_spec); - if (ret) - mode = oid_spec.mode; - ath_mutex_unlock (&ciphers_registered_lock); + spec = search_oid (string, &oid_spec); + if (spec) + return oid_spec.mode; - return mode; + return 0; } -/* Map the cipher algorithm whose ID is contained in ALGORITHM to a - string representation of the algorithm name. For unknown algorithm - IDs this function returns "?". */ -static const char * -cipher_algo_to_string (int algorithm) -{ - gcry_module_t cipher; - const char *name; - - REGISTER_DEFAULT_CIPHERS; - - ath_mutex_lock (&ciphers_registered_lock); - cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); - if (cipher) - { - name = ((gcry_cipher_spec_t *) cipher->spec)->name; - _gcry_module_release (cipher); - } - else - name = "?"; - ath_mutex_unlock (&ciphers_registered_lock); - - return name; -} - /* Map the cipher algorithm identifier ALGORITHM to a string representing this algorithm. This string is the default name as - used by Libgcrypt. An pointer to an empty string is returned for - an unknown algorithm. NULL is never returned. */ + used by Libgcrypt. A "?" is returned for an unknown algorithm. + NULL is never returned. */ const char * -gcry_cipher_algo_name (int algorithm) +_gcry_cipher_algo_name (int algorithm) { - return cipher_algo_to_string (algorithm); + gcry_cipher_spec_t *spec; + + spec = spec_from_algo (algorithm); + return spec? spec->name : "?"; } /* Flag the cipher algorithm with the identifier ALGORITHM as disabled. There is no error return, the function does nothing for - unknown algorithms. Disabled algorithms are vitually not available - in Libgcrypt. */ + unknown algorithms. Disabled algorithms are virtually not + available in Libgcrypt. This is not thread safe and should thus be + called early. */ static void -disable_cipher_algo (int algorithm) +disable_cipher_algo (int algo) { - gcry_module_t cipher; - - REGISTER_DEFAULT_CIPHERS; + gcry_cipher_spec_t *spec = spec_from_algo (algo); - ath_mutex_lock (&ciphers_registered_lock); - cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); - if (cipher) - { - if (! (cipher->flags & FLAG_MODULE_DISABLED)) - cipher->flags |= FLAG_MODULE_DISABLED; - _gcry_module_release (cipher); - } - ath_mutex_unlock (&ciphers_registered_lock); + if (spec) + spec->flags.disabled = 1; } @@ -577,79 +276,51 @@ disable_cipher_algo (int algorithm) static gcry_err_code_t check_cipher_algo (int algorithm) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_module_t cipher; + gcry_cipher_spec_t *spec; - REGISTER_DEFAULT_CIPHERS; + spec = spec_from_algo (algorithm); + if (spec && !spec->flags.disabled) + return 0; - ath_mutex_lock (&ciphers_registered_lock); - cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); - if (cipher) - { - if (cipher->flags & FLAG_MODULE_DISABLED) - err = GPG_ERR_CIPHER_ALGO; - _gcry_module_release (cipher); - } - else - err = GPG_ERR_CIPHER_ALGO; - ath_mutex_unlock (&ciphers_registered_lock); - - return err; + return GPG_ERR_CIPHER_ALGO; } -/* Return the standard length of the key for the cipher algorithm with - the identifier ALGORITHM. This function expects a valid algorithm - and will abort if the algorithm is not available or the length of - the key is not known. */ +/* Return the standard length in bits of the key for the cipher + algorithm with the identifier ALGORITHM. */ static unsigned int cipher_get_keylen (int algorithm) { - gcry_module_t cipher; + gcry_cipher_spec_t *spec; unsigned len = 0; - REGISTER_DEFAULT_CIPHERS; - - ath_mutex_lock (&ciphers_registered_lock); - cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); - if (cipher) + spec = spec_from_algo (algorithm); + if (spec) { - len = ((gcry_cipher_spec_t *) cipher->spec)->keylen; + len = spec->keylen; if (!len) log_bug ("cipher %d w/o key length\n", algorithm); - _gcry_module_release (cipher); } - else - log_bug ("cipher %d not found\n", algorithm); - ath_mutex_unlock (&ciphers_registered_lock); return len; } + /* Return the block length of the cipher algorithm with the identifier - ALGORITHM. This function expects a valid algorithm and will abort - if the algorithm is not available or the length of the key is not - known. */ + ALGORITHM. This function return 0 for an invalid algorithm. */ static unsigned int cipher_get_blocksize (int algorithm) { - gcry_module_t cipher; + gcry_cipher_spec_t *spec; unsigned len = 0; - REGISTER_DEFAULT_CIPHERS; - - ath_mutex_lock (&ciphers_registered_lock); - cipher = _gcry_module_lookup_id (ciphers_registered, algorithm); - if (cipher) + spec = spec_from_algo (algorithm); + if (spec) { - len = ((gcry_cipher_spec_t *) cipher->spec)->blocksize; - if (! len) - log_bug ("cipher %d w/o blocksize\n", algorithm); - _gcry_module_release (cipher); + len = spec->blocksize; + if (!len) + log_bug ("cipher %d w/o blocksize\n", algorithm); } - else - log_bug ("cipher %d not found\n", algorithm); - ath_mutex_unlock (&ciphers_registered_lock); return len; } @@ -669,50 +340,48 @@ cipher_get_blocksize (int algorithm) Values for these flags may be combined using OR. */ -gcry_error_t -gcry_cipher_open (gcry_cipher_hd_t *handle, - int algo, int mode, unsigned int flags) +gcry_err_code_t +_gcry_cipher_open (gcry_cipher_hd_t *handle, + int algo, int mode, unsigned int flags) +{ + gcry_err_code_t rc; + gcry_cipher_hd_t h = NULL; + + if (mode >= GCRY_CIPHER_MODE_INTERNAL) + rc = GPG_ERR_INV_CIPHER_MODE; + else + rc = _gcry_cipher_open_internal (&h, algo, mode, flags); + + *handle = rc ? NULL : h; + + return rc; +} + + +gcry_err_code_t +_gcry_cipher_open_internal (gcry_cipher_hd_t *handle, + int algo, int mode, unsigned int flags) { int secure = (flags & GCRY_CIPHER_SECURE); - gcry_cipher_spec_t *cipher = NULL; - cipher_extra_spec_t *extraspec = NULL; - gcry_module_t module = NULL; + gcry_cipher_spec_t *spec; gcry_cipher_hd_t h = NULL; - gcry_err_code_t err = 0; + gcry_err_code_t err; /* If the application missed to call the random poll function, we do it here to ensure that it is used once in a while. */ _gcry_fast_random_poll (); - - REGISTER_DEFAULT_CIPHERS; - - /* Fetch the according module and check wether the cipher is marked - available for use. */ - ath_mutex_lock (&ciphers_registered_lock); - module = _gcry_module_lookup_id (ciphers_registered, algo); - if (module) - { - /* Found module. */ - if (module->flags & FLAG_MODULE_DISABLED) - { - /* Not available for use. */ - err = GPG_ERR_CIPHER_ALGO; - _gcry_module_release (module); - } - else - { - cipher = (gcry_cipher_spec_t *) module->spec; - extraspec = module->extraspec; - } - } - else + spec = spec_from_algo (algo); + if (!spec) + err = GPG_ERR_CIPHER_ALGO; + else if (spec->flags.disabled) err = GPG_ERR_CIPHER_ALGO; - ath_mutex_unlock (&ciphers_registered_lock); + else + err = 0; /* check flags */ if ((! err) - && ((flags & ~(0 + && ((flags & ~(0 | GCRY_CIPHER_SECURE | GCRY_CIPHER_ENABLE_SYNC | GCRY_CIPHER_CBC_CTS @@ -724,20 +393,31 @@ gcry_cipher_open (gcry_cipher_hd_t *handle, if (! err) switch (mode) { + case GCRY_CIPHER_MODE_CCM: +#ifdef HAVE_U64_TYPEDEF + if (spec->blocksize != GCRY_CCM_BLOCK_LEN) + err = GPG_ERR_INV_CIPHER_MODE; + if (!spec->encrypt || !spec->decrypt) + err = GPG_ERR_INV_CIPHER_MODE; + break; +#else + err = GPG_ERR_NOT_SUPPORTED; +#endif + case GCRY_CIPHER_MODE_ECB: case GCRY_CIPHER_MODE_CBC: case GCRY_CIPHER_MODE_CFB: case GCRY_CIPHER_MODE_OFB: case GCRY_CIPHER_MODE_CTR: case GCRY_CIPHER_MODE_AESWRAP: - if ((cipher->encrypt == dummy_encrypt_block) - || (cipher->decrypt == dummy_decrypt_block)) + case GCRY_CIPHER_MODE_CMAC: + case GCRY_CIPHER_MODE_GCM: + if (!spec->encrypt || !spec->decrypt) err = GPG_ERR_INV_CIPHER_MODE; break; case GCRY_CIPHER_MODE_STREAM: - if ((cipher->stencrypt == dummy_encrypt_stream) - || (cipher->stdecrypt == dummy_decrypt_stream)) + if (!spec->stencrypt || !spec->stdecrypt) err = GPG_ERR_INV_CIPHER_MODE; break; @@ -756,13 +436,12 @@ gcry_cipher_open (gcry_cipher_hd_t *handle, /* Perform selftest here and mark this with a flag in cipher_table? No, we should not do this as it takes too long. Further it does not make sense to exclude algorithms with failing selftests at - runtime: If a selftest fails there is something seriously wrong - with the system and thus we better die immediately. */ + runtime: If a selftest fails there is something seriously wrong with the system and thus we better die immediately. */ if (! err) { size_t size = (sizeof (*h) - + 2 * cipher->contextsize + + 2 * spec->contextsize - sizeof (cipher_context_alignment_t) #ifdef NEED_16BYTE_ALIGNED_CONTEXT + 15 /* Space for leading alignment gap. */ @@ -770,12 +449,12 @@ gcry_cipher_open (gcry_cipher_hd_t *handle, ); if (secure) - h = gcry_calloc_secure (1, size); + h = xtrycalloc_secure (1, size); else - h = gcry_calloc (1, size); + h = xtrycalloc (1, size); if (! h) - err = gpg_err_code_from_errno (errno); + err = gpg_err_code_from_syserror (); else { size_t off = 0; @@ -793,9 +472,7 @@ gcry_cipher_open (gcry_cipher_hd_t *handle, h->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL; h->actual_handle_size = size - off; h->handle_offset = off; - h->cipher = cipher; - h->extraspec = extraspec; - h->module = module; + h->spec = spec; h->algo = algo; h->mode = mode; h->flags = flags; @@ -811,9 +488,50 @@ gcry_cipher_open (gcry_cipher_hd_t *handle, h->bulk.cfb_dec = _gcry_aes_cfb_dec; h->bulk.cbc_enc = _gcry_aes_cbc_enc; h->bulk.cbc_dec = _gcry_aes_cbc_dec; + h->bulk.ctr_enc = _gcry_aes_ctr_enc; break; #endif /*USE_AES*/ - +#ifdef USE_BLOWFISH + case GCRY_CIPHER_BLOWFISH: + h->bulk.cfb_dec = _gcry_blowfish_cfb_dec; + h->bulk.cbc_dec = _gcry_blowfish_cbc_dec; + h->bulk.ctr_enc = _gcry_blowfish_ctr_enc; + break; +#endif /*USE_BLOWFISH*/ +#ifdef USE_CAST5 + case GCRY_CIPHER_CAST5: + h->bulk.cfb_dec = _gcry_cast5_cfb_dec; + h->bulk.cbc_dec = _gcry_cast5_cbc_dec; + h->bulk.ctr_enc = _gcry_cast5_ctr_enc; + break; +#endif /*USE_CAMELLIA*/ +#ifdef USE_CAMELLIA + case GCRY_CIPHER_CAMELLIA128: + case GCRY_CIPHER_CAMELLIA192: + case GCRY_CIPHER_CAMELLIA256: + h->bulk.cbc_dec = _gcry_camellia_cbc_dec; + h->bulk.cfb_dec = _gcry_camellia_cfb_dec; + h->bulk.ctr_enc = _gcry_camellia_ctr_enc; + break; +#endif /*USE_CAMELLIA*/ +#ifdef USE_SERPENT + case GCRY_CIPHER_SERPENT128: + case GCRY_CIPHER_SERPENT192: + case GCRY_CIPHER_SERPENT256: + h->bulk.cbc_dec = _gcry_serpent_cbc_dec; + h->bulk.cfb_dec = _gcry_serpent_cfb_dec; + h->bulk.ctr_enc = _gcry_serpent_ctr_enc; + break; +#endif /*USE_SERPENT*/ +#ifdef USE_TWOFISH + case GCRY_CIPHER_TWOFISH: + case GCRY_CIPHER_TWOFISH128: + h->bulk.cbc_dec = _gcry_twofish_cbc_dec; + h->bulk.cfb_dec = _gcry_twofish_cfb_dec; + h->bulk.ctr_enc = _gcry_twofish_ctr_enc; + break; +#endif /*USE_TWOFISH*/ + default: break; } @@ -822,17 +540,6 @@ gcry_cipher_open (gcry_cipher_hd_t *handle, /* Done. */ - if (err) - { - if (module) - { - /* Release module. */ - ath_mutex_lock (&ciphers_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&ciphers_registered_lock); - } - } - *handle = err ? NULL : h; return gcry_error (err); @@ -842,7 +549,7 @@ gcry_cipher_open (gcry_cipher_hd_t *handle, /* Release all resources associated with the cipher handle H. H may be NULL in which case this is a no-operation. */ void -gcry_cipher_close (gcry_cipher_hd_t h) +_gcry_cipher_close (gcry_cipher_hd_t h) { size_t off; @@ -856,11 +563,6 @@ gcry_cipher_close (gcry_cipher_hd_t h) else h->magic = 0; - /* Release module. */ - ath_mutex_lock (&ciphers_registered_lock); - _gcry_module_release (h->module); - ath_mutex_unlock (&ciphers_registered_lock); - /* We always want to wipe out the memory even when the context has been allocated in secure memory. The user might have disabled secure memory or is using his own implementation which does not @@ -870,56 +572,83 @@ gcry_cipher_close (gcry_cipher_hd_t h) off = h->handle_offset; wipememory (h, h->actual_handle_size); - gcry_free ((char*)h - off); + xfree ((char*)h - off); } /* Set the key to be used for the encryption context C to KEY with length KEYLEN. The length should match the required length. */ -static gcry_error_t -cipher_setkey (gcry_cipher_hd_t c, byte *key, unsigned int keylen) +static gcry_err_code_t +cipher_setkey (gcry_cipher_hd_t c, byte *key, size_t keylen) { - gcry_err_code_t ret; + gcry_err_code_t rc; - ret = (*c->cipher->setkey) (&c->context.c, key, keylen); - if (!ret) + rc = c->spec->setkey (&c->context.c, key, keylen); + if (!rc) { /* Duplicate initial context. */ - memcpy ((void *) ((char *) &c->context.c + c->cipher->contextsize), + memcpy ((void *) ((char *) &c->context.c + c->spec->contextsize), (void *) &c->context.c, - c->cipher->contextsize); + c->spec->contextsize); c->marks.key = 1; + + switch (c->mode) + { + case GCRY_CIPHER_MODE_CMAC: + _gcry_cipher_cmac_set_subkeys (c); + break; + + case GCRY_CIPHER_MODE_GCM: + _gcry_cipher_gcm_setkey (c); + break; + + default: + break; + }; } else c->marks.key = 0; - return gcry_error (ret); + return rc; } /* Set the IV to be used for the encryption context C to IV with length IVLEN. The length should match the required length. */ -static void -cipher_setiv( gcry_cipher_hd_t c, const byte *iv, unsigned ivlen ) +static gcry_err_code_t +cipher_setiv (gcry_cipher_hd_t c, const byte *iv, size_t ivlen) { - memset (c->u_iv.iv, 0, c->cipher->blocksize); - if (iv) + /* GCM has its own IV handler */ + if (c->mode == GCRY_CIPHER_MODE_GCM) + return _gcry_cipher_gcm_setiv (c, iv, ivlen); + + /* If the cipher has its own IV handler, we use only this one. This + is currently used for stream ciphers requiring a nonce. */ + if (c->spec->setiv) + { + c->spec->setiv (&c->context.c, iv, ivlen); + return 0; + } + + memset (c->u_iv.iv, 0, c->spec->blocksize); + if (iv) { - if (ivlen != c->cipher->blocksize) + if (ivlen != c->spec->blocksize) { log_info ("WARNING: cipher_setiv: ivlen=%u blklen=%u\n", - ivlen, (unsigned int)c->cipher->blocksize); + (unsigned int)ivlen, (unsigned int)c->spec->blocksize); fips_signal_error ("IV length does not match blocklength"); } - if (ivlen > c->cipher->blocksize) - ivlen = c->cipher->blocksize; + if (ivlen > c->spec->blocksize) + ivlen = c->spec->blocksize; memcpy (c->u_iv.iv, iv, ivlen); c->marks.iv = 1; } else - c->marks.iv = 0; - + c->marks.iv = 0; c->unused = 0; + + return 0; } @@ -928,705 +657,178 @@ cipher_setiv( gcry_cipher_hd_t c, const byte *iv, unsigned ivlen ) static void cipher_reset (gcry_cipher_hd_t c) { - memcpy (&c->context.c, - (char *) &c->context.c + c->cipher->contextsize, - c->cipher->contextsize); - memset (&c->marks, 0, sizeof c->marks); - memset (c->u_iv.iv, 0, c->cipher->blocksize); - memset (c->lastiv, 0, c->cipher->blocksize); - memset (c->ctr, 0, c->cipher->blocksize); -} - - -static void -do_ecb_encrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, - unsigned int nblocks ) -{ - unsigned int n; - - for (n=0; n < nblocks; n++ ) - { - c->cipher->encrypt ( &c->context.c, outbuf, (byte*)/*arggg*/inbuf ); - inbuf += c->cipher->blocksize; - outbuf += c->cipher->blocksize; - } -} - -static void -do_ecb_decrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, - unsigned int nblocks ) -{ - unsigned int n; + unsigned int marks_key; - for (n=0; n < nblocks; n++ ) - { - c->cipher->decrypt ( &c->context.c, outbuf, (byte*)/*arggg*/inbuf ); - inbuf += c->cipher->blocksize; - outbuf += c->cipher->blocksize; - } -} + marks_key = c->marks.key; + memcpy (&c->context.c, + (char *) &c->context.c + c->spec->contextsize, + c->spec->contextsize); + memset (&c->marks, 0, sizeof c->marks); + memset (c->u_iv.iv, 0, c->spec->blocksize); + memset (c->lastiv, 0, c->spec->blocksize); + memset (c->u_ctr.ctr, 0, c->spec->blocksize); + c->unused = 0; -static void -do_cbc_encrypt (gcry_cipher_hd_t c, unsigned char *outbuf, - const unsigned char *inbuf, unsigned int nbytes ) -{ - unsigned int n; - unsigned char *ivp; - int i; - size_t blocksize = c->cipher->blocksize; - unsigned nblocks = nbytes / blocksize; + c->marks.key = marks_key; - if ((c->flags & GCRY_CIPHER_CBC_CTS) && nbytes > blocksize) + switch (c->mode) { - if ((nbytes % blocksize) == 0) - nblocks--; - } + case GCRY_CIPHER_MODE_CMAC: + /* Only clear 'tag' for cmac, keep subkeys. */ + c->u_mode.cmac.tag = 0; + break; - if (c->bulk.cbc_enc) - { - c->bulk.cbc_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks, - (c->flags & GCRY_CIPHER_CBC_MAC)); - inbuf += nblocks * blocksize; - if (!(c->flags & GCRY_CIPHER_CBC_MAC)) - outbuf += nblocks * blocksize; - } - else - { - for (n=0; n < nblocks; n++ ) - { - for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) - outbuf[i] = inbuf[i] ^ *ivp++; - c->cipher->encrypt ( &c->context.c, outbuf, outbuf ); - memcpy (c->u_iv.iv, outbuf, blocksize ); - inbuf += blocksize; - if (!(c->flags & GCRY_CIPHER_CBC_MAC)) - outbuf += blocksize; - } - } + case GCRY_CIPHER_MODE_GCM: + /* Only clear head of u_mode, keep ghash_key and gcm_table. */ + { + byte *u_mode_pos = (void *)&c->u_mode; + byte *ghash_key_pos = c->u_mode.gcm.u_ghash_key.key; + size_t u_mode_head_length = ghash_key_pos - u_mode_pos; - if ((c->flags & GCRY_CIPHER_CBC_CTS) && nbytes > blocksize) - { - /* We have to be careful here, since outbuf might be equal to - inbuf. */ - int restbytes; - unsigned char b; + memset (&c->u_mode, 0, u_mode_head_length); + } + break; - if ((nbytes % blocksize) == 0) - restbytes = blocksize; - else - restbytes = nbytes % blocksize; +#ifdef HAVE_U64_TYPEDEF + case GCRY_CIPHER_MODE_CCM: + memset (&c->u_mode.ccm, 0, sizeof c->u_mode.ccm); + break; +#endif - outbuf -= blocksize; - for (ivp = c->u_iv.iv, i = 0; i < restbytes; i++) - { - b = inbuf[i]; - outbuf[blocksize + i] = outbuf[i]; - outbuf[i] = b ^ *ivp++; - } - for (; i < blocksize; i++) - outbuf[i] = 0 ^ *ivp++; - - c->cipher->encrypt (&c->context.c, outbuf, outbuf); - memcpy (c->u_iv.iv, outbuf, blocksize); + default: + break; /* u_mode unused by other modes. */ } } -static void -do_cbc_decrypt (gcry_cipher_hd_t c, unsigned char *outbuf, - const unsigned char *inbuf, unsigned int nbytes) + +static gcry_err_code_t +do_ecb_crypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen, + gcry_cipher_encrypt_t crypt_fn) { - unsigned int n; - unsigned char *ivp; - int i; - size_t blocksize = c->cipher->blocksize; - unsigned int nblocks = nbytes / blocksize; - - if ((c->flags & GCRY_CIPHER_CBC_CTS) && nbytes > blocksize) - { - nblocks--; - if ((nbytes % blocksize) == 0) - nblocks--; - memcpy (c->lastiv, c->u_iv.iv, blocksize); - } + unsigned int blocksize = c->spec->blocksize; + size_t n, nblocks; + unsigned int burn, nburn; - if (c->bulk.cbc_dec) - { - c->bulk.cbc_dec (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); - inbuf += nblocks * blocksize; - outbuf += nblocks * blocksize; - } - else - { - for (n=0; n < nblocks; n++ ) - { - /* Because outbuf and inbuf might be the same, we have to - * save the original ciphertext block. We use LASTIV for - * this here because it is not used otherwise. */ - memcpy (c->lastiv, inbuf, blocksize); - c->cipher->decrypt ( &c->context.c, outbuf, inbuf ); - for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) - outbuf[i] ^= *ivp++; - memcpy(c->u_iv.iv, c->lastiv, blocksize ); - inbuf += c->cipher->blocksize; - outbuf += c->cipher->blocksize; - } - } - - if ((c->flags & GCRY_CIPHER_CBC_CTS) && nbytes > blocksize) - { - int restbytes; - - if ((nbytes % blocksize) == 0) - restbytes = blocksize; - else - restbytes = nbytes % blocksize; - - memcpy (c->lastiv, c->u_iv.iv, blocksize ); /* Save Cn-2. */ - memcpy (c->u_iv.iv, inbuf + blocksize, restbytes ); /* Save Cn. */ - - c->cipher->decrypt ( &c->context.c, outbuf, inbuf ); - for (ivp=c->u_iv.iv,i=0; i < restbytes; i++ ) - outbuf[i] ^= *ivp++; - - memcpy(outbuf + blocksize, outbuf, restbytes); - for(i=restbytes; i < blocksize; i++) - c->u_iv.iv[i] = outbuf[i]; - c->cipher->decrypt (&c->context.c, outbuf, c->u_iv.iv); - for(ivp=c->lastiv,i=0; i < blocksize; i++ ) - outbuf[i] ^= *ivp++; - /* c->lastiv is now really lastlastiv, does this matter? */ - } -} + if (outbuflen < inbuflen) + return GPG_ERR_BUFFER_TOO_SHORT; + if ((inbuflen % blocksize)) + return GPG_ERR_INV_LENGTH; + nblocks = inbuflen / blocksize; + burn = 0; -static void -do_cfb_encrypt( gcry_cipher_hd_t c, unsigned char *outbuf, - const unsigned char *inbuf, unsigned int nbytes ) -{ - unsigned char *ivp; - size_t blocksize = c->cipher->blocksize; - size_t blocksize_x_2 = blocksize + blocksize; - - if ( nbytes <= c->unused ) + for (n=0; n < nblocks; n++ ) { - /* Short enough to be encoded by the remaining XOR mask. */ - /* XOR the input with the IV and store input into IV. */ - for (ivp=c->u_iv.iv+c->cipher->blocksize - c->unused; - nbytes; - nbytes--, c->unused-- ) - *outbuf++ = (*ivp++ ^= *inbuf++); - return; + nburn = crypt_fn (&c->context.c, outbuf, inbuf); + burn = nburn > burn ? nburn : burn; + inbuf += blocksize; + outbuf += blocksize; } - if ( c->unused ) - { - /* XOR the input with the IV and store input into IV */ - nbytes -= c->unused; - for(ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- ) - *outbuf++ = (*ivp++ ^= *inbuf++); - } + if (burn > 0) + _gcry_burn_stack (burn + 4 * sizeof(void *)); - /* Now we can process complete blocks. We use a loop as long as we - have at least 2 blocks and use conditions for the rest. This - also allows to use a bulk encryption function if available. */ - if (nbytes >= blocksize_x_2 && c->bulk.cfb_enc) - { - unsigned int nblocks = nbytes / blocksize; - c->bulk.cfb_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); - outbuf += nblocks * blocksize; - inbuf += nblocks * blocksize; - nbytes -= nblocks * blocksize; - } - else - { - while ( nbytes >= blocksize_x_2 ) - { - int i; - /* Encrypt the IV. */ - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - /* XOR the input with the IV and store input into IV. */ - for(ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) - *outbuf++ = (*ivp++ ^= *inbuf++); - nbytes -= blocksize; - } - } - - if ( nbytes >= blocksize ) - { - int i; - /* Save the current IV and then encrypt the IV. */ - memcpy( c->lastiv, c->u_iv.iv, blocksize ); - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - /* XOR the input with the IV and store input into IV */ - for(ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) - *outbuf++ = (*ivp++ ^= *inbuf++); - nbytes -= blocksize; - } - if ( nbytes ) - { - /* Save the current IV and then encrypt the IV. */ - memcpy( c->lastiv, c->u_iv.iv, blocksize ); - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - c->unused = blocksize; - /* Apply the XOR. */ - c->unused -= nbytes; - for(ivp=c->u_iv.iv; nbytes; nbytes-- ) - *outbuf++ = (*ivp++ ^= *inbuf++); - } + return 0; } - -static void -do_cfb_decrypt( gcry_cipher_hd_t c, unsigned char *outbuf, - const unsigned char *inbuf, unsigned int nbytes ) +static gcry_err_code_t +do_ecb_encrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) { - unsigned char *ivp; - unsigned long temp; - int i; - size_t blocksize = c->cipher->blocksize; - size_t blocksize_x_2 = blocksize + blocksize; - - if (nbytes <= c->unused) - { - /* Short enough to be encoded by the remaining XOR mask. */ - /* XOR the input with the IV and store input into IV. */ - for (ivp=c->u_iv.iv+blocksize - c->unused; - nbytes; - nbytes--, c->unused--) - { - temp = *inbuf++; - *outbuf++ = *ivp ^ temp; - *ivp++ = temp; - } - return; - } - - if (c->unused) - { - /* XOR the input with the IV and store input into IV. */ - nbytes -= c->unused; - for (ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- ) - { - temp = *inbuf++; - *outbuf++ = *ivp ^ temp; - *ivp++ = temp; - } - } - - /* Now we can process complete blocks. We use a loop as long as we - have at least 2 blocks and use conditions for the rest. This - also allows to use a bulk encryption function if available. */ - if (nbytes >= blocksize_x_2 && c->bulk.cfb_dec) - { - unsigned int nblocks = nbytes / blocksize; - c->bulk.cfb_dec (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks); - outbuf += nblocks * blocksize; - inbuf += nblocks * blocksize; - nbytes -= nblocks * blocksize; - } - else - { - while (nbytes >= blocksize_x_2 ) - { - /* Encrypt the IV. */ - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - /* XOR the input with the IV and store input into IV. */ - for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) - { - temp = *inbuf++; - *outbuf++ = *ivp ^ temp; - *ivp++ = temp; - } - nbytes -= blocksize; - } - } - - if (nbytes >= blocksize ) - { - /* Save the current IV and then encrypt the IV. */ - memcpy ( c->lastiv, c->u_iv.iv, blocksize); - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - /* XOR the input with the IV and store input into IV */ - for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) - { - temp = *inbuf++; - *outbuf++ = *ivp ^ temp; - *ivp++ = temp; - } - nbytes -= blocksize; - } - - if (nbytes) - { - /* Save the current IV and then encrypt the IV. */ - memcpy ( c->lastiv, c->u_iv.iv, blocksize ); - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - c->unused = blocksize; - /* Apply the XOR. */ - c->unused -= nbytes; - for (ivp=c->u_iv.iv; nbytes; nbytes-- ) - { - temp = *inbuf++; - *outbuf++ = *ivp ^ temp; - *ivp++ = temp; - } - } + return do_ecb_crypt (c, outbuf, outbuflen, inbuf, inbuflen, c->spec->encrypt); } - -static void -do_ofb_encrypt( gcry_cipher_hd_t c, - byte *outbuf, const byte *inbuf, unsigned nbytes ) -{ - byte *ivp; - size_t blocksize = c->cipher->blocksize; - - if ( nbytes <= c->unused ) - { - /* Short enough to be encoded by the remaining XOR mask. */ - /* XOR the input with the IV */ - for (ivp=c->u_iv.iv+c->cipher->blocksize - c->unused; - nbytes; - nbytes--, c->unused-- ) - *outbuf++ = (*ivp++ ^ *inbuf++); - return; - } - - if( c->unused ) - { - nbytes -= c->unused; - for(ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- ) - *outbuf++ = (*ivp++ ^ *inbuf++); - } - - /* Now we can process complete blocks. */ - while ( nbytes >= blocksize ) - { - int i; - /* Encrypt the IV (and save the current one). */ - memcpy( c->lastiv, c->u_iv.iv, blocksize ); - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - - for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) - *outbuf++ = (*ivp++ ^ *inbuf++); - nbytes -= blocksize; - } - if ( nbytes ) - { /* process the remaining bytes */ - memcpy( c->lastiv, c->u_iv.iv, blocksize ); - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - c->unused = blocksize; - c->unused -= nbytes; - for(ivp=c->u_iv.iv; nbytes; nbytes-- ) - *outbuf++ = (*ivp++ ^ *inbuf++); - } -} - -static void -do_ofb_decrypt( gcry_cipher_hd_t c, - byte *outbuf, const byte *inbuf, unsigned int nbytes ) +static gcry_err_code_t +do_ecb_decrypt (gcry_cipher_hd_t c, + unsigned char *outbuf, size_t outbuflen, + const unsigned char *inbuf, size_t inbuflen) { - byte *ivp; - size_t blocksize = c->cipher->blocksize; - - if( nbytes <= c->unused ) - { - /* Short enough to be encoded by the remaining XOR mask. */ - for (ivp=c->u_iv.iv+blocksize - c->unused; nbytes; nbytes--,c->unused--) - *outbuf++ = *ivp++ ^ *inbuf++; - return; - } - - if ( c->unused ) - { - nbytes -= c->unused; - for (ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- ) - *outbuf++ = *ivp++ ^ *inbuf++; - } - - /* Now we can process complete blocks. */ - while ( nbytes >= blocksize ) - { - int i; - /* Encrypt the IV (and save the current one). */ - memcpy( c->lastiv, c->u_iv.iv, blocksize ); - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ ) - *outbuf++ = *ivp++ ^ *inbuf++; - nbytes -= blocksize; - } - if ( nbytes ) - { /* Process the remaining bytes. */ - /* Encrypt the IV (and save the current one). */ - memcpy( c->lastiv, c->u_iv.iv, blocksize ); - c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv ); - c->unused = blocksize; - c->unused -= nbytes; - for (ivp=c->u_iv.iv; nbytes; nbytes-- ) - *outbuf++ = *ivp++ ^ *inbuf++; - } + return do_ecb_crypt (c, outbuf, outbuflen, inbuf, inbuflen, c->spec->decrypt); } -static void -do_ctr_encrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, - unsigned int nbytes ) +/**************** + * Encrypt INBUF to OUTBUF with the mode selected at open. + * inbuf and outbuf may overlap or be the same. + * Depending on the mode some constraints apply to INBUFLEN. + */ +static gcry_err_code_t +cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen) { - unsigned int n; - byte tmp[MAX_BLOCKSIZE]; - int i; + gcry_err_code_t rc; - for(n=0; n < nbytes; n++) + switch (c->mode) { - if ((n % c->cipher->blocksize) == 0) - { - c->cipher->encrypt (&c->context.c, tmp, c->ctr); - - for (i = c->cipher->blocksize; i > 0; i--) - { - c->ctr[i-1]++; - if (c->ctr[i-1] != 0) - break; - } - } - - /* XOR input with encrypted counter and store in output. */ - outbuf[n] = inbuf[n] ^ tmp[n % c->cipher->blocksize]; - } -} - -static void -do_ctr_decrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, - unsigned int nbytes ) -{ - do_ctr_encrypt (c, outbuf, inbuf, nbytes); -} + case GCRY_CIPHER_MODE_ECB: + rc = do_ecb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + case GCRY_CIPHER_MODE_CBC: + rc = _gcry_cipher_cbc_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; -/* Perform the AES-Wrap algorithm as specified by RFC3394. We - implement this as a mode usable with any cipher algorithm of - blocksize 128. */ -static gcry_err_code_t -do_aeswrap_encrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, - const byte *inbuf, unsigned int inbuflen ) -{ - int j, x; - unsigned int n, i; - unsigned char *r, *a, *b; - unsigned char t[8]; + case GCRY_CIPHER_MODE_CFB: + rc = _gcry_cipher_cfb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; -#if MAX_BLOCKSIZE < 8 -#error Invalid block size -#endif - /* We require a cipher with a 128 bit block length. */ - if (c->cipher->blocksize != 16) - return GPG_ERR_INV_LENGTH; - - /* The output buffer must be able to hold the input data plus one - additional block. */ - if (outbuflen < inbuflen + 8) - return GPG_ERR_BUFFER_TOO_SHORT; - /* Input data must be multiple of 64 bits. */ - if (inbuflen % 8) - return GPG_ERR_INV_ARG; + case GCRY_CIPHER_MODE_OFB: + rc = _gcry_cipher_ofb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; - n = inbuflen / 8; + case GCRY_CIPHER_MODE_CTR: + rc = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; - /* We need at least two 64 bit blocks. */ - if (n < 2) - return GPG_ERR_INV_ARG; + case GCRY_CIPHER_MODE_AESWRAP: + rc = _gcry_cipher_aeswrap_encrypt (c, outbuf, outbuflen, + inbuf, inbuflen); + break; - r = outbuf; - a = outbuf; /* We store A directly in OUTBUF. */ - b = c->ctr; /* B is also used to concatenate stuff. */ + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; - /* If an IV has been set we use that IV as the Alternative Initial - Value; if it has not been set we use the standard value. */ - if (c->marks.iv) - memcpy (a, c->u_iv.iv, 8); - else - memset (a, 0xa6, 8); + case GCRY_CIPHER_MODE_CMAC: + rc = GPG_ERR_INV_CIPHER_MODE; + break; - /* Copy the inbuf to the outbuf. */ - memmove (r+8, inbuf, inbuflen); + case GCRY_CIPHER_MODE_GCM: + rc = _gcry_cipher_gcm_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; - memset (t, 0, sizeof t); /* t := 0. */ + case GCRY_CIPHER_MODE_STREAM: + c->spec->stencrypt (&c->context.c, + outbuf, (byte*)/*arggg*/inbuf, inbuflen); + rc = 0; + break; - for (j = 0; j <= 5; j++) - { - for (i = 1; i <= n; i++) + case GCRY_CIPHER_MODE_NONE: + if (fips_mode () || !_gcry_get_debug_flag (0)) { - /* B := AES_k( A | R[i] ) */ - memcpy (b, a, 8); - memcpy (b+8, r+i*8, 8); - c->cipher->encrypt (&c->context.c, b, b); - /* t := t + 1 */ - for (x = 7; x >= 0; x--) - { - t[x]++; - if (t[x]) - break; - } - /* A := MSB_64(B) ^ t */ - for (x=0; x < 8; x++) - a[x] = b[x] ^ t[x]; - /* R[i] := LSB_64(B) */ - memcpy (r+i*8, b+8, 8); + fips_signal_error ("cipher mode NONE used"); + rc = GPG_ERR_INV_CIPHER_MODE; } - } - - return 0; -} - -/* Perform the AES-Unwrap algorithm as specified by RFC3394. We - implement this as a mode usable with any cipher algorithm of - blocksize 128. */ -static gcry_err_code_t -do_aeswrap_decrypt (gcry_cipher_hd_t c, byte *outbuf, unsigned int outbuflen, - const byte *inbuf, unsigned int inbuflen) -{ - int j, x; - unsigned int n, i; - unsigned char *r, *a, *b; - unsigned char t[8]; - -#if MAX_BLOCKSIZE < 8 -#error Invalid block size -#endif - /* We require a cipher with a 128 bit block length. */ - if (c->cipher->blocksize != 16) - return GPG_ERR_INV_LENGTH; - - /* The output buffer must be able to hold the input data minus one - additional block. Fixme: The caller has more restrictive checks - - we may want to fix them for this mode. */ - if (outbuflen + 8 < inbuflen) - return GPG_ERR_BUFFER_TOO_SHORT; - /* Input data must be multiple of 64 bits. */ - if (inbuflen % 8) - return GPG_ERR_INV_ARG; - - n = inbuflen / 8; - - /* We need at least three 64 bit blocks. */ - if (n < 3) - return GPG_ERR_INV_ARG; - - r = outbuf; - a = c->lastiv; /* We use c->LASTIV as buffer for A. */ - b = c->ctr; /* B is also used to concatenate stuff. */ - - /* Copy the inbuf to the outbuf and save A. */ - memcpy (a, inbuf, 8); - memmove (r, inbuf+8, inbuflen-8); - n--; /* Reduce to actual number of data blocks. */ - - /* t := 6 * n */ - i = n * 6; /* The range is valid because: n = inbuflen / 8 - 1. */ - for (x=0; x < 8 && x < sizeof (i); x++) - t[7-x] = i >> (8*x); - for (; x < 8; x++) - t[7-x] = 0; - - for (j = 5; j >= 0; j--) - { - for (i = n; i >= 1; i--) + else { - /* B := AES_k^1( (A ^ t)| R[i] ) */ - for (x = 0; x < 8; x++) - b[x] = a[x] ^ t[x]; - memcpy (b+8, r+(i-1)*8, 8); - c->cipher->decrypt (&c->context.c, b, b); - /* t := t - 1 */ - for (x = 7; x >= 0; x--) - { - t[x]--; - if (t[x] != 0xff) - break; - } - /* A := MSB_64(B) */ - memcpy (a, b, 8); - /* R[i] := LSB_64(B) */ - memcpy (r+(i-1)*8, b+8, 8); + if (inbuf != outbuf) + memmove (outbuf, inbuf, inbuflen); + rc = 0; } - } + break; - /* If an IV has been set we compare against this Alternative Initial - Value; if it has not been set we compare against the standard IV. */ - if (c->marks.iv) - j = memcmp (a, c->u_iv.iv, 8); - else - { - for (j=0, x=0; x < 8; x++) - if (a[x] != 0xa6) - { - j=1; - break; - } + default: + log_fatal ("cipher_encrypt: invalid mode %d\n", c->mode ); + rc = GPG_ERR_INV_CIPHER_MODE; + break; } - return j? GPG_ERR_CHECKSUM : 0; -} - -/**************** - * Encrypt INBUF to OUTBUF with the mode selected at open. - * inbuf and outbuf may overlap or be the same. - * Depending on the mode some contraints apply to NBYTES. - */ -static gcry_err_code_t -cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, - const byte *inbuf, unsigned int nbytes) -{ - gcry_err_code_t rc = GPG_ERR_NO_ERROR; - - switch( c->mode ) { - case GCRY_CIPHER_MODE_ECB: - if (!(nbytes%c->cipher->blocksize)) - do_ecb_encrypt(c, outbuf, inbuf, nbytes/c->cipher->blocksize ); - else - rc = GPG_ERR_INV_ARG; - break; - case GCRY_CIPHER_MODE_CBC: - if (!(nbytes%c->cipher->blocksize) - || (nbytes > c->cipher->blocksize - && (c->flags & GCRY_CIPHER_CBC_CTS))) - do_cbc_encrypt(c, outbuf, inbuf, nbytes ); - else - rc = GPG_ERR_INV_ARG; - break; - case GCRY_CIPHER_MODE_CFB: - do_cfb_encrypt(c, outbuf, inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_OFB: - do_ofb_encrypt(c, outbuf, inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_CTR: - do_ctr_encrypt(c, outbuf, inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_STREAM: - c->cipher->stencrypt ( &c->context.c, - outbuf, (byte*)/*arggg*/inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_NONE: - if (fips_mode () || !_gcry_get_debug_flag (0)) - { - fips_signal_error ("cipher mode NONE used"); - rc = GPG_ERR_INV_CIPHER_MODE; - } - else - { - if ( inbuf != outbuf ) - memmove (outbuf, inbuf, nbytes); - } - break; - default: - log_fatal("cipher_encrypt: invalid mode %d\n", c->mode ); - rc = GPG_ERR_INV_CIPHER_MODE; - break; - } - return rc; + return rc; } @@ -1634,48 +836,26 @@ cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf, * Encrypt IN and write it to OUT. If IN is NULL, in-place encryption has * been requested. */ -gcry_error_t -gcry_cipher_encrypt (gcry_cipher_hd_t h, void *out, size_t outsize, - const void *in, size_t inlen) +gcry_err_code_t +_gcry_cipher_encrypt (gcry_cipher_hd_t h, void *out, size_t outsize, + const void *in, size_t inlen) { - gcry_err_code_t err; + gcry_err_code_t rc; - if (h->mode == GCRY_CIPHER_MODE_AESWRAP) - { - /* Hack to implement AESWRAP without touching the other modes. - The actual function has been taken from the current - development version which does all error checking in each - mode function. */ - if (!in) - err = do_aeswrap_encrypt (h, out, outsize, out, outsize); - else - err = do_aeswrap_encrypt (h, out, outsize, in, inlen); - } - else if (!in) + if (!in) /* Caller requested in-place encryption. */ { - /* Caller requested in-place encryption. */ - /* Actually cipher_encrypt() does not need to know about it, but - * we may change it in the future to get better performance. */ - err = cipher_encrypt (h, out, out, outsize); + in = out; + inlen = outsize; } - else if (outsize < ((h->flags & GCRY_CIPHER_CBC_MAC) ? - h->cipher->blocksize : inlen)) - err = GPG_ERR_TOO_SHORT; - else if ((h->mode == GCRY_CIPHER_MODE_ECB - || (h->mode == GCRY_CIPHER_MODE_CBC - && (! ((h->flags & GCRY_CIPHER_CBC_CTS) - && (inlen > h->cipher->blocksize))))) - && (inlen % h->cipher->blocksize)) - err = GPG_ERR_INV_ARG; - else - err = cipher_encrypt (h, out, in, inlen); - if (err && out) - memset (out, 0x42, outsize); /* Failsafe: Make sure that the - plaintext will never make it into - OUT. */ + rc = cipher_encrypt (h, out, outsize, in, inlen); - return gcry_error (err); + /* Failsafe: Make sure that the plaintext will never make it into + OUT if the encryption returned an error. */ + if (rc && out) + memset (out, 0x42, outsize); + + return rc; } @@ -1683,99 +863,94 @@ gcry_cipher_encrypt (gcry_cipher_hd_t h, void *out, size_t outsize, /**************** * Decrypt INBUF to OUTBUF with the mode selected at open. * inbuf and outbuf may overlap or be the same. - * Depending on the mode some some contraints apply to NBYTES. + * Depending on the mode some some contraints apply to INBUFLEN. */ static gcry_err_code_t -cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf, - unsigned int nbytes) +cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen, + const byte *inbuf, size_t inbuflen) { - gcry_err_code_t rc = GPG_ERR_NO_ERROR; + gcry_err_code_t rc; - switch( c->mode ) { - case GCRY_CIPHER_MODE_ECB: - if (!(nbytes%c->cipher->blocksize)) - do_ecb_decrypt(c, outbuf, inbuf, nbytes/c->cipher->blocksize ); - else - rc = GPG_ERR_INV_ARG; - break; - case GCRY_CIPHER_MODE_CBC: - if (!(nbytes%c->cipher->blocksize) - || (nbytes > c->cipher->blocksize - && (c->flags & GCRY_CIPHER_CBC_CTS))) - do_cbc_decrypt(c, outbuf, inbuf, nbytes ); - else - rc = GPG_ERR_INV_ARG; - break; - case GCRY_CIPHER_MODE_CFB: - do_cfb_decrypt(c, outbuf, inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_OFB: - do_ofb_decrypt(c, outbuf, inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_CTR: - do_ctr_decrypt(c, outbuf, inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_STREAM: - c->cipher->stdecrypt ( &c->context.c, - outbuf, (byte*)/*arggg*/inbuf, nbytes ); - break; - case GCRY_CIPHER_MODE_NONE: - if (fips_mode () || !_gcry_get_debug_flag (0)) - { - fips_signal_error ("cipher mode NONE used"); - rc = GPG_ERR_INV_CIPHER_MODE; - } - else - { - if (inbuf != outbuf) - memmove (outbuf, inbuf, nbytes); - } - break; - default: - log_fatal ("cipher_decrypt: invalid mode %d\n", c->mode ); - rc = GPG_ERR_INV_CIPHER_MODE; - break; - } - return rc; -} + switch (c->mode) + { + case GCRY_CIPHER_MODE_ECB: + rc = do_ecb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + case GCRY_CIPHER_MODE_CBC: + rc = _gcry_cipher_cbc_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; -gcry_error_t -gcry_cipher_decrypt (gcry_cipher_hd_t h, void *out, size_t outsize, - const void *in, size_t inlen) -{ - gcry_err_code_t err = 0; + case GCRY_CIPHER_MODE_CFB: + rc = _gcry_cipher_cfb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; - if (h->mode == GCRY_CIPHER_MODE_AESWRAP) - { - /* Hack to implement AESWRAP without touching the other modes. - The actual function has been taken from the current - development version which does all error checking in each - mode function. */ - if (!in) - err = do_aeswrap_decrypt (h, out, outsize, out, outsize); + case GCRY_CIPHER_MODE_OFB: + rc = _gcry_cipher_ofb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + + case GCRY_CIPHER_MODE_CTR: + rc = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + + case GCRY_CIPHER_MODE_AESWRAP: + rc = _gcry_cipher_aeswrap_decrypt (c, outbuf, outbuflen, + inbuf, inbuflen); + break; + + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + + case GCRY_CIPHER_MODE_CMAC: + rc = GPG_ERR_INV_CIPHER_MODE; + break; + + case GCRY_CIPHER_MODE_GCM: + rc = _gcry_cipher_gcm_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); + break; + + case GCRY_CIPHER_MODE_STREAM: + c->spec->stdecrypt (&c->context.c, + outbuf, (byte*)/*arggg*/inbuf, inbuflen); + rc = 0; + break; + + case GCRY_CIPHER_MODE_NONE: + if (fips_mode () || !_gcry_get_debug_flag (0)) + { + fips_signal_error ("cipher mode NONE used"); + rc = GPG_ERR_INV_CIPHER_MODE; + } else - err = do_aeswrap_decrypt (h, out, outsize, in, inlen); + { + if (inbuf != outbuf) + memmove (outbuf, inbuf, inbuflen); + rc = 0; + } + break; + + default: + log_fatal ("cipher_decrypt: invalid mode %d\n", c->mode ); + rc = GPG_ERR_INV_CIPHER_MODE; + break; } - else if (!in) + + return rc; +} + + +gcry_err_code_t +_gcry_cipher_decrypt (gcry_cipher_hd_t h, void *out, size_t outsize, + const void *in, size_t inlen) +{ + if (!in) /* Caller requested in-place encryption. */ { - /* Caller requested in-place encryption. */ - /* Actually cipher_encrypt() does not need to know about it, but - * we may change it in the future to get better performance. */ - err = cipher_decrypt (h, out, out, outsize); + in = out; + inlen = outsize; } - else if (outsize < inlen) - err = GPG_ERR_TOO_SHORT; - else if (((h->mode == GCRY_CIPHER_MODE_ECB) - || ((h->mode == GCRY_CIPHER_MODE_CBC) - && (! ((h->flags & GCRY_CIPHER_CBC_CTS) - && (inlen > h->cipher->blocksize))))) - && (inlen % h->cipher->blocksize) != 0) - err = GPG_ERR_INV_ARG; - else - err = cipher_decrypt (h, out, in, inlen); - return gcry_error (err); + return cipher_decrypt (h, out, outsize, in, inlen); } @@ -1790,59 +965,157 @@ cipher_sync (gcry_cipher_hd_t c) if ((c->flags & GCRY_CIPHER_ENABLE_SYNC) && c->unused) { memmove (c->u_iv.iv + c->unused, - c->u_iv.iv, c->cipher->blocksize - c->unused); + c->u_iv.iv, c->spec->blocksize - c->unused); memcpy (c->u_iv.iv, - c->lastiv + c->cipher->blocksize - c->unused, c->unused); + c->lastiv + c->spec->blocksize - c->unused, c->unused); c->unused = 0; } } -gcry_error_t +gcry_err_code_t _gcry_cipher_setkey (gcry_cipher_hd_t hd, const void *key, size_t keylen) { return cipher_setkey (hd, (void*)key, keylen); } -gcry_error_t +gcry_err_code_t _gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen) { - cipher_setiv (hd, iv, ivlen); - return 0; + gcry_err_code_t rc = 0; + + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_set_nonce (hd, iv, ivlen); + break; + + default: + rc = cipher_setiv (hd, iv, ivlen); + break; + } + return rc; } /* Set counter for CTR mode. (CTR,CTRLEN) must denote a buffer of block size length, or (NULL,0) to set the CTR to the all-zero block. */ -gpg_error_t +gpg_err_code_t _gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen) { - if (ctr && ctrlen == hd->cipher->blocksize) - memcpy (hd->ctr, ctr, hd->cipher->blocksize); + if (ctr && ctrlen == hd->spec->blocksize) + { + memcpy (hd->u_ctr.ctr, ctr, hd->spec->blocksize); + hd->unused = 0; + } else if (!ctr || !ctrlen) - memset (hd->ctr, 0, hd->cipher->blocksize); + { + memset (hd->u_ctr.ctr, 0, hd->spec->blocksize); + hd->unused = 0; + } else - return gpg_error (GPG_ERR_INV_ARG); + return GPG_ERR_INV_ARG; + return 0; } -gcry_error_t -gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) +gcry_err_code_t +_gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, + size_t abuflen) { - gcry_err_code_t rc = GPG_ERR_NO_ERROR; + gcry_err_code_t rc; - switch (cmd) + switch (hd->mode) { - case GCRYCTL_SET_KEY: /* Deprecated; use gcry_cipher_setkey. */ - rc = cipher_setkey( h, buffer, buflen ); + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_authenticate (hd, abuf, abuflen); + break; + + case GCRY_CIPHER_MODE_CMAC: + rc = _gcry_cipher_cmac_authenticate (hd, abuf, abuflen); + break; + + case GCRY_CIPHER_MODE_GCM: + rc = _gcry_cipher_gcm_authenticate (hd, abuf, abuflen); + break; + + default: + log_error ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } + + return rc; +} + + +gcry_err_code_t +_gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen) +{ + gcry_err_code_t rc; + + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_get_tag (hd, outtag, taglen); + break; + + case GCRY_CIPHER_MODE_CMAC: + rc = _gcry_cipher_cmac_get_tag (hd, outtag, taglen); break; - case GCRYCTL_SET_IV: /* Deprecated; use gcry_cipher_setiv. */ - cipher_setiv( h, buffer, buflen ); + case GCRY_CIPHER_MODE_GCM: + rc = _gcry_cipher_gcm_get_tag (hd, outtag, taglen); break; + default: + log_error ("gcry_cipher_gettag: invalid mode %d\n", hd->mode); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } + + return rc; +} + + +gcry_err_code_t +_gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen) +{ + gcry_err_code_t rc; + + switch (hd->mode) + { + case GCRY_CIPHER_MODE_CCM: + rc = _gcry_cipher_ccm_check_tag (hd, intag, taglen); + break; + + case GCRY_CIPHER_MODE_CMAC: + rc = _gcry_cipher_cmac_check_tag (hd, intag, taglen); + break; + + case GCRY_CIPHER_MODE_GCM: + rc = _gcry_cipher_gcm_check_tag (hd, intag, taglen); + break; + + default: + log_error ("gcry_cipher_checktag: invalid mode %d\n", hd->mode); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } + + return rc; +} + + +gcry_err_code_t +_gcry_cipher_ctl (gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) +{ + gcry_err_code_t rc = 0; + + switch (cmd) + { case GCRYCTL_RESET: cipher_reset (h); break; @@ -1871,6 +1144,34 @@ gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) h->flags &= ~GCRY_CIPHER_CBC_MAC; break; + case GCRYCTL_SET_CCM_LENGTHS: +#ifdef HAVE_U64_TYPEDEF + { + u64 params[3]; + size_t encryptedlen; + size_t aadlen; + size_t authtaglen; + + if (h->mode != GCRY_CIPHER_MODE_CCM) + return gcry_error (GPG_ERR_INV_CIPHER_MODE); + + if (!buffer || buflen != 3 * sizeof(u64)) + return gcry_error (GPG_ERR_INV_ARG); + + /* This command is used to pass additional length parameters needed + by CCM mode to initialize CBC-MAC. */ + memcpy (params, buffer, sizeof(params)); + encryptedlen = params[0]; + aadlen = params[1]; + authtaglen = params[2]; + + rc = _gcry_cipher_ccm_set_lengths (h, encryptedlen, aadlen, authtaglen); + } +#else + rc = GPG_ERR_NOT_SUPPORTED; +#endif + break; + case GCRYCTL_DISABLE_ALGO: /* This command expects NULL for H and BUFFER to point to an integer with the algo number. */ @@ -1879,18 +1180,9 @@ gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) disable_cipher_algo( *(int*)buffer ); break; - case GCRYCTL_SET_CTR: /* Deprecated; use gcry_cipher_setctr. */ - if (buffer && buflen == h->cipher->blocksize) - memcpy (h->ctr, buffer, h->cipher->blocksize); - else if (buffer == NULL || buflen == 0) - memset (h->ctr, 0, h->cipher->blocksize); - else - rc = GPG_ERR_INV_ARG; - break; - case 61: /* Disable weak key detection (private). */ - if (h->extraspec->set_extra_info) - rc = h->extraspec->set_extra_info + if (h->spec->set_extra_info) + rc = h->spec->set_extra_info (&h->context.c, CIPHER_INFO_NO_WEAK_KEY, NULL, 0); else rc = GPG_ERR_NOT_SUPPORTED; @@ -1898,23 +1190,23 @@ gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) case 62: /* Return current input vector (private). */ /* This is the input block as used in CFB and OFB mode which has - initially been set as IV. The returned format is: + initially been set as IV. The returned format is: 1 byte Actual length of the block in bytes. n byte The block. If the provided buffer is too short, an error is returned. */ - if (buflen < (1 + h->cipher->blocksize)) + if (buflen < (1 + h->spec->blocksize)) rc = GPG_ERR_TOO_SHORT; else { unsigned char *ivp; unsigned char *dst = buffer; int n = h->unused; - + if (!n) - n = h->cipher->blocksize; - gcry_assert (n <= h->cipher->blocksize); + n = h->spec->blocksize; + gcry_assert (n <= h->spec->blocksize); *dst++ = n; - ivp = h->u_iv.iv + h->cipher->blocksize - n; + ivp = h->u_iv.iv + h->spec->blocksize - n; while (n--) *dst++ = *ivp++; } @@ -1924,22 +1216,22 @@ gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) rc = GPG_ERR_INV_OP; } - return gcry_error (rc); + return rc; } /* Return information about the cipher handle H. CMD is the kind of information requested. BUFFER and NBYTES are reserved for now. - There are no values for CMD yet defined. + There are no values for CMD yet defined. + + The function always returns GPG_ERR_INV_OP. - The fucntion always returns GPG_ERR_INV_OP. - */ -gcry_error_t -gcry_cipher_info (gcry_cipher_hd_t h, int cmd, void *buffer, size_t *nbytes) +gcry_err_code_t +_gcry_cipher_info (gcry_cipher_hd_t h, int cmd, void *buffer, size_t *nbytes) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_err_code_t rc = 0; (void)h; (void)buffer; @@ -1948,10 +1240,10 @@ gcry_cipher_info (gcry_cipher_hd_t h, int cmd, void *buffer, size_t *nbytes) switch (cmd) { default: - err = GPG_ERR_INV_OP; + rc = GPG_ERR_INV_OP; } - return gcry_error (err); + return rc; } /* Return information about the given cipher algorithm ALGO. @@ -1971,63 +1263,64 @@ gcry_cipher_info (gcry_cipher_hd_t h, int cmd, void *buffer, size_t *nbytes) GCRYCTL_TEST_ALGO: Returns 0 if the specified algorithm ALGO is available for use. BUFFER and NBYTES must be zero. - + Note: Because this function is in most cases used to return an integer value, we can make it easier for the caller to just look at the return value. The caller will in all cases consult the value - and thereby detecting whether a error occured or not (i.e. while + and thereby detecting whether a error occurred or not (i.e. while checking the block size) */ -gcry_error_t -gcry_cipher_algo_info (int algo, int what, void *buffer, size_t *nbytes) +gcry_err_code_t +_gcry_cipher_algo_info (int algo, int what, void *buffer, size_t *nbytes) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_err_code_t rc = 0; unsigned int ui; switch (what) { case GCRYCTL_GET_KEYLEN: if (buffer || (! nbytes)) - err = GPG_ERR_CIPHER_ALGO; + rc = GPG_ERR_CIPHER_ALGO; else { ui = cipher_get_keylen (algo); if ((ui > 0) && (ui <= 512)) *nbytes = (size_t) ui / 8; else - /* The only reason is an invalid algo or a strange - blocksize. */ - err = GPG_ERR_CIPHER_ALGO; + /* The only reason for an error is an invalid algo. */ + rc = GPG_ERR_CIPHER_ALGO; } break; case GCRYCTL_GET_BLKLEN: if (buffer || (! nbytes)) - err = GPG_ERR_CIPHER_ALGO; + rc = GPG_ERR_CIPHER_ALGO; else { ui = cipher_get_blocksize (algo); if ((ui > 0) && (ui < 10000)) *nbytes = ui; else - /* The only reason is an invalid algo or a strange - blocksize. */ - err = GPG_ERR_CIPHER_ALGO; + { + /* The only reason is an invalid algo or a strange + blocksize. */ + rc = GPG_ERR_CIPHER_ALGO; + } } break; case GCRYCTL_TEST_ALGO: if (buffer || nbytes) - err = GPG_ERR_INV_ARG; + rc = GPG_ERR_INV_ARG; else - err = check_cipher_algo (algo); + rc = check_cipher_algo (algo); break; default: - err = GPG_ERR_INV_OP; + rc = GPG_ERR_INV_OP; } - return gcry_error (err); + return rc; } @@ -2040,15 +1333,16 @@ gcry_cipher_algo_info (int algo, int what, void *buffer, size_t *nbytes) gcry_cipher_algo_info because it allows for proper type checking. */ size_t -gcry_cipher_get_algo_keylen (int algo) +_gcry_cipher_get_algo_keylen (int algo) { size_t n; - if (gcry_cipher_algo_info (algo, GCRYCTL_GET_KEYLEN, NULL, &n)) + if (_gcry_cipher_algo_info (algo, GCRYCTL_GET_KEYLEN, NULL, &n)) n = 0; return n; } + /* This functions returns the blocklength of the algorithm ALGO counted in octets. On error 0 is returned. @@ -2056,42 +1350,21 @@ gcry_cipher_get_algo_keylen (int algo) gcry_cipher_algo_info because it allows for proper type checking. */ size_t -gcry_cipher_get_algo_blklen (int algo) +_gcry_cipher_get_algo_blklen (int algo) { size_t n; - if (gcry_cipher_algo_info( algo, GCRYCTL_GET_BLKLEN, NULL, &n)) + if (_gcry_cipher_algo_info( algo, GCRYCTL_GET_BLKLEN, NULL, &n)) n = 0; return n; } + /* Explicitly initialize this module. */ gcry_err_code_t _gcry_cipher_init (void) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - REGISTER_DEFAULT_CIPHERS; - - return err; -} - -/* Get a list consisting of the IDs of the loaded cipher modules. If - LIST is zero, write the number of loaded cipher modules to - LIST_LENGTH and return. If LIST is non-zero, the first - *LIST_LENGTH algorithm IDs are stored in LIST, which must be of - according size. In case there are less cipher modules than - *LIST_LENGTH, *LIST_LENGTH is updated to the correct number. */ -gcry_error_t -gcry_cipher_list (int *list, int *list_length) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - ath_mutex_lock (&ciphers_registered_lock); - err = _gcry_module_list (ciphers_registered, list, list_length); - ath_mutex_unlock (&ciphers_registered_lock); - - return err; + return 0; } @@ -2100,34 +1373,21 @@ gcry_cipher_list (int *list, int *list_length) gpg_error_t _gcry_cipher_selftest (int algo, int extended, selftest_report_func_t report) { - gcry_module_t module = NULL; - cipher_extra_spec_t *extraspec = NULL; gcry_err_code_t ec = 0; + gcry_cipher_spec_t *spec; - REGISTER_DEFAULT_CIPHERS; - - ath_mutex_lock (&ciphers_registered_lock); - module = _gcry_module_lookup_id (ciphers_registered, algo); - if (module && !(module->flags & FLAG_MODULE_DISABLED)) - extraspec = module->extraspec; - ath_mutex_unlock (&ciphers_registered_lock); - if (extraspec && extraspec->selftest) - ec = extraspec->selftest (algo, extended, report); + spec = spec_from_algo (algo); + if (spec && !spec->flags.disabled && spec->selftest) + ec = spec->selftest (algo, extended, report); else { ec = GPG_ERR_CIPHER_ALGO; if (report) - report ("cipher", algo, "module", - module && !(module->flags & FLAG_MODULE_DISABLED)? + report ("cipher", algo, "module", + (spec && !spec->flags.disabled)? "no selftest available" : - module? "algorithm disabled" : "algorithm not found"); + spec? "algorithm disabled" : "algorithm not found"); } - if (module) - { - ath_mutex_lock (&ciphers_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&ciphers_registered_lock); - } return gpg_error (ec); } diff --git a/plugins/MirOTR/Libgcrypt/cipher/crc.c b/plugins/MirOTR/Libgcrypt/cipher/crc.c index d04fff8941..1322f0da8c 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/crc.c +++ b/plugins/MirOTR/Libgcrypt/cipher/crc.c @@ -25,7 +25,6 @@ #include <string.h> #include "g10lib.h" -#include "memory.h" #include "cipher.h" #include "bithelp.h" @@ -150,9 +149,12 @@ CRC_CONTEXT; /* CRC32 */ static void -crc32_init (void *context) +crc32_init (void *context, unsigned int flags) { CRC_CONTEXT *ctx = (CRC_CONTEXT *) context; + + (void)flags; + ctx->CRC = 0 ^ 0xffffffffL; } @@ -185,9 +187,12 @@ crc32_final (void *context) /* CRC32 a'la RFC 1510 */ static void -crc32rfc1510_init (void *context) +crc32rfc1510_init (void *context, unsigned int flags) { CRC_CONTEXT *ctx = (CRC_CONTEXT *) context; + + (void)flags; + ctx->CRC = 0; } @@ -238,9 +243,12 @@ crc32rfc1510_final (void *context) #define CRC24_POLY 0x1864cfbL static void -crc24rfc2440_init (void *context) +crc24rfc2440_init (void *context, unsigned int flags) { CRC_CONTEXT *ctx = (CRC_CONTEXT *) context; + + (void)flags; + ctx->CRC = CRC24_INIT; } @@ -273,8 +281,12 @@ crc24rfc2440_final (void *context) ctx->buf[2] = (ctx->CRC ) & 0xFF; } +/* We allow the CRC algorithms even in FIPS mode because they are + actually no cryptographic primitives. */ + gcry_md_spec_t _gcry_digest_spec_crc32 = { + GCRY_MD_CRC32, {0, 1}, "CRC32", NULL, 0, NULL, 4, crc32_init, crc32_write, crc32_final, crc32_read, sizeof (CRC_CONTEXT) @@ -282,6 +294,7 @@ gcry_md_spec_t _gcry_digest_spec_crc32 = gcry_md_spec_t _gcry_digest_spec_crc32_rfc1510 = { + GCRY_MD_CRC32_RFC1510, {0, 1}, "CRC32RFC1510", NULL, 0, NULL, 4, crc32rfc1510_init, crc32_write, crc32rfc1510_final, crc32_read, @@ -290,6 +303,7 @@ gcry_md_spec_t _gcry_digest_spec_crc32_rfc1510 = gcry_md_spec_t _gcry_digest_spec_crc24_rfc2440 = { + GCRY_MD_CRC24_RFC2440, {0, 1}, "CRC24RFC2440", NULL, 0, NULL, 3, crc24rfc2440_init, crc24rfc2440_write, crc24rfc2440_final, crc32_read, diff --git a/plugins/MirOTR/Libgcrypt/cipher/des.c b/plugins/MirOTR/Libgcrypt/cipher/des.c index f91df77713..6611fd3b88 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/des.c +++ b/plugins/MirOTR/Libgcrypt/cipher/des.c @@ -22,7 +22,7 @@ * Bruce Schneier: Applied Cryptography. Second Edition. * John Wiley & Sons, 1996. ISBN 0-471-12845-7. Pages 358 ff. * This implementation is according to the definition of DES in FIPS - * PUB 46-2 from December 1993. + * PUB 46-2 from December 1993. */ @@ -106,7 +106,7 @@ * * if ( (error_msg = selftest()) ) * { - * fprintf(stderr, "An error in the DES/Tripple-DES implementation occured: %s\n", error_msg); + * fprintf(stderr, "An error in the DES/Triple-DES implementation occurred: %s\n", error_msg); * abort(); * } */ @@ -118,6 +118,7 @@ #include "types.h" /* for byte and u32 typedefs */ #include "g10lib.h" #include "cipher.h" +#include "bufhelp.h" #if defined(__GNUC__) && defined(__GNU_LIBRARY__) #define working_memcmp memcmp @@ -388,7 +389,7 @@ static byte weak_keys[64][8] = }; static unsigned char weak_keys_chksum[20] = { 0xD0, 0xCF, 0x07, 0x38, 0x93, 0x70, 0x8A, 0x83, 0x7D, 0xD7, - 0x8A, 0x36, 0x65, 0x29, 0x6C, 0x1F, 0x7C, 0x3F, 0xD3, 0x41 + 0x8A, 0x36, 0x65, 0x29, 0x6C, 0x1F, 0x7C, 0x3F, 0xD3, 0x41 }; @@ -455,14 +456,12 @@ static unsigned char weak_keys_chksum[20] = { * Macros to convert 8 bytes from/to 32bit words. */ #define READ_64BIT_DATA(data, left, right) \ - left = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; \ - right = (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7]; + left = buf_get_be32(data + 0); \ + right = buf_get_be32(data + 4); #define WRITE_64BIT_DATA(data, left, right) \ - data[0] = (left >> 24) &0xff; data[1] = (left >> 16) &0xff; \ - data[2] = (left >> 8) &0xff; data[3] = left &0xff; \ - data[4] = (right >> 24) &0xff; data[5] = (right >> 16) &0xff; \ - data[6] = (right >> 8) &0xff; data[7] = right &0xff; + buf_put_be32(data + 0, left); \ + buf_put_be32(data + 4, right); /* * Handy macros for encryption and decryption of data @@ -888,20 +887,21 @@ selftest (void) if (memcmp (input, result, 8)) return "Triple-DES test failed."; } - + /* * More Triple-DES test. These are testvectors as used by SSLeay, * thanks to Jeroen C. van Gelderen. */ - { - struct { byte key[24]; byte plain[8]; byte cipher[8]; } testdata[] = { + { + static const struct { byte key[24]; byte plain[8]; byte cipher[8]; } + testdata[] = { { { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 }, { 0x95,0xF8,0xA5,0xE5,0xDD,0x31,0xD9,0x00 }, { 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, - + { { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 }, @@ -966,7 +966,7 @@ selftest (void) { tripledes_set3keys (des3, testdata[i].key, testdata[i].key + 8, testdata[i].key + 16); - + tripledes_ecb_encrypt (des3, testdata[i].plain, result); if (memcmp (testdata[i].cipher, result, 8)) return "Triple-DES SSLeay test failed on encryption."; @@ -1047,28 +1047,28 @@ do_tripledes_set_extra_info (void *context, int what, break; default: - ec = GPG_ERR_INV_OP; + ec = GPG_ERR_INV_OP; break; } return ec; } -static void +static unsigned int do_tripledes_encrypt( void *context, byte *outbuf, const byte *inbuf ) { struct _tripledes_ctx *ctx = (struct _tripledes_ctx *) context; tripledes_ecb_encrypt ( ctx, inbuf, outbuf ); - _gcry_burn_stack (32); + return /*burn_stack*/ (32); } -static void +static unsigned int do_tripledes_decrypt( void *context, byte *outbuf, const byte *inbuf ) { struct _tripledes_ctx *ctx = (struct _tripledes_ctx *) context; tripledes_ecb_decrypt ( ctx, inbuf, outbuf ); - _gcry_burn_stack (32); + return /*burn_stack*/ (32); } static gcry_err_code_t @@ -1091,28 +1091,28 @@ do_des_setkey (void *context, const byte *key, unsigned keylen) } -static void +static unsigned int do_des_encrypt( void *context, byte *outbuf, const byte *inbuf ) { struct _des_ctx *ctx = (struct _des_ctx *) context; des_ecb_encrypt ( ctx, inbuf, outbuf ); - _gcry_burn_stack (32); + return /*burn_stack*/ (32); } -static void +static unsigned int do_des_decrypt( void *context, byte *outbuf, const byte *inbuf ) { struct _des_ctx *ctx = (struct _des_ctx *) context; des_ecb_decrypt ( ctx, inbuf, outbuf ); - _gcry_burn_stack (32); + return /*burn_stack*/ (32); } -/* +/* Self-test section. */ @@ -1123,7 +1123,7 @@ selftest_fips (int extended, selftest_report_func_t report) { const char *what; const char *errtxt; - + (void)extended; /* No extended tests available. */ what = "low-level"; @@ -1160,7 +1160,7 @@ run_selftests (int algo, int extended, selftest_report_func_t report) default: ec = GPG_ERR_CIPHER_ALGO; break; - + } return ec; } @@ -1169,6 +1169,7 @@ run_selftests (int algo, int extended, selftest_report_func_t report) gcry_cipher_spec_t _gcry_cipher_spec_des = { + GCRY_CIPHER_DES, {0, 0}, "DES", NULL, NULL, 8, 64, sizeof (struct _des_ctx), do_des_setkey, do_des_encrypt, do_des_decrypt }; @@ -1185,12 +1186,10 @@ static gcry_cipher_oid_spec_t oids_tripledes[] = gcry_cipher_spec_t _gcry_cipher_spec_tripledes = { + GCRY_CIPHER_3DES, {0, 1}, "3DES", NULL, oids_tripledes, 8, 192, sizeof (struct _tripledes_ctx), - do_tripledes_setkey, do_tripledes_encrypt, do_tripledes_decrypt - }; - -cipher_extra_spec_t _gcry_cipher_extraspec_tripledes = - { + do_tripledes_setkey, do_tripledes_encrypt, do_tripledes_decrypt, + NULL, NULL, run_selftests, do_tripledes_set_extra_info }; diff --git a/plugins/MirOTR/Libgcrypt/cipher/dsa-common.c b/plugins/MirOTR/Libgcrypt/cipher/dsa-common.c new file mode 100644 index 0000000000..a5e42a21ce --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/dsa-common.c @@ -0,0 +1,394 @@ +/* dsa-common.c - Common code for DSA + * Copyright (C) 1998, 1999 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "pubkey-internal.h" + + +/* + * Generate a random secret exponent K less than Q. + * Note that ECDSA uses this code also to generate D. + */ +gcry_mpi_t +_gcry_dsa_gen_k (gcry_mpi_t q, int security_level) +{ + gcry_mpi_t k = mpi_alloc_secure (mpi_get_nlimbs (q)); + unsigned int nbits = mpi_get_nbits (q); + unsigned int nbytes = (nbits+7)/8; + char *rndbuf = NULL; + + /* To learn why we don't use mpi_mod to get the requested bit size, + read the paper: "The Insecurity of the Digital Signature + Algorithm with Partially Known Nonces" by Nguyen and Shparlinski. + Journal of Cryptology, New York. Vol 15, nr 3 (2003) */ + + if (DBG_CIPHER) + log_debug ("choosing a random k of %u bits at seclevel %d\n", + nbits, security_level); + for (;;) + { + if ( !rndbuf || nbits < 32 ) + { + xfree (rndbuf); + rndbuf = _gcry_random_bytes_secure (nbytes, security_level); + } + else + { /* Change only some of the higher bits. We could improve + this by directly requesting more memory at the first call + to get_random_bytes() and use these extra bytes here. + However the required management code is more complex and + thus we better use this simple method. */ + char *pp = _gcry_random_bytes_secure (4, security_level); + memcpy (rndbuf, pp, 4); + xfree (pp); + } + _gcry_mpi_set_buffer (k, rndbuf, nbytes, 0); + + /* Make sure we have the requested number of bits. This code + looks a bit funny but it is easy to understand if you + consider that mpi_set_highbit clears all higher bits. We + don't have a clear_highbit, thus we first set the high bit + and then clear it again. */ + if (mpi_test_bit (k, nbits-1)) + mpi_set_highbit (k, nbits-1); + else + { + mpi_set_highbit (k, nbits-1); + mpi_clear_bit (k, nbits-1); + } + + if (!(mpi_cmp (k, q) < 0)) /* check: k < q */ + { + if (DBG_CIPHER) + log_debug ("\tk too large - again\n"); + continue; /* no */ + } + if (!(mpi_cmp_ui (k, 0) > 0)) /* check: k > 0 */ + { + if (DBG_CIPHER) + log_debug ("\tk is zero - again\n"); + continue; /* no */ + } + break; /* okay */ + } + xfree (rndbuf); + + return k; +} + + +/* Turn VALUE into an octet string and store it in an allocated buffer + at R_FRAME. If the resulting octet string is shorter than NBYTES + the result will be left padded with zeroes. If VALUE does not fit + into NBYTES an error code is returned. */ +static gpg_err_code_t +int2octets (unsigned char **r_frame, gcry_mpi_t value, size_t nbytes) +{ + gpg_err_code_t rc; + size_t nframe, noff, n; + unsigned char *frame; + + rc = _gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &nframe, value); + if (rc) + return rc; + if (nframe > nbytes) + return GPG_ERR_TOO_LARGE; /* Value too long to fit into NBYTES. */ + + noff = (nframe < nbytes)? nbytes - nframe : 0; + n = nframe + noff; + frame = mpi_is_secure (value)? xtrymalloc_secure (n) : xtrymalloc (n); + if (!frame) + return gpg_err_code_from_syserror (); + if (noff) + memset (frame, 0, noff); + nframe += noff; + rc = _gcry_mpi_print (GCRYMPI_FMT_USG, frame+noff, nframe-noff, NULL, value); + if (rc) + { + xfree (frame); + return rc; + } + + *r_frame = frame; + return 0; +} + + +/* Connert the bit string BITS of length NBITS into an octet string + with a length of (QBITS+7)/8 bytes. On success store the result at + R_FRAME. */ +static gpg_err_code_t +bits2octets (unsigned char **r_frame, + const void *bits, unsigned int nbits, + gcry_mpi_t q, unsigned int qbits) +{ + gpg_err_code_t rc; + gcry_mpi_t z1; + + /* z1 = bits2int (b) */ + rc = _gcry_mpi_scan (&z1, GCRYMPI_FMT_USG, bits, (nbits+7)/8, NULL); + if (rc) + return rc; + if (nbits > qbits) + mpi_rshift (z1, z1, nbits - qbits); + + /* z2 - z1 mod q */ + if (mpi_cmp (z1, q) >= 0) + mpi_sub (z1, z1, q); + + /* Convert to an octet string. */ + rc = int2octets (r_frame, z1, (qbits+7)/8); + + mpi_free (z1); + return rc; +} + + +/* + * Generate a deterministic secret exponent K less than DSA_Q. H1 is + * the to be signed digest with a length of HLEN bytes. HALGO is the + * algorithm used to create the hash. On success the value for K is + * stored at R_K. + */ +gpg_err_code_t +_gcry_dsa_gen_rfc6979_k (gcry_mpi_t *r_k, + gcry_mpi_t dsa_q, gcry_mpi_t dsa_x, + const unsigned char *h1, unsigned int hlen, + int halgo, unsigned int extraloops) +{ + gpg_err_code_t rc; + unsigned char *V = NULL; + unsigned char *K = NULL; + unsigned char *x_buf = NULL; + unsigned char *h1_buf = NULL; + gcry_md_hd_t hd = NULL; + unsigned char *t = NULL; + gcry_mpi_t k = NULL; + unsigned int tbits, qbits; + int i; + + qbits = mpi_get_nbits (dsa_q); + + if (!qbits || !h1 || !hlen) + return GPG_ERR_EINVAL; + + if (_gcry_md_get_algo_dlen (halgo) != hlen) + return GPG_ERR_DIGEST_ALGO; + + /* Step b: V = 0x01 0x01 0x01 ... 0x01 */ + V = xtrymalloc (hlen); + if (!V) + { + rc = gpg_err_code_from_syserror (); + goto leave; + } + for (i=0; i < hlen; i++) + V[i] = 1; + + /* Step c: K = 0x00 0x00 0x00 ... 0x00 */ + K = xtrycalloc (1, hlen); + if (!K) + { + rc = gpg_err_code_from_syserror (); + goto leave; + } + + rc = int2octets (&x_buf, dsa_x, (qbits+7)/8); + if (rc) + goto leave; + + rc = bits2octets (&h1_buf, h1, hlen*8, dsa_q, qbits); + if (rc) + goto leave; + + /* Create a handle to compute the HMACs. */ + rc = _gcry_md_open (&hd, halgo, (GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC)); + if (rc) + goto leave; + + /* Step d: K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) */ + rc = _gcry_md_setkey (hd, K, hlen); + if (rc) + goto leave; + _gcry_md_write (hd, V, hlen); + _gcry_md_write (hd, "", 1); + _gcry_md_write (hd, x_buf, (qbits+7)/8); + _gcry_md_write (hd, h1_buf, (qbits+7)/8); + memcpy (K, _gcry_md_read (hd, 0), hlen); + + /* Step e: V = HMAC_K(V) */ + rc = _gcry_md_setkey (hd, K, hlen); + if (rc) + goto leave; + _gcry_md_write (hd, V, hlen); + memcpy (V, _gcry_md_read (hd, 0), hlen); + + /* Step f: K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1) */ + rc = _gcry_md_setkey (hd, K, hlen); + if (rc) + goto leave; + _gcry_md_write (hd, V, hlen); + _gcry_md_write (hd, "\x01", 1); + _gcry_md_write (hd, x_buf, (qbits+7)/8); + _gcry_md_write (hd, h1_buf, (qbits+7)/8); + memcpy (K, _gcry_md_read (hd, 0), hlen); + + /* Step g: V = HMAC_K(V) */ + rc = _gcry_md_setkey (hd, K, hlen); + if (rc) + goto leave; + _gcry_md_write (hd, V, hlen); + memcpy (V, _gcry_md_read (hd, 0), hlen); + + /* Step h. */ + t = xtrymalloc ((qbits+7)/8+hlen); + if (!t) + { + rc = gpg_err_code_from_syserror (); + goto leave; + } + + again: + for (tbits = 0; tbits < qbits;) + { + /* V = HMAC_K(V) */ + rc = _gcry_md_setkey (hd, K, hlen); + if (rc) + goto leave; + _gcry_md_write (hd, V, hlen); + memcpy (V, _gcry_md_read (hd, 0), hlen); + + /* T = T || V */ + memcpy (t+(tbits+7)/8, V, hlen); + tbits += 8*hlen; + } + + /* k = bits2int (T) */ + mpi_free (k); + k = NULL; + rc = _gcry_mpi_scan (&k, GCRYMPI_FMT_USG, t, (tbits+7)/8, NULL); + if (rc) + goto leave; + if (tbits > qbits) + mpi_rshift (k, k, tbits - qbits); + + /* Check: k < q and k > 1 */ + if (!(mpi_cmp (k, dsa_q) < 0 && mpi_cmp_ui (k, 0) > 0)) + { + /* K = HMAC_K(V || 0x00) */ + rc = _gcry_md_setkey (hd, K, hlen); + if (rc) + goto leave; + _gcry_md_write (hd, V, hlen); + _gcry_md_write (hd, "", 1); + memcpy (K, _gcry_md_read (hd, 0), hlen); + + /* V = HMAC_K(V) */ + rc = _gcry_md_setkey (hd, K, hlen); + if (rc) + goto leave; + _gcry_md_write (hd, V, hlen); + memcpy (V, _gcry_md_read (hd, 0), hlen); + + goto again; + } + + /* The caller may have requested that we introduce some extra loops. + This is for example useful if the caller wants another value for + K because the last returned one yielded an R of 0. Becuase this + is very unlikely we implement it in a straightforward way. */ + if (extraloops) + { + extraloops--; + + /* K = HMAC_K(V || 0x00) */ + rc = _gcry_md_setkey (hd, K, hlen); + if (rc) + goto leave; + _gcry_md_write (hd, V, hlen); + _gcry_md_write (hd, "", 1); + memcpy (K, _gcry_md_read (hd, 0), hlen); + + /* V = HMAC_K(V) */ + rc = _gcry_md_setkey (hd, K, hlen); + if (rc) + goto leave; + _gcry_md_write (hd, V, hlen); + memcpy (V, _gcry_md_read (hd, 0), hlen); + + goto again; + } + + /* log_mpidump (" k", k); */ + + leave: + xfree (t); + _gcry_md_close (hd); + xfree (h1_buf); + xfree (x_buf); + xfree (K); + xfree (V); + + if (rc) + mpi_free (k); + else + *r_k = k; + return rc; +} + +/* + * Truncate opaque hash value to qbits for DSA. + * Non-opaque input is not truncated, in hope that user + * knows what is passed. It is not possible to correctly + * trucate non-opaque inputs. + */ +gpg_err_code_t +_gcry_dsa_normalize_hash (gcry_mpi_t input, + gcry_mpi_t *out, + unsigned int qbits) +{ + gpg_err_code_t rc = 0; + const void *abuf; + unsigned int abits; + gcry_mpi_t hash; + + if (mpi_is_opaque (input)) + { + abuf = mpi_get_opaque (input, &abits); + rc = _gcry_mpi_scan (&hash, GCRYMPI_FMT_USG, abuf, (abits+7)/8, NULL); + if (rc) + return rc; + if (abits > qbits) + mpi_rshift (hash, hash, abits - qbits); + } + else + hash = input; + + *out = hash; + + return rc; +} diff --git a/plugins/MirOTR/Libgcrypt/cipher/dsa.c b/plugins/MirOTR/Libgcrypt/cipher/dsa.c index ceb94965c5..09cd9693ec 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/dsa.c +++ b/plugins/MirOTR/Libgcrypt/cipher/dsa.c @@ -1,6 +1,7 @@ /* dsa.c - DSA signature algorithm * Copyright (C) 1998, 2000, 2001, 2002, 2003, * 2006, 2008 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH. * * This file is part of Libgcrypt. * @@ -26,6 +27,8 @@ #include "g10lib.h" #include "mpi.h" #include "cipher.h" +#include "pubkey-internal.h" + typedef struct { @@ -55,6 +58,14 @@ typedef struct } dsa_domain_t; +static const char *dsa_names[] = + { + "dsa", + "openpgp-dsa", + NULL, + }; + + /* A sample 1024 bit DSA key used for the selftests. */ static const char sample_secret_key[] = "(private-key" @@ -74,7 +85,7 @@ static const char sample_secret_key[] = " 42CAA7DC289F0C5A9D155F02D3D551DB741A81695B74D4C8F477F9C7838EB0FB#)" " (x #11D54E4ADBD3034160F2CED4B7CD292A4EBF3EC0#)))"; /* A sample 1024 bit DSA key used for the selftests (public only). */ -static const char sample_public_key[] = +static const char sample_public_key[] = "(public-key" " (dsa" " (p #00AD7C0025BA1A15F775F3F2D673718391D00456978D347B33D7B49E7F32EDAB" @@ -94,7 +105,6 @@ static const char sample_public_key[] = -static gcry_mpi_t gen_k (gcry_mpi_t q); static int test_keys (DSA_secret_key *sk, unsigned int qbits); static int check_secret_key (DSA_secret_key *sk); static gpg_err_code_t generate (DSA_secret_key *sk, @@ -103,10 +113,12 @@ static gpg_err_code_t generate (DSA_secret_key *sk, int transient_key, dsa_domain_t *domain, gcry_mpi_t **ret_factors); -static void sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, - DSA_secret_key *skey); -static int verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, +static gpg_err_code_t sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, + DSA_secret_key *skey, int flags, int hashalgo); +static gpg_err_code_t verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_public_key *pkey); +static unsigned int dsa_get_nbits (gcry_sexp_t parms); + static void (*progress_cb) (void *,const char *, int, int, int ); static void *progress_cb_data; @@ -130,78 +142,15 @@ progress (int c) } -/* - * Generate a random secret exponent k less than q. - */ -static gcry_mpi_t -gen_k( gcry_mpi_t q ) -{ - gcry_mpi_t k = mpi_alloc_secure( mpi_get_nlimbs(q) ); - unsigned int nbits = mpi_get_nbits(q); - unsigned int nbytes = (nbits+7)/8; - char *rndbuf = NULL; - - if ( DBG_CIPHER ) - log_debug("choosing a random k "); - for (;;) - { - if( DBG_CIPHER ) - progress('.'); - - if ( !rndbuf || nbits < 32 ) - { - gcry_free(rndbuf); - rndbuf = gcry_random_bytes_secure( (nbits+7)/8, GCRY_STRONG_RANDOM ); - } - else - { /* Change only some of the higher bits. We could improve - this by directly requesting more memory at the first call - to get_random_bytes() and use this the here maybe it is - easier to do this directly in random.c. */ - char *pp = gcry_random_bytes_secure( 4, GCRY_STRONG_RANDOM ); - memcpy( rndbuf,pp, 4 ); - gcry_free(pp); - } - _gcry_mpi_set_buffer( k, rndbuf, nbytes, 0 ); - if ( mpi_test_bit( k, nbits-1 ) ) - mpi_set_highbit( k, nbits-1 ); - else - { - mpi_set_highbit( k, nbits-1 ); - mpi_clear_bit( k, nbits-1 ); - } - - if( !(mpi_cmp( k, q ) < 0) ) /* check: k < q */ - { - if( DBG_CIPHER ) - progress('+'); - continue; /* no */ - } - if( !(mpi_cmp_ui( k, 0 ) > 0) ) /* check: k > 0 */ - { - if( DBG_CIPHER ) - progress('-'); - continue; /* no */ - } - break; /* okay */ - } - gcry_free(rndbuf); - if( DBG_CIPHER ) - progress('\n'); - - return k; -} - - /* Check that a freshly generated key actually works. Returns 0 on success. */ static int test_keys (DSA_secret_key *sk, unsigned int qbits) { int result = -1; /* Default to failure. */ DSA_public_key pk; - gcry_mpi_t data = gcry_mpi_new (qbits); - gcry_mpi_t sig_a = gcry_mpi_new (qbits); - gcry_mpi_t sig_b = gcry_mpi_new (qbits); + gcry_mpi_t data = mpi_new (qbits); + gcry_mpi_t sig_a = mpi_new (qbits); + gcry_mpi_t sig_b = mpi_new (qbits); /* Put the relevant parameters into a public key structure. */ pk.p = sk->p; @@ -210,26 +159,26 @@ test_keys (DSA_secret_key *sk, unsigned int qbits) pk.y = sk->y; /* Create a random plaintext. */ - gcry_mpi_randomize (data, qbits, GCRY_WEAK_RANDOM); + _gcry_mpi_randomize (data, qbits, GCRY_WEAK_RANDOM); /* Sign DATA using the secret key. */ - sign (sig_a, sig_b, data, sk); + sign (sig_a, sig_b, data, sk, 0, 0); /* Verify the signature using the public key. */ - if ( !verify (sig_a, sig_b, data, &pk) ) + if ( verify (sig_a, sig_b, data, &pk) ) goto leave; /* Signature does not match. */ /* Modify the data and check that the signing fails. */ - gcry_mpi_add_ui (data, data, 1); - if ( verify (sig_a, sig_b, data, &pk) ) + mpi_add_ui (data, data, 1); + if ( !verify (sig_a, sig_b, data, &pk) ) goto leave; /* Signature matches but should not. */ result = 0; /* The test succeeded. */ leave: - gcry_mpi_release (sig_b); - gcry_mpi_release (sig_a); - gcry_mpi_release (data); + _gcry_mpi_release (sig_b); + _gcry_mpi_release (sig_a); + _gcry_mpi_release (data); return result; } @@ -247,6 +196,7 @@ static gpg_err_code_t generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, int transient_key, dsa_domain_t *domain, gcry_mpi_t **ret_factors ) { + gpg_err_code_t rc; gcry_mpi_t p; /* the prime */ gcry_mpi_t q; /* the 160 bit prime factor */ gcry_mpi_t g; /* the generator */ @@ -298,7 +248,10 @@ generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, else { /* Generate new domain parameters. */ - p = _gcry_generate_elg_prime (1, nbits, qbits, NULL, ret_factors); + rc = _gcry_generate_elg_prime (1, nbits, qbits, NULL, &p, ret_factors); + if (rc) + return rc; + /* Get q out of factors. */ q = mpi_copy ((*ret_factors)[0]); gcry_assert (mpi_get_nbits (q) == qbits); @@ -314,48 +267,55 @@ generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, { mpi_add_ui (h, h, 1); /* g = h^e mod p */ - gcry_mpi_powm (g, h, e, p); - } + mpi_powm (g, h, e, p); + } while (!mpi_cmp_ui (g, 1)); /* Continue until g != 1. */ } /* Select a random number X with the property: * 0 < x < q-1 + * + * FIXME: Why do we use the requirement x < q-1 ? It should be + * sufficient to test for x < q. FIPS-186-3 check x < q-1 but it + * does not check for 0 < x because it makes sure that Q is unsigned + * and finally adds one to the result so that 0 will never be + * returned. We should replace the code below with _gcry_dsa_gen_k. + * * This must be a very good random number because this is the secret * part. The random quality depends on the transient_key flag. */ random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM; if (DBG_CIPHER) - log_debug("choosing a random x%s", transient_key? " (transient-key)":""); + log_debug("choosing a random x%s\n", transient_key? " (transient-key)":""); gcry_assert( qbits >= 160 ); x = mpi_alloc_secure( mpi_get_nlimbs(q) ); mpi_sub_ui( h, q, 1 ); /* put q-1 into h */ rndbuf = NULL; - do + do { if( DBG_CIPHER ) progress('.'); if( !rndbuf ) - rndbuf = gcry_random_bytes_secure ((qbits+7)/8, random_level); - else + rndbuf = _gcry_random_bytes_secure ((qbits+7)/8, random_level); + else { /* Change only some of the higher bits (= 2 bytes)*/ - char *r = gcry_random_bytes_secure (2, random_level); + char *r = _gcry_random_bytes_secure (2, random_level); memcpy(rndbuf, r, 2 ); - gcry_free(r); + xfree(r); } _gcry_mpi_set_buffer( x, rndbuf, (qbits+7)/8, 0 ); mpi_clear_highbit( x, qbits+1 ); - } + } while ( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, h )<0 ) ); - gcry_free(rndbuf); + xfree(rndbuf); mpi_free( e ); mpi_free( h ); /* y = g^x mod p */ y = mpi_alloc( mpi_get_nlimbs(p) ); - gcry_mpi_powm( y, g, x, p ); + mpi_powm (y, g, x, p); - if( DBG_CIPHER ) + if( DBG_CIPHER ) { progress('\n'); log_mpidump("dsa p", p ); @@ -375,11 +335,11 @@ generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, /* Now we can test our keys (this should never fail!). */ if ( test_keys (sk, qbits) ) { - gcry_mpi_release (sk->p); sk->p = NULL; - gcry_mpi_release (sk->q); sk->q = NULL; - gcry_mpi_release (sk->g); sk->g = NULL; - gcry_mpi_release (sk->y); sk->y = NULL; - gcry_mpi_release (sk->x); sk->x = NULL; + _gcry_mpi_release (sk->p); sk->p = NULL; + _gcry_mpi_release (sk->q); sk->q = NULL; + _gcry_mpi_release (sk->g); sk->g = NULL; + _gcry_mpi_release (sk->y); sk->y = NULL; + _gcry_mpi_release (sk->x); sk->x = NULL; fips_signal_error ("self-test after key generation failed"); return GPG_ERR_SELFTEST_FAILED; } @@ -406,8 +366,8 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, const void *seed; size_t seedlen; } initial_seed = { NULL, NULL, 0 }; - gcry_mpi_t prime_q = NULL; - gcry_mpi_t prime_p = NULL; + gcry_mpi_t prime_q = NULL; + gcry_mpi_t prime_p = NULL; gcry_mpi_t value_g = NULL; /* The generator. */ gcry_mpi_t value_y = NULL; /* g^x mod p */ gcry_mpi_t value_x = NULL; /* The secret exponent. */ @@ -462,20 +422,20 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, /* Get an initial seed value. */ if (deriveparms) { - initial_seed.sexp = gcry_sexp_find_token (deriveparms, "seed", 0); + initial_seed.sexp = sexp_find_token (deriveparms, "seed", 0); if (initial_seed.sexp) - initial_seed.seed = gcry_sexp_nth_data (initial_seed.sexp, 1, + initial_seed.seed = sexp_nth_data (initial_seed.sexp, 1, &initial_seed.seedlen); } - + /* Fixme: Enable 186-3 after it has been approved and after fixing the generation function. */ /* if (use_fips186_2) */ (void)use_fips186_2; - ec = _gcry_generate_fips186_2_prime (nbits, qbits, - initial_seed.seed, + ec = _gcry_generate_fips186_2_prime (nbits, qbits, + initial_seed.seed, initial_seed.seedlen, - &prime_q, &prime_p, + &prime_q, &prime_p, r_counter, r_seed, r_seedlen); /* else */ @@ -483,7 +443,7 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, /* &prime_q, &prime_p, */ /* r_counter, */ /* r_seed, r_seedlen, NULL); */ - gcry_sexp_release (initial_seed.sexp); + sexp_release (initial_seed.sexp); if (ec) goto leave; @@ -493,33 +453,33 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, mpi_sub_ui (value_e, prime_p, 1); mpi_fdiv_q (value_e, value_e, prime_q ); value_g = mpi_alloc_like (prime_p); - value_h = mpi_alloc_set_ui (1); + value_h = mpi_alloc_set_ui (1); do { mpi_add_ui (value_h, value_h, 1); /* g = h^e mod p */ mpi_powm (value_g, value_h, value_e, prime_p); - } + } while (!mpi_cmp_ui (value_g, 1)); /* Continue until g != 1. */ } /* Select a random number x with: 0 < x < q */ - value_x = gcry_mpi_snew (qbits); - do + value_x = mpi_snew (qbits); + do { if( DBG_CIPHER ) progress('.'); - gcry_mpi_randomize (value_x, qbits, GCRY_VERY_STRONG_RANDOM); + _gcry_mpi_randomize (value_x, qbits, GCRY_VERY_STRONG_RANDOM); mpi_clear_highbit (value_x, qbits+1); - } + } while (!(mpi_cmp_ui (value_x, 0) > 0 && mpi_cmp (value_x, prime_q) < 0)); /* y = g^x mod p */ value_y = mpi_alloc_like (prime_p); - gcry_mpi_powm (value_y, value_g, value_x, prime_p); + mpi_powm (value_y, value_g, value_x, prime_p); - if (DBG_CIPHER) + if (DBG_CIPHER) { progress('\n'); log_mpidump("dsa p", prime_p ); @@ -539,22 +499,22 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, *r_h = value_h; value_h = NULL; leave: - gcry_mpi_release (prime_p); - gcry_mpi_release (prime_q); - gcry_mpi_release (value_g); - gcry_mpi_release (value_y); - gcry_mpi_release (value_x); - gcry_mpi_release (value_h); - gcry_mpi_release (value_e); + _gcry_mpi_release (prime_p); + _gcry_mpi_release (prime_q); + _gcry_mpi_release (value_g); + _gcry_mpi_release (value_y); + _gcry_mpi_release (value_x); + _gcry_mpi_release (value_h); + _gcry_mpi_release (value_e); /* As a last step test this keys (this should never fail of course). */ if (!ec && test_keys (sk, qbits) ) { - gcry_mpi_release (sk->p); sk->p = NULL; - gcry_mpi_release (sk->q); sk->q = NULL; - gcry_mpi_release (sk->g); sk->g = NULL; - gcry_mpi_release (sk->y); sk->y = NULL; - gcry_mpi_release (sk->x); sk->x = NULL; + _gcry_mpi_release (sk->p); sk->p = NULL; + _gcry_mpi_release (sk->q); sk->q = NULL; + _gcry_mpi_release (sk->g); sk->g = NULL; + _gcry_mpi_release (sk->y); sk->y = NULL; + _gcry_mpi_release (sk->x); sk->x = NULL; fips_signal_error ("self-test after key generation failed"); ec = GPG_ERR_SELFTEST_FAILED; } @@ -562,9 +522,9 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits, if (ec) { *r_counter = 0; - gcry_free (*r_seed); *r_seed = NULL; + xfree (*r_seed); *r_seed = NULL; *r_seedlen = 0; - gcry_mpi_release (*r_h); *r_h = NULL; + _gcry_mpi_release (*r_h); *r_h = NULL; } return ec; @@ -582,7 +542,7 @@ check_secret_key( DSA_secret_key *sk ) int rc; gcry_mpi_t y = mpi_alloc( mpi_get_nlimbs(sk->y) ); - gcry_mpi_powm( y, sk->g, sk->x, sk->p ); + mpi_powm( y, sk->g, sk->x, sk->p ); rc = !mpi_cmp( y, sk->y ); mpi_free( y ); return rc; @@ -591,20 +551,63 @@ check_secret_key( DSA_secret_key *sk ) /* - Make a DSA signature from HASH and put it into r and s. + Make a DSA signature from INPUT and put it into r and s. + + INPUT may either be a plain MPI or an opaque MPI which is then + internally converted to a plain MPI. FLAGS and HASHALGO may both + be 0 for standard operation mode. + + The return value is 0 on success or an error code. Note that for + backward compatibility the function will not return any error if + FLAGS and HASHALGO are both 0 and INPUT is a plain MPI. */ -static void -sign(gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_secret_key *skey ) +static gpg_err_code_t +sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_secret_key *skey, + int flags, int hashalgo) { + gpg_err_code_t rc; + gcry_mpi_t hash; gcry_mpi_t k; gcry_mpi_t kinv; gcry_mpi_t tmp; + const void *abuf; + unsigned int abits, qbits; + int extraloops = 0; + + qbits = mpi_get_nbits (skey->q); - /* Select a random k with 0 < k < q */ - k = gen_k( skey->q ); + /* Convert the INPUT into an MPI. */ + rc = _gcry_dsa_normalize_hash (input, &hash, qbits); + if (rc) + return rc; + + again: + /* Create the K value. */ + if ((flags & PUBKEY_FLAG_RFC6979) && hashalgo) + { + /* Use Pornin's method for deterministic DSA. If this flag is + set, it is expected that HASH is an opaque MPI with the to be + signed hash. That hash is also used as h1 from 3.2.a. */ + if (!mpi_is_opaque (input)) + { + rc = GPG_ERR_CONFLICT; + goto leave; + } + + abuf = mpi_get_opaque (input, &abits); + rc = _gcry_dsa_gen_rfc6979_k (&k, skey->q, skey->x, + abuf, (abits+7)/8, hashalgo, extraloops); + if (rc) + goto leave; + } + else + { + /* Select a random k with 0 < k < q */ + k = _gcry_dsa_gen_k (skey->q, GCRY_STRONG_RANDOM); + } /* r = (a^k mod p) mod q */ - gcry_mpi_powm( r, skey->g, k, skey->p ); + mpi_powm( r, skey->g, k, skey->p ); mpi_fdiv_r( r, r, skey->q ); /* kinv = k^(-1) mod q */ @@ -620,24 +623,46 @@ sign(gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_secret_key *skey ) mpi_free(k); mpi_free(kinv); mpi_free(tmp); + + if (!mpi_cmp_ui (r, 0)) + { + /* This is a highly unlikely code path. */ + extraloops++; + goto again; + } + + rc = 0; + + leave: + if (hash != input) + mpi_free (hash); + + return rc; } /* Returns true if the signature composed from R and S is valid. */ -static int -verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_public_key *pkey ) +static gpg_err_code_t +verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_public_key *pkey ) { - int rc; + gpg_err_code_t rc = 0; gcry_mpi_t w, u1, u2, v; gcry_mpi_t base[3]; gcry_mpi_t ex[3]; + gcry_mpi_t hash; + unsigned int nbits; if( !(mpi_cmp_ui( r, 0 ) > 0 && mpi_cmp( r, pkey->q ) < 0) ) - return 0; /* assertion 0 < r < q failed */ + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */ if( !(mpi_cmp_ui( s, 0 ) > 0 && mpi_cmp( s, pkey->q ) < 0) ) - return 0; /* assertion 0 < s < q failed */ + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */ + + nbits = mpi_get_nbits (pkey->q); + rc = _gcry_dsa_normalize_hash (input, &hash, nbits); + if (rc) + return rc; w = mpi_alloc( mpi_get_nlimbs(pkey->q) ); u1 = mpi_alloc( mpi_get_nlimbs(pkey->q) ); @@ -660,12 +685,25 @@ verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_public_key *pkey ) mpi_mulpowm( v, base, ex, pkey->p ); mpi_fdiv_r( v, v, pkey->q ); - rc = !mpi_cmp( v, r ); + if (mpi_cmp( v, r )) + { + if (DBG_CIPHER) + { + log_mpidump (" i", input); + log_mpidump (" h", hash); + log_mpidump (" v", v); + log_mpidump (" r", r); + log_mpidump (" s", s); + } + rc = GPG_ERR_BAD_SIGNATURE; + } mpi_free(w); mpi_free(u1); mpi_free(u2); mpi_free(v); + if (hash != input) + mpi_free (hash); return rc; } @@ -676,366 +714,458 @@ verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_public_key *pkey ) *********************************************/ static gcry_err_code_t -dsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue, - const gcry_sexp_t genparms, - gcry_mpi_t *skey, gcry_mpi_t **retfactors, - gcry_sexp_t *r_extrainfo) +dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) { - gpg_err_code_t ec; + gpg_err_code_t rc; + unsigned int nbits; + gcry_sexp_t domainsexp; DSA_secret_key sk; gcry_sexp_t l1; unsigned int qbits = 0; gcry_sexp_t deriveparms = NULL; gcry_sexp_t seedinfo = NULL; - int transient_key = 0; - int use_fips186_2 = 0; - int use_fips186 = 0; + gcry_sexp_t misc_info = NULL; + int flags = 0; dsa_domain_t domain; - - (void)algo; /* No need to check it. */ - (void)evalue; /* Not required for DSA. */ + gcry_mpi_t *factors = NULL; + memset (&sk, 0, sizeof sk); memset (&domain, 0, sizeof domain); - if (genparms) + rc = _gcry_pk_util_get_nbits (genparms, &nbits); + if (rc) + return rc; + + /* Parse the optional flags list. */ + l1 = sexp_find_token (genparms, "flags", 0); + if (l1) { - gcry_sexp_t domainsexp; - - /* Parse the optional qbits element. */ - l1 = gcry_sexp_find_token (genparms, "qbits", 0); - if (l1) + rc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL); + sexp_release (l1); + if (rc) + return rc;\ + } + + /* Parse the optional qbits element. */ + l1 = sexp_find_token (genparms, "qbits", 0); + if (l1) + { + char buf[50]; + const char *s; + size_t n; + + s = sexp_nth_data (l1, 1, &n); + if (!s || n >= DIM (buf) - 1 ) { - char buf[50]; - const char *s; - size_t n; - - s = gcry_sexp_nth_data (l1, 1, &n); - if (!s || n >= DIM (buf) - 1 ) - { - gcry_sexp_release (l1); - return GPG_ERR_INV_OBJ; /* No value or value too large. */ - } - memcpy (buf, s, n); - buf[n] = 0; - qbits = (unsigned int)strtoul (buf, NULL, 0); - gcry_sexp_release (l1); + sexp_release (l1); + return GPG_ERR_INV_OBJ; /* No value or value too large. */ } + memcpy (buf, s, n); + buf[n] = 0; + qbits = (unsigned int)strtoul (buf, NULL, 0); + sexp_release (l1); + } - /* Parse the optional transient-key flag. */ - l1 = gcry_sexp_find_token (genparms, "transient-key", 0); + /* Parse the optional transient-key flag. */ + if (!(flags & PUBKEY_FLAG_TRANSIENT_KEY)) + { + l1 = sexp_find_token (genparms, "transient-key", 0); if (l1) { - transient_key = 1; - gcry_sexp_release (l1); + flags |= PUBKEY_FLAG_TRANSIENT_KEY; + sexp_release (l1); } + } - /* Get the optional derive parameters. */ - deriveparms = gcry_sexp_find_token (genparms, "derive-parms", 0); + /* Get the optional derive parameters. */ + deriveparms = sexp_find_token (genparms, "derive-parms", 0); - /* Parse the optional "use-fips186" flags. */ - l1 = gcry_sexp_find_token (genparms, "use-fips186", 0); + /* Parse the optional "use-fips186" flags. */ + if (!(flags & PUBKEY_FLAG_USE_FIPS186)) + { + l1 = sexp_find_token (genparms, "use-fips186", 0); if (l1) { - use_fips186 = 1; - gcry_sexp_release (l1); + flags |= PUBKEY_FLAG_USE_FIPS186; + sexp_release (l1); } - l1 = gcry_sexp_find_token (genparms, "use-fips186-2", 0); + } + if (!(flags & PUBKEY_FLAG_USE_FIPS186_2)) + { + l1 = sexp_find_token (genparms, "use-fips186-2", 0); if (l1) { - use_fips186_2 = 1; - gcry_sexp_release (l1); + flags |= PUBKEY_FLAG_USE_FIPS186_2; + sexp_release (l1); } + } - /* Check whether domain parameters are given. */ - domainsexp = gcry_sexp_find_token (genparms, "domain", 0); - if (domainsexp) + /* Check whether domain parameters are given. */ + domainsexp = sexp_find_token (genparms, "domain", 0); + if (domainsexp) + { + /* DERIVEPARMS can't be used together with domain parameters. + NBITS abnd QBITS may not be specified because there values + are derived from the domain parameters. */ + if (deriveparms || qbits || nbits) { - /* DERIVEPARMS can't be used together with domain - parameters. NBITS abnd QBITS may not be specified - because there values are derived from the domain - parameters. */ - if (deriveparms || qbits || nbits) - { - gcry_sexp_release (domainsexp); - gcry_sexp_release (deriveparms); - return GPG_ERR_INV_VALUE; - } - - /* Put all domain parameters into the domain object. */ - l1 = gcry_sexp_find_token (domainsexp, "p", 0); - domain.p = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (l1); - l1 = gcry_sexp_find_token (domainsexp, "q", 0); - domain.q = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (l1); - l1 = gcry_sexp_find_token (domainsexp, "g", 0); - domain.g = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (l1); - gcry_sexp_release (domainsexp); - - /* Check that all domain parameters are available. */ - if (!domain.p || !domain.q || !domain.g) - { - gcry_mpi_release (domain.p); - gcry_mpi_release (domain.q); - gcry_mpi_release (domain.g); - gcry_sexp_release (deriveparms); - return GPG_ERR_MISSING_VALUE; - } + sexp_release (domainsexp); + sexp_release (deriveparms); + return GPG_ERR_INV_VALUE; + } - /* Get NBITS and QBITS from the domain parameters. */ - nbits = mpi_get_nbits (domain.p); - qbits = mpi_get_nbits (domain.q); + /* Put all domain parameters into the domain object. */ + l1 = sexp_find_token (domainsexp, "p", 0); + domain.p = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + sexp_release (l1); + l1 = sexp_find_token (domainsexp, "q", 0); + domain.q = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + sexp_release (l1); + l1 = sexp_find_token (domainsexp, "g", 0); + domain.g = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + sexp_release (l1); + sexp_release (domainsexp); + + /* Check that all domain parameters are available. */ + if (!domain.p || !domain.q || !domain.g) + { + _gcry_mpi_release (domain.p); + _gcry_mpi_release (domain.q); + _gcry_mpi_release (domain.g); + sexp_release (deriveparms); + return GPG_ERR_MISSING_VALUE; } + + /* Get NBITS and QBITS from the domain parameters. */ + nbits = mpi_get_nbits (domain.p); + qbits = mpi_get_nbits (domain.q); } - if (deriveparms || use_fips186 || use_fips186_2 || fips_mode ()) + if (deriveparms + || (flags & PUBKEY_FLAG_USE_FIPS186) + || (flags & PUBKEY_FLAG_USE_FIPS186_2) + || fips_mode ()) { int counter; void *seed; size_t seedlen; gcry_mpi_t h_value; - ec = generate_fips186 (&sk, nbits, qbits, deriveparms, use_fips186_2, + rc = generate_fips186 (&sk, nbits, qbits, deriveparms, + !!(flags & PUBKEY_FLAG_USE_FIPS186_2), &domain, &counter, &seed, &seedlen, &h_value); - gcry_sexp_release (deriveparms); - if (!ec && h_value) + if (!rc && h_value) { /* Format the seed-values unless domain parameters are used for which a H_VALUE of NULL is an indication. */ - ec = gpg_err_code (gcry_sexp_build - (&seedinfo, NULL, - "(seed-values(counter %d)(seed %b)(h %m))", - counter, (int)seedlen, seed, h_value)); - if (ec) - { - gcry_mpi_release (sk.p); sk.p = NULL; - gcry_mpi_release (sk.q); sk.q = NULL; - gcry_mpi_release (sk.g); sk.g = NULL; - gcry_mpi_release (sk.y); sk.y = NULL; - gcry_mpi_release (sk.x); sk.x = NULL; - } - gcry_free (seed); - gcry_mpi_release (h_value); + rc = sexp_build (&seedinfo, NULL, + "(seed-values(counter %d)(seed %b)(h %m))", + counter, (int)seedlen, seed, h_value); + xfree (seed); + _gcry_mpi_release (h_value); } } else { - ec = generate (&sk, nbits, qbits, transient_key, &domain, retfactors); + rc = generate (&sk, nbits, qbits, + !!(flags & PUBKEY_FLAG_TRANSIENT_KEY), + &domain, &factors); } - gcry_mpi_release (domain.p); - gcry_mpi_release (domain.q); - gcry_mpi_release (domain.g); - - if (!ec) + if (!rc) { - skey[0] = sk.p; - skey[1] = sk.q; - skey[2] = sk.g; - skey[3] = sk.y; - skey[4] = sk.x; - - if (!r_extrainfo) - { - /* Old style interface - return the factors - if any - at - retfactors. */ - } - else if (!*retfactors && !seedinfo) - { - /* No factors and no seedinfo, thus there is nothing to return. */ - *r_extrainfo = NULL; - } + /* Put the factors into MISC_INFO. Note that the factors are + not confidential thus we can store them in standard memory. */ + int nfactors, i, j; + char *p; + char *format = NULL; + void **arg_list = NULL; + + for (nfactors=0; factors && factors[nfactors]; nfactors++) + ; + /* Allocate space for the format string: + "(misc-key-info%S(pm1-factors%m))" + with one "%m" for each factor and construct it. */ + format = xtrymalloc (50 + 2*nfactors); + if (!format) + rc = gpg_err_code_from_syserror (); else { - /* Put the factors into extrainfo and set retfactors to NULL - to make use of the new interface. Note that the factors - are not confidential thus we can store them in standard - memory. */ - int nfactors, i, j; - char *p; - char *format = NULL; - void **arg_list = NULL; - - for (nfactors=0; *retfactors && (*retfactors)[nfactors]; nfactors++) - ; - /* Allocate space for the format string: - "(misc-key-info%S(pm1-factors%m))" - with one "%m" for each factor and construct it. */ - format = gcry_malloc (50 + 2*nfactors); - if (!format) - ec = gpg_err_code_from_syserror (); - else + p = stpcpy (format, "(misc-key-info"); + if (seedinfo) + p = stpcpy (p, "%S"); + if (nfactors) { - p = stpcpy (format, "(misc-key-info"); - if (seedinfo) - p = stpcpy (p, "%S"); - if (nfactors) - { - p = stpcpy (p, "(pm1-factors"); - for (i=0; i < nfactors; i++) - p = stpcpy (p, "%m"); - p = stpcpy (p, ")"); - } + p = stpcpy (p, "(pm1-factors"); + for (i=0; i < nfactors; i++) + p = stpcpy (p, "%m"); p = stpcpy (p, ")"); - - /* Allocate space for the list of factors plus one for - an S-expression plus an extra NULL entry for safety - and fill it with the factors. */ - arg_list = gcry_calloc (nfactors+1+1, sizeof *arg_list); - if (!arg_list) - ec = gpg_err_code_from_syserror (); - else - { - i = 0; - if (seedinfo) - arg_list[i++] = &seedinfo; - for (j=0; j < nfactors; j++) - arg_list[i++] = (*retfactors) + j; - arg_list[i] = NULL; - - ec = gpg_err_code (gcry_sexp_build_array - (r_extrainfo, NULL, format, arg_list)); - } - } - - gcry_free (arg_list); - gcry_free (format); - for (i=0; i < nfactors; i++) - { - gcry_mpi_release ((*retfactors)[i]); - (*retfactors)[i] = NULL; } - gcry_free (*retfactors); - *retfactors = NULL; - if (ec) + p = stpcpy (p, ")"); + + /* Allocate space for the list of factors plus one for the + seedinfo s-exp plus an extra NULL entry for safety and + fill it with the factors. */ + arg_list = xtrycalloc (nfactors+1+1, sizeof *arg_list); + if (!arg_list) + rc = gpg_err_code_from_syserror (); + else { - for (i=0; i < 5; i++) - { - gcry_mpi_release (skey[i]); - skey[i] = NULL; - } + i = 0; + if (seedinfo) + arg_list[i++] = &seedinfo; + for (j=0; j < nfactors; j++) + arg_list[i++] = factors + j; + arg_list[i] = NULL; + + rc = sexp_build_array (&misc_info, NULL, format, arg_list); } } - } - - gcry_sexp_release (seedinfo); - return ec; -} + xfree (arg_list); + xfree (format); + } -static gcry_err_code_t -dsa_generate (int algo, unsigned int nbits, unsigned long evalue, - gcry_mpi_t *skey, gcry_mpi_t **retfactors) -{ - (void)evalue; - return dsa_generate_ext (algo, nbits, 0, NULL, skey, retfactors, NULL); + if (!rc) + rc = sexp_build (r_skey, NULL, + "(key-data" + " (public-key" + " (dsa(p%m)(q%m)(g%m)(y%m)))" + " (private-key" + " (dsa(p%m)(q%m)(g%m)(y%m)(x%m)))" + " %S)", + sk.p, sk.q, sk.g, sk.y, + sk.p, sk.q, sk.g, sk.y, sk.x, + misc_info); + + + _gcry_mpi_release (sk.p); + _gcry_mpi_release (sk.q); + _gcry_mpi_release (sk.g); + _gcry_mpi_release (sk.y); + _gcry_mpi_release (sk.x); + + _gcry_mpi_release (domain.p); + _gcry_mpi_release (domain.q); + _gcry_mpi_release (domain.g); + + sexp_release (seedinfo); + sexp_release (misc_info); + sexp_release (deriveparms); + if (factors) + { + gcry_mpi_t *mp; + for (mp = factors; *mp; mp++) + mpi_free (*mp); + xfree (factors); + } + return rc; } static gcry_err_code_t -dsa_check_secret_key (int algo, gcry_mpi_t *skey) +dsa_check_secret_key (gcry_sexp_t keyparms) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - DSA_secret_key sk; + gcry_err_code_t rc; + DSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL}; - (void)algo; + rc = _gcry_sexp_extract_param (keyparms, NULL, "pqgyx", + &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, + NULL); + if (rc) + goto leave; - if ((! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3]) || (! skey[4])) - err = GPG_ERR_BAD_MPI; - else - { - sk.p = skey[0]; - sk.q = skey[1]; - sk.g = skey[2]; - sk.y = skey[3]; - sk.x = skey[4]; - if (! check_secret_key (&sk)) - err = GPG_ERR_BAD_SECKEY; - } + if (!check_secret_key (&sk)) + rc = GPG_ERR_BAD_SECKEY; - return err; + leave: + _gcry_mpi_release (sk.p); + _gcry_mpi_release (sk.q); + _gcry_mpi_release (sk.g); + _gcry_mpi_release (sk.y); + _gcry_mpi_release (sk.x); + if (DBG_CIPHER) + log_debug ("dsa_testkey => %s\n", gpg_strerror (rc)); + return rc; } static gcry_err_code_t -dsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey) +dsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - DSA_secret_key sk; + gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_mpi_t data = NULL; + DSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL}; + gcry_mpi_t sig_r = NULL; + gcry_mpi_t sig_s = NULL; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN, + dsa_get_nbits (keyparms)); + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_mpidump ("dsa_sign data", data); - (void)algo; + /* Extract the key. */ + rc = _gcry_sexp_extract_param (keyparms, NULL, "pqgyx", + &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_mpidump ("dsa_sign p", sk.p); + log_mpidump ("dsa_sign q", sk.q); + log_mpidump ("dsa_sign g", sk.g); + log_mpidump ("dsa_sign y", sk.y); + if (!fips_mode ()) + log_mpidump ("dsa_sign x", sk.x); + } - if ((! data) - || (! skey[0]) || (! skey[1]) || (! skey[2]) - || (! skey[3]) || (! skey[4])) - err = GPG_ERR_BAD_MPI; - else + sig_r = mpi_new (0); + sig_s = mpi_new (0); + rc = sign (sig_r, sig_s, data, &sk, ctx.flags, ctx.hash_algo); + if (rc) + goto leave; + if (DBG_CIPHER) { - sk.p = skey[0]; - sk.q = skey[1]; - sk.g = skey[2]; - sk.y = skey[3]; - sk.x = skey[4]; - resarr[0] = mpi_alloc (mpi_get_nlimbs (sk.p)); - resarr[1] = mpi_alloc (mpi_get_nlimbs (sk.p)); - sign (resarr[0], resarr[1], data, &sk); + log_mpidump ("dsa_sign sig_r", sig_r); + log_mpidump ("dsa_sign sig_s", sig_s); } - return err; + rc = sexp_build (r_sig, NULL, "(sig-val(dsa(r%M)(s%M)))", sig_r, sig_s); + + leave: + _gcry_mpi_release (sig_r); + _gcry_mpi_release (sig_s); + _gcry_mpi_release (sk.p); + _gcry_mpi_release (sk.q); + _gcry_mpi_release (sk.g); + _gcry_mpi_release (sk.y); + _gcry_mpi_release (sk.x); + _gcry_mpi_release (data); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("dsa_sign => %s\n", gpg_strerror (rc)); + return rc; } + static gcry_err_code_t -dsa_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey, - int (*cmp) (void *, gcry_mpi_t), void *opaquev) +dsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - DSA_public_key pk; - - (void)algo; - (void)cmp; - (void)opaquev; + gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_sexp_t l1 = NULL; + gcry_mpi_t sig_r = NULL; + gcry_mpi_t sig_s = NULL; + gcry_mpi_t data = NULL; + DSA_public_key pk = { NULL, NULL, NULL, NULL }; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY, + dsa_get_nbits (s_keyparms)); + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_mpidump ("dsa_verify data", data); + + /* Extract the signature value. */ + rc = _gcry_pk_util_preparse_sigval (s_sig, dsa_names, &l1, NULL); + if (rc) + goto leave; + rc = _gcry_sexp_extract_param (l1, NULL, "rs", &sig_r, &sig_s, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_mpidump ("dsa_verify s_r", sig_r); + log_mpidump ("dsa_verify s_s", sig_s); + } - if ((! data[0]) || (! data[1]) || (! hash) - || (! pkey[0]) || (! pkey[1]) || (! pkey[2]) || (! pkey[3])) - err = GPG_ERR_BAD_MPI; - else + /* Extract the key. */ + rc = _gcry_sexp_extract_param (s_keyparms, NULL, "pqgy", + &pk.p, &pk.q, &pk.g, &pk.y, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) { - pk.p = pkey[0]; - pk.q = pkey[1]; - pk.g = pkey[2]; - pk.y = pkey[3]; - if (! verify (data[0], data[1], hash, &pk)) - err = GPG_ERR_BAD_SIGNATURE; + log_mpidump ("dsa_verify p", pk.p); + log_mpidump ("dsa_verify q", pk.q); + log_mpidump ("dsa_verify g", pk.g); + log_mpidump ("dsa_verify y", pk.y); } - return err; + + /* Verify the signature. */ + rc = verify (sig_r, sig_s, data, &pk); + + leave: + _gcry_mpi_release (pk.p); + _gcry_mpi_release (pk.q); + _gcry_mpi_release (pk.g); + _gcry_mpi_release (pk.y); + _gcry_mpi_release (data); + _gcry_mpi_release (sig_r); + _gcry_mpi_release (sig_s); + sexp_release (l1); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("dsa_verify => %s\n", rc?gpg_strerror (rc):"Good"); + return rc; } +/* Return the number of bits for the key described by PARMS. On error + * 0 is returned. The format of PARMS starts with the algorithm name; + * for example: + * + * (dsa + * (p <mpi>) + * (q <mpi>) + * (g <mpi>) + * (y <mpi>)) + * + * More parameters may be given but we only need P here. + */ static unsigned int -dsa_get_nbits (int algo, gcry_mpi_t *pkey) +dsa_get_nbits (gcry_sexp_t parms) { - (void)algo; - - return mpi_get_nbits (pkey[0]); + gcry_sexp_t l1; + gcry_mpi_t p; + unsigned int nbits; + + l1 = sexp_find_token (parms, "p", 1); + if (!l1) + return 0; /* Parameter P not found. */ + + p = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + sexp_release (l1); + nbits = p? mpi_get_nbits (p) : 0; + _gcry_mpi_release (p); + return nbits; } -/* +/* Self-test section. */ static const char * selftest_sign_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) { - static const char sample_data[] = - "(data (flags pkcs1)" - " (hash sha1 #a0b1c2d3e4f500102030405060708090a1b2c3d4#))"; - static const char sample_data_bad[] = - "(data (flags pkcs1)" - " (hash sha1 #a0b1c2d3e4f510102030405060708090a1b2c3d4#))"; + static const char sample_data[] = + "(data (flags raw)" + " (value #a0b1c2d3e4f500102030405060708090a1b2c3d4#))"; + static const char sample_data_bad[] = + "(data (flags raw)" + " (value #a0b1c2d3e4f510102030405060708090a1b2c3d4#))"; const char *errtxt = NULL; gcry_error_t err; @@ -1043,30 +1173,29 @@ selftest_sign_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) gcry_sexp_t data_bad = NULL; gcry_sexp_t sig = NULL; - err = gcry_sexp_sscan (&data, NULL, - sample_data, strlen (sample_data)); + err = sexp_sscan (&data, NULL, sample_data, strlen (sample_data)); if (!err) - err = gcry_sexp_sscan (&data_bad, NULL, - sample_data_bad, strlen (sample_data_bad)); + err = sexp_sscan (&data_bad, NULL, + sample_data_bad, strlen (sample_data_bad)); if (err) { errtxt = "converting data failed"; goto leave; } - err = gcry_pk_sign (&sig, data, skey); + err = _gcry_pk_sign (&sig, data, skey); if (err) { errtxt = "signing failed"; goto leave; } - err = gcry_pk_verify (sig, data, pkey); + err = _gcry_pk_verify (sig, data, pkey); if (err) { errtxt = "verify failed"; goto leave; } - err = gcry_pk_verify (sig, data_bad, pkey); + err = _gcry_pk_verify (sig, data_bad, pkey); if (gcry_err_code (err) != GPG_ERR_BAD_SIGNATURE) { errtxt = "bad signature not detected"; @@ -1075,9 +1204,9 @@ selftest_sign_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) leave: - gcry_sexp_release (sig); - gcry_sexp_release (data_bad); - gcry_sexp_release (data); + sexp_release (sig); + sexp_release (data_bad); + sexp_release (data); return errtxt; } @@ -1093,22 +1222,21 @@ selftests_dsa (selftest_report_func_t report) /* Convert the S-expressions into the internal representation. */ what = "convert"; - err = gcry_sexp_sscan (&skey, NULL, - sample_secret_key, strlen (sample_secret_key)); + err = sexp_sscan (&skey, NULL, sample_secret_key, strlen (sample_secret_key)); if (!err) - err = gcry_sexp_sscan (&pkey, NULL, - sample_public_key, strlen (sample_public_key)); + err = sexp_sscan (&pkey, NULL, + sample_public_key, strlen (sample_public_key)); if (err) { - errtxt = gcry_strerror (err); + errtxt = _gcry_strerror (err); goto failed; } what = "key consistency"; - err = gcry_pk_testkey (skey); + err = _gcry_pk_testkey (skey); if (err) { - errtxt = gcry_strerror (err); + errtxt = _gcry_strerror (err); goto failed; } @@ -1117,13 +1245,13 @@ selftests_dsa (selftest_report_func_t report) if (errtxt) goto failed; - gcry_sexp_release (pkey); - gcry_sexp_release (skey); + sexp_release (pkey); + sexp_release (skey); return 0; /* Succeeded. */ failed: - gcry_sexp_release (pkey); - gcry_sexp_release (skey); + sexp_release (pkey); + sexp_release (skey); if (report) report ("pubkey", GCRY_PK_DSA, what, errtxt); return GPG_ERR_SELFTEST_FAILED; @@ -1146,7 +1274,7 @@ run_selftests (int algo, int extended, selftest_report_func_t report) default: ec = GPG_ERR_PUBKEY_ALGO; break; - + } return ec; } @@ -1154,29 +1282,18 @@ run_selftests (int algo, int extended, selftest_report_func_t report) -static const char *dsa_names[] = - { - "dsa", - "openpgp-dsa", - NULL, - }; - gcry_pk_spec_t _gcry_pubkey_spec_dsa = { - "DSA", dsa_names, - "pqgy", "pqgyx", "", "rs", "pqgy", + GCRY_PK_DSA, { 0, 1 }, GCRY_PK_USAGE_SIGN, + "DSA", dsa_names, + "pqgy", "pqgyx", "", "rs", "pqgy", dsa_generate, dsa_check_secret_key, NULL, NULL, dsa_sign, dsa_verify, - dsa_get_nbits + dsa_get_nbits, + run_selftests }; -pk_extra_spec_t _gcry_pubkey_extraspec_dsa = - { - run_selftests, - dsa_generate_ext - }; - diff --git a/plugins/MirOTR/Libgcrypt/cipher/ecc-common.h b/plugins/MirOTR/Libgcrypt/cipher/ecc-common.h new file mode 100644 index 0000000000..f066b4b785 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/ecc-common.h @@ -0,0 +1,142 @@ +/* ecc-common.h - Declarations of common ECC code + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef GCRY_ECC_COMMON_H +#define GCRY_ECC_COMMON_H + + +/* Definition of a curve. */ +typedef struct +{ + enum gcry_mpi_ec_models model;/* The model descrinbing this curve. */ + enum ecc_dialects dialect; /* The dialect used with the curve. */ + gcry_mpi_t p; /* Prime specifying the field GF(p). */ + gcry_mpi_t a; /* First coefficient of the Weierstrass equation. */ + gcry_mpi_t b; /* Second coefficient of the Weierstrass equation. + or d as used by Twisted Edwards curves. */ + mpi_point_struct G; /* Base point (generator). */ + gcry_mpi_t n; /* Order of G. */ + const char *name; /* Name of the curve or NULL. */ +} elliptic_curve_t; + + +typedef struct +{ + elliptic_curve_t E; + mpi_point_struct Q; /* Q = [d]G */ +} ECC_public_key; + + +typedef struct +{ + elliptic_curve_t E; + mpi_point_struct Q; + gcry_mpi_t d; +} ECC_secret_key; + + + +/* Set the value from S into D. */ +static inline void +point_set (mpi_point_t d, mpi_point_t s) +{ + mpi_set (d->x, s->x); + mpi_set (d->y, s->y); + mpi_set (d->z, s->z); +} + +#define point_init(a) _gcry_mpi_point_init ((a)) +#define point_free(a) _gcry_mpi_point_free_parts ((a)) + + +/*-- ecc-curves.c --*/ +gpg_err_code_t _gcry_ecc_fill_in_curve (unsigned int nbits, + const char *name, + elliptic_curve_t *curve, + unsigned int *r_nbits); +gpg_err_code_t _gcry_ecc_update_curve_param (const char *name, + enum gcry_mpi_ec_models *model, + enum ecc_dialects *dialect, + gcry_mpi_t *p, gcry_mpi_t *a, + gcry_mpi_t *b, gcry_mpi_t *g, + gcry_mpi_t *n); + +const char *_gcry_ecc_get_curve (gcry_sexp_t keyparms, + int iterator, + unsigned int *r_nbits); +gcry_sexp_t _gcry_ecc_get_param_sexp (const char *name); + +/*-- ecc-misc.c --*/ +void _gcry_ecc_curve_free (elliptic_curve_t *E); +elliptic_curve_t _gcry_ecc_curve_copy (elliptic_curve_t E); +const char *_gcry_ecc_model2str (enum gcry_mpi_ec_models model); +const char *_gcry_ecc_dialect2str (enum ecc_dialects dialect); +gcry_mpi_t _gcry_ecc_ec2os (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t p); +gcry_err_code_t _gcry_ecc_os2ec (mpi_point_t result, gcry_mpi_t value); + +mpi_point_t _gcry_ecc_compute_public (mpi_point_t Q, mpi_ec_t ec, + mpi_point_t G, gcry_mpi_t d); + +/*-- ecc.c --*/ + +/*-- ecc-ecdsa.c --*/ +gpg_err_code_t _gcry_ecc_ecdsa_sign (gcry_mpi_t input, ECC_secret_key *skey, + gcry_mpi_t r, gcry_mpi_t s, + int flags, int hashalgo); +gpg_err_code_t _gcry_ecc_ecdsa_verify (gcry_mpi_t input, ECC_public_key *pkey, + gcry_mpi_t r, gcry_mpi_t s); + +/*-- ecc-eddsa.c --*/ +gpg_err_code_t _gcry_ecc_eddsa_recover_x (gcry_mpi_t x, gcry_mpi_t y, int sign, + mpi_ec_t ec); +gpg_err_code_t _gcry_ecc_eddsa_encodepoint (mpi_point_t point, mpi_ec_t ctx, + gcry_mpi_t x, gcry_mpi_t y, + int with_prefix, + unsigned char **r_buffer, + unsigned int *r_buflen); +gpg_err_code_t _gcry_ecc_eddsa_ensure_compact (gcry_mpi_t value, + unsigned int nbits); +gpg_err_code_t _gcry_ecc_eddsa_decodepoint (gcry_mpi_t pk, mpi_ec_t ctx, + mpi_point_t result, + unsigned char **r_encpk, + unsigned int *r_encpklen); +gpg_err_code_t _gcry_ecc_eddsa_compute_h_d (unsigned char **r_digest, + gcry_mpi_t d, mpi_ec_t ec); + +gpg_err_code_t _gcry_ecc_eddsa_genkey (ECC_secret_key *sk, + elliptic_curve_t *E, + mpi_ec_t ctx, + gcry_random_level_t random_level); +gpg_err_code_t _gcry_ecc_eddsa_sign (gcry_mpi_t input, + ECC_secret_key *sk, + gcry_mpi_t r_r, gcry_mpi_t s, + int hashalgo, gcry_mpi_t pk); +gpg_err_code_t _gcry_ecc_eddsa_verify (gcry_mpi_t input, + ECC_public_key *pk, + gcry_mpi_t r, gcry_mpi_t s, + int hashalgo, gcry_mpi_t pkmpi); + +/*-- ecc-gost.c --*/ +gpg_err_code_t _gcry_ecc_gost_sign (gcry_mpi_t input, ECC_secret_key *skey, + gcry_mpi_t r, gcry_mpi_t s); +gpg_err_code_t _gcry_ecc_gost_verify (gcry_mpi_t input, ECC_public_key *pkey, + gcry_mpi_t r, gcry_mpi_t s); + + +#endif /*GCRY_ECC_COMMON_H*/ diff --git a/plugins/MirOTR/Libgcrypt/cipher/ecc-curves.c b/plugins/MirOTR/Libgcrypt/cipher/ecc-curves.c new file mode 100644 index 0000000000..306f2adda2 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/ecc-curves.c @@ -0,0 +1,1162 @@ +/* ecc-curves.c - Elliptic Curve parameter mangement + * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "context.h" +#include "ec-context.h" +#include "pubkey-internal.h" +#include "ecc-common.h" + + +/* This tables defines aliases for curve names. */ +static const struct +{ + const char *name; /* Our name. */ + const char *other; /* Other name. */ +} curve_aliases[] = + { + /*{ "Curve25519", "1.3.6.1.4.1.3029.1.5.1" },*/ + { "Ed25519", "1.3.6.1.4.1.11591.15.1" }, + + { "NIST P-192", "1.2.840.10045.3.1.1" }, /* X9.62 OID */ + { "NIST P-192", "prime192v1" }, /* X9.62 name. */ + { "NIST P-192", "secp192r1" }, /* SECP name. */ + { "NIST P-192", "nistp192" }, /* rfc5656. */ + + { "NIST P-224", "secp224r1" }, + { "NIST P-224", "1.3.132.0.33" }, /* SECP OID. */ + { "NIST P-224", "nistp224" }, /* rfc5656. */ + + { "NIST P-256", "1.2.840.10045.3.1.7" }, /* From NIST SP 800-78-1. */ + { "NIST P-256", "prime256v1" }, + { "NIST P-256", "secp256r1" }, + { "NIST P-256", "nistp256" }, /* rfc5656. */ + + { "NIST P-384", "secp384r1" }, + { "NIST P-384", "1.3.132.0.34" }, + { "NIST P-384", "nistp384" }, /* rfc5656. */ + + { "NIST P-521", "secp521r1" }, + { "NIST P-521", "1.3.132.0.35" }, + { "NIST P-521", "nistp521" }, /* rfc5656. */ + + { "brainpoolP160r1", "1.3.36.3.3.2.8.1.1.1" }, + { "brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3" }, + { "brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5" }, + { "brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7" }, + { "brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9" }, + { "brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11"}, + { "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13"}, + + { NULL, NULL} + }; + + +typedef struct +{ + const char *desc; /* Description of the curve. */ + unsigned int nbits; /* Number of bits. */ + unsigned int fips:1; /* True if this is a FIPS140-2 approved curve. */ + + /* The model describing this curve. This is mainly used to select + the group equation. */ + enum gcry_mpi_ec_models model; + + /* The actual ECC dialect used. This is used for curve specific + optimizations and to select encodings etc. */ + enum ecc_dialects dialect; + + const char *p; /* The prime defining the field. */ + const char *a, *b; /* The coefficients. For Twisted Edwards + Curves b is used for d. */ + const char *n; /* The order of the base point. */ + const char *g_x, *g_y; /* Base point. */ +} ecc_domain_parms_t; + + +/* This static table defines all available curves. */ +static const ecc_domain_parms_t domain_parms[] = + { + { + /* (-x^2 + y^2 = 1 + dx^2y^2) */ + "Ed25519", 256, 0, + MPI_EC_TWISTEDEDWARDS, ECC_DIALECT_ED25519, + "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED", + "-0x01", + "-0x2DFC9311D490018C7338BF8688861767FF8FF5B2BEBE27548A14B235ECA6874A", + "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED", + "0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A", + "0x6666666666666666666666666666666666666666666666666666666666666658" + }, + { + "NIST P-192", 192, 1, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xfffffffffffffffffffffffffffffffeffffffffffffffff", + "0xfffffffffffffffffffffffffffffffefffffffffffffffc", + "0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", + "0xffffffffffffffffffffffff99def836146bc9b1b4d22831", + + "0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012", + "0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811" + }, + { + "NIST P-224", 224, 1, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xffffffffffffffffffffffffffffffff000000000000000000000001", + "0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe", + "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", + "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d" , + + "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", + "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34" + }, + { + "NIST P-256", 256, 1, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff", + "0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc", + "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", + "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + + "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", + "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5" + }, + { + "NIST P-384", 384, 1, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe" + "ffffffff0000000000000000ffffffff", + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe" + "ffffffff0000000000000000fffffffc", + "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a" + "c656398d8a2ed19d2a85c8edd3ec2aef", + "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf" + "581a0db248b0a77aecec196accc52973", + + "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38" + "5502f25dbf55296c3a545e3872760ab7", + "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0" + "0a60b1ce1d7e819d7a431d7c90ea0e5f" + }, + { + "NIST P-521", 521, 1, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc", + "0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef10" + "9e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", + "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "ffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409", + + "0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d" + "3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", + "0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e" + "662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650" + }, + + { "brainpoolP160r1", 160, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xe95e4a5f737059dc60dfc7ad95b3d8139515620f", + "0x340e7be2a280eb74e2be61bada745d97e8f7c300", + "0x1e589a8595423412134faa2dbdec95c8d8675e58", + "0xe95e4a5f737059dc60df5991d45029409e60fc09", + "0xbed5af16ea3f6a4f62938c4631eb5af7bdbcdbc3", + "0x1667cb477a1a8ec338f94741669c976316da6321" + }, + + { "brainpoolP192r1", 192, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xc302f41d932a36cda7a3463093d18db78fce476de1a86297", + "0x6a91174076b1e0e19c39c031fe8685c1cae040e5c69a28ef", + "0x469a28ef7c28cca3dc721d044f4496bcca7ef4146fbf25c9", + "0xc302f41d932a36cda7a3462f9e9e916b5be8f1029ac4acc1", + "0xc0a0647eaab6a48753b033c56cb0f0900a2f5c4853375fd6", + "0x14b690866abd5bb88b5f4828c1490002e6773fa2fa299b8f" + }, + + { "brainpoolP224r1", 224, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xd7c134aa264366862a18302575d1d787b09f075797da89f57ec8c0ff", + "0x68a5e62ca9ce6c1c299803a6c1530b514e182ad8b0042a59cad29f43", + "0x2580f63ccfe44138870713b1a92369e33e2135d266dbb372386c400b", + "0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7939f", + "0x0d9029ad2c7e5cf4340823b2a87dc68c9e4ce3174c1e6efdee12c07d", + "0x58aa56f772c0726f24c6b89e4ecdac24354b9e99caa3f6d3761402cd" + }, + + { "brainpoolP256r1", 256, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xa9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e5377", + "0x7d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9", + "0x26dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b6", + "0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a7", + "0x8bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262", + "0x547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f046997" + }, + + { "brainpoolP320r1", 320, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xd35e472036bc4fb7e13c785ed201e065f98fcfa6f6f40def4f92b9ec7893ec28" + "fcd412b1f1b32e27", + "0x3ee30b568fbab0f883ccebd46d3f3bb8a2a73513f5eb79da66190eb085ffa9f4" + "92f375a97d860eb4", + "0x520883949dfdbc42d3ad198640688a6fe13f41349554b49acc31dccd88453981" + "6f5eb4ac8fb1f1a6", + "0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e9" + "8691555b44c59311", + "0x43bd7e9afb53d8b85289bcc48ee5bfe6f20137d10a087eb6e7871e2a10a599c7" + "10af8d0d39e20611", + "0x14fdd05545ec1cc8ab4093247f77275e0743ffed117182eaa9c77877aaac6ac7" + "d35245d1692e8ee1" + }, + + { "brainpoolP384r1", 384, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b412b1da197fb71123" + "acd3a729901d1a71874700133107ec53", + "0x7bc382c63d8c150c3c72080ace05afa0c2bea28e4fb22787139165efba91f90f" + "8aa5814a503ad4eb04a8c7dd22ce2826", + "0x04a8c7dd22ce28268b39b55416f0447c2fb77de107dcd2a62e880ea53eeb62d5" + "7cb4390295dbc9943ab78696fa504c11", + "0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7" + "cf3ab6af6b7fc3103b883202e9046565", + "0x1d1c64f068cf45ffa2a63a81b7c13f6b8847a3e77ef14fe3db7fcafe0cbd10e8" + "e826e03436d646aaef87b2e247d4af1e", + "0x8abe1d7520f9c2a45cb1eb8e95cfd55262b70b29feec5864e19c054ff9912928" + "0e4646217791811142820341263c5315" + }, + + { "brainpoolP512r1", 512, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330871" + "7d4d9b009bc66842aecda12ae6a380e62881ff2f2d82c68528aa6056583a48f3", + "0x7830a3318b603b89e2327145ac234cc594cbdd8d3df91610a83441caea9863bc" + "2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a72bf2c7b9e7c1ac4d77fc94ca", + "0x3df91610a83441caea9863bc2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a7" + "2bf2c7b9e7c1ac4d77fc94cadc083e67984050b75ebae5dd2809bd638016f723", + "0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870" + "553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90069", + "0x81aee4bdd82ed9645a21322e9c4c6a9385ed9f70b5d916c1b43b62eef4d0098e" + "ff3b1f78e2d0d48d50d1687b93b97d5f7c6d5047406a5e688b352209bcb9f822", + "0x7dde385d566332ecc0eabfa9cf7822fdf209f70024a57b1aa000c55b881f8111" + "b2dcde494a5f485e5bca4bd88a2763aed1ca2b2fa8f0540678cd1e0f3ad80892" + }, + { + "GOST2001-test", 256, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x8000000000000000000000000000000000000000000000000000000000000431", + "0x0000000000000000000000000000000000000000000000000000000000000007", + "0x5fbff498aa938ce739b8e022fbafef40563f6e6a3472fc2a514c0ce9dae23b7e", + "0x8000000000000000000000000000000150fe8a1892976154c59cfc193accf5b3", + + "0x0000000000000000000000000000000000000000000000000000000000000002", + "0x08e2a8a0e65147d4bd6316030e16d19c85c97f0a9ca267122b96abbcea7e8fc8", + }, + + { + "GOST2012-test", 511, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x4531acd1fe0023c7550d267b6b2fee80922b14b2ffb90f04d4eb7c09b5d2d15d" + "f1d852741af4704a0458047e80e4546d35b8336fac224dd81664bbf528be6373", + "0x0000000000000000000000000000000000000000000000000000000000000007", + "0x1cff0806a31116da29d8cfa54e57eb748bc5f377e49400fdd788b649eca1ac4" + "361834013b2ad7322480a89ca58e0cf74bc9e540c2add6897fad0a3084f302adc", + "0x4531acd1fe0023c7550d267b6b2fee80922b14b2ffb90f04d4eb7c09b5d2d15d" + "a82f2d7ecb1dbac719905c5eecc423f1d86e25edbe23c595d644aaf187e6e6df", + + "0x24d19cc64572ee30f396bf6ebbfd7a6c5213b3b3d7057cc825f91093a68cd762" + "fd60611262cd838dc6b60aa7eee804e28bc849977fac33b4b530f1b120248a9a", + "0x2bb312a43bd2ce6e0d020613c857acddcfbf061e91e5f2c3f32447c259f39b2" + "c83ab156d77f1496bf7eb3351e1ee4e43dc1a18b91b24640b6dbb92cb1add371e", + }, + + { NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL } + }; + + + + +/* Return a copy of POINT. */ +static gcry_mpi_point_t +point_copy (gcry_mpi_point_t point) +{ + gcry_mpi_point_t newpoint; + + if (point) + { + newpoint = mpi_point_new (0); + point_set (newpoint, point); + } + else + newpoint = NULL; + return newpoint; +} + + +/* Helper to scan a hex string. */ +static gcry_mpi_t +scanval (const char *string) +{ + gpg_err_code_t rc; + gcry_mpi_t val; + + rc = _gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL); + if (rc) + log_fatal ("scanning ECC parameter failed: %s\n", gpg_strerror (rc)); + return val; +} + + +/* Return the index of the domain_parms table for a curve with NAME. + Return -1 if not found. */ +static int +find_domain_parms_idx (const char *name) +{ + int idx, aliasno; + + /* First check our native curves. */ + for (idx = 0; domain_parms[idx].desc; idx++) + if (!strcmp (name, domain_parms[idx].desc)) + return idx; + + /* If not found consult the alias table. */ + if (!domain_parms[idx].desc) + { + for (aliasno = 0; curve_aliases[aliasno].name; aliasno++) + if (!strcmp (name, curve_aliases[aliasno].other)) + break; + if (curve_aliases[aliasno].name) + { + for (idx = 0; domain_parms[idx].desc; idx++) + if (!strcmp (curve_aliases[aliasno].name, domain_parms[idx].desc)) + return idx; + } + } + + return -1; +} + + +/* Generate the crypto system setup. This function takes the NAME of + a curve or the desired number of bits and stores at R_CURVE the + parameters of the named curve or those of a suitable curve. If + R_NBITS is not NULL, the chosen number of bits is stored there. + NULL may be given for R_CURVE, if the value is not required and for + example only a quick test for availability is desired. Note that + the curve fields should be initialized to zero because fields which + are not NULL are skipped. */ +gpg_err_code_t +_gcry_ecc_fill_in_curve (unsigned int nbits, const char *name, + elliptic_curve_t *curve, unsigned int *r_nbits) +{ + int idx; + const char *resname = NULL; /* Set to a found curve name. */ + + if (name) + idx = find_domain_parms_idx (name); + else + { + for (idx = 0; domain_parms[idx].desc; idx++) + if (nbits == domain_parms[idx].nbits + && domain_parms[idx].model == MPI_EC_WEIERSTRASS) + break; + if (!domain_parms[idx].desc) + idx = -1; + } + if (idx < 0) + return GPG_ERR_UNKNOWN_CURVE; + + resname = domain_parms[idx].desc; + + /* In fips mode we only support NIST curves. Note that it is + possible to bypass this check by specifying the curve parameters + directly. */ + if (fips_mode () && !domain_parms[idx].fips ) + return GPG_ERR_NOT_SUPPORTED; + + switch (domain_parms[idx].model) + { + case MPI_EC_WEIERSTRASS: + case MPI_EC_TWISTEDEDWARDS: + break; + case MPI_EC_MONTGOMERY: + return GPG_ERR_NOT_SUPPORTED; + default: + return GPG_ERR_BUG; + } + + + if (r_nbits) + *r_nbits = domain_parms[idx].nbits; + + if (curve) + { + curve->model = domain_parms[idx].model; + curve->dialect = domain_parms[idx].dialect; + if (!curve->p) + curve->p = scanval (domain_parms[idx].p); + if (!curve->a) + curve->a = scanval (domain_parms[idx].a); + if (!curve->b) + curve->b = scanval (domain_parms[idx].b); + if (!curve->n) + curve->n = scanval (domain_parms[idx].n); + if (!curve->G.x) + curve->G.x = scanval (domain_parms[idx].g_x); + if (!curve->G.y) + curve->G.y = scanval (domain_parms[idx].g_y); + if (!curve->G.z) + curve->G.z = mpi_alloc_set_ui (1); + if (!curve->name) + curve->name = resname; + } + + return 0; +} + + +/* Give the name of the curve NAME, store the curve parameters into P, + A, B, G, and N if they point to NULL value. Note that G is returned + in standard uncompressed format. Also update MODEL and DIALECT if + they are not NULL. */ +gpg_err_code_t +_gcry_ecc_update_curve_param (const char *name, + enum gcry_mpi_ec_models *model, + enum ecc_dialects *dialect, + gcry_mpi_t *p, gcry_mpi_t *a, gcry_mpi_t *b, + gcry_mpi_t *g, gcry_mpi_t *n) +{ + int idx; + + idx = find_domain_parms_idx (name); + if (idx < 0) + return GPG_ERR_UNKNOWN_CURVE; + + if (g) + { + char *buf; + size_t len; + + len = 4; + len += strlen (domain_parms[idx].g_x+2); + len += strlen (domain_parms[idx].g_y+2); + len++; + buf = xtrymalloc (len); + if (!buf) + return gpg_err_code_from_syserror (); + strcpy (stpcpy (stpcpy (buf, "0x04"), domain_parms[idx].g_x+2), + domain_parms[idx].g_y+2); + _gcry_mpi_release (*g); + *g = scanval (buf); + xfree (buf); + } + if (model) + *model = domain_parms[idx].model; + if (dialect) + *dialect = domain_parms[idx].dialect; + if (p) + { + _gcry_mpi_release (*p); + *p = scanval (domain_parms[idx].p); + } + if (a) + { + _gcry_mpi_release (*a); + *a = scanval (domain_parms[idx].a); + } + if (b) + { + _gcry_mpi_release (*b); + *b = scanval (domain_parms[idx].b); + } + if (n) + { + _gcry_mpi_release (*n); + *n = scanval (domain_parms[idx].n); + } + return 0; +} + + +/* Return the name matching the parameters in PKEY. This works only + with curves described by the Weierstrass equation. */ +const char * +_gcry_ecc_get_curve (gcry_sexp_t keyparms, int iterator, unsigned int *r_nbits) +{ + gpg_err_code_t rc; + const char *result = NULL; + elliptic_curve_t E; + gcry_mpi_t mpi_g = NULL; + gcry_mpi_t tmp = NULL; + int idx; + + memset (&E, 0, sizeof E); + + if (r_nbits) + *r_nbits = 0; + + if (!keyparms) + { + idx = iterator; + if (idx >= 0 && idx < DIM (domain_parms)) + { + result = domain_parms[idx].desc; + if (r_nbits) + *r_nbits = domain_parms[idx].nbits; + } + return result; + } + + + /* + * Extract the curve parameters.. + */ + rc = gpg_err_code (sexp_extract_param (keyparms, NULL, "-pabgn", + &E.p, &E.a, &E.b, &mpi_g, &E.n, + NULL)); + if (rc == GPG_ERR_NO_OBJ) + { + /* This might be the second use case of checking whether a + specific curve given by name is supported. */ + gcry_sexp_t l1; + char *name; + + l1 = sexp_find_token (keyparms, "curve", 5); + if (!l1) + goto leave; /* No curve name parameter. */ + + name = sexp_nth_string (l1, 1); + sexp_release (l1); + if (!name) + goto leave; /* Name missing or out of core. */ + + idx = find_domain_parms_idx (name); + xfree (name); + if (idx >= 0) /* Curve found. */ + { + result = domain_parms[idx].desc; + if (r_nbits) + *r_nbits = domain_parms[idx].nbits; + } + return result; + } + + if (rc) + goto leave; + + if (mpi_g) + { + _gcry_mpi_point_init (&E.G); + if (_gcry_ecc_os2ec (&E.G, mpi_g)) + goto leave; + } + + for (idx = 0; domain_parms[idx].desc; idx++) + { + mpi_free (tmp); + tmp = scanval (domain_parms[idx].p); + if (!mpi_cmp (tmp, E.p)) + { + mpi_free (tmp); + tmp = scanval (domain_parms[idx].a); + if (!mpi_cmp (tmp, E.a)) + { + mpi_free (tmp); + tmp = scanval (domain_parms[idx].b); + if (!mpi_cmp (tmp, E.b)) + { + mpi_free (tmp); + tmp = scanval (domain_parms[idx].n); + if (!mpi_cmp (tmp, E.n)) + { + mpi_free (tmp); + tmp = scanval (domain_parms[idx].g_x); + if (!mpi_cmp (tmp, E.G.x)) + { + mpi_free (tmp); + tmp = scanval (domain_parms[idx].g_y); + if (!mpi_cmp (tmp, E.G.y)) + { + result = domain_parms[idx].desc; + if (r_nbits) + *r_nbits = domain_parms[idx].nbits; + goto leave; + } + } + } + } + } + } + } + + leave: + _gcry_mpi_release (tmp); + _gcry_mpi_release (E.p); + _gcry_mpi_release (E.a); + _gcry_mpi_release (E.b); + _gcry_mpi_release (mpi_g); + _gcry_mpi_point_free_parts (&E.G); + _gcry_mpi_release (E.n); + return result; +} + + +/* Helper to extract an MPI from key parameters. */ +static gpg_err_code_t +mpi_from_keyparam (gcry_mpi_t *r_a, gcry_sexp_t keyparam, const char *name) +{ + gcry_err_code_t ec = 0; + gcry_sexp_t l1; + + l1 = sexp_find_token (keyparam, name, 0); + if (l1) + { + *r_a = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + sexp_release (l1); + if (!*r_a) + ec = GPG_ERR_INV_OBJ; + } + return ec; +} + +/* Helper to extract a point from key parameters. If no parameter + with NAME is found, the functions tries to find a non-encoded point + by appending ".x", ".y" and ".z" to NAME. ".z" is in this case + optional and defaults to 1. EC is the context which at this point + may not be fully initialized. */ +static gpg_err_code_t +point_from_keyparam (gcry_mpi_point_t *r_a, + gcry_sexp_t keyparam, const char *name, mpi_ec_t ec) +{ + gcry_err_code_t rc; + gcry_sexp_t l1; + gcry_mpi_point_t point; + + l1 = sexp_find_token (keyparam, name, 0); + if (l1) + { + gcry_mpi_t a; + + a = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_OPAQUE); + sexp_release (l1); + if (!a) + return GPG_ERR_INV_OBJ; + + point = mpi_point_new (0); + if (ec && ec->dialect == ECC_DIALECT_ED25519) + rc = _gcry_ecc_eddsa_decodepoint (a, ec, point, NULL, NULL); + else + rc = _gcry_ecc_os2ec (point, a); + mpi_free (a); + if (rc) + { + mpi_point_release (point); + return rc; + } + } + else + { + char *tmpname; + gcry_mpi_t x = NULL; + gcry_mpi_t y = NULL; + gcry_mpi_t z = NULL; + + tmpname = xtrymalloc (strlen (name) + 2 + 1); + if (!tmpname) + return gpg_err_code_from_syserror (); + strcpy (stpcpy (tmpname, name), ".x"); + rc = mpi_from_keyparam (&x, keyparam, tmpname); + if (rc) + { + xfree (tmpname); + return rc; + } + strcpy (stpcpy (tmpname, name), ".y"); + rc = mpi_from_keyparam (&y, keyparam, tmpname); + if (rc) + { + mpi_free (x); + xfree (tmpname); + return rc; + } + strcpy (stpcpy (tmpname, name), ".z"); + rc = mpi_from_keyparam (&z, keyparam, tmpname); + if (rc) + { + mpi_free (y); + mpi_free (x); + xfree (tmpname); + return rc; + } + if (!z) + z = mpi_set_ui (NULL, 1); + if (x && y) + point = mpi_point_snatch_set (NULL, x, y, z); + else + { + mpi_free (x); + mpi_free (y); + mpi_free (z); + point = NULL; + } + xfree (tmpname); + } + + if (point) + *r_a = point; + return 0; +} + + +/* This function creates a new context for elliptic curve operations. + Either KEYPARAM or CURVENAME must be given. If both are given and + KEYPARAM has no curve parameter, CURVENAME is used to add missing + parameters. On success 0 is returned and the new context stored at + R_CTX. On error NULL is stored at R_CTX and an error code is + returned. The context needs to be released using + gcry_ctx_release. */ +gpg_err_code_t +_gcry_mpi_ec_new (gcry_ctx_t *r_ctx, + gcry_sexp_t keyparam, const char *curvename) +{ + gpg_err_code_t errc; + gcry_ctx_t ctx = NULL; + enum gcry_mpi_ec_models model = MPI_EC_WEIERSTRASS; + enum ecc_dialects dialect = ECC_DIALECT_STANDARD; + gcry_mpi_t p = NULL; + gcry_mpi_t a = NULL; + gcry_mpi_t b = NULL; + gcry_mpi_point_t G = NULL; + gcry_mpi_t n = NULL; + gcry_mpi_point_t Q = NULL; + gcry_mpi_t d = NULL; + int flags = 0; + gcry_sexp_t l1; + + *r_ctx = NULL; + + if (keyparam) + { + /* Parse an optional flags list. */ + l1 = sexp_find_token (keyparam, "flags", 0); + if (l1) + { + errc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL); + sexp_release (l1); + l1 = NULL; + if (errc) + goto leave; + } + + /* Check whether a curve name was given. */ + l1 = sexp_find_token (keyparam, "curve", 5); + + /* If we don't have a curve name or if override parameters have + explicitly been requested, parse them. */ + if (!l1 || (flags & PUBKEY_FLAG_PARAM)) + { + errc = mpi_from_keyparam (&p, keyparam, "p"); + if (errc) + goto leave; + errc = mpi_from_keyparam (&a, keyparam, "a"); + if (errc) + goto leave; + errc = mpi_from_keyparam (&b, keyparam, "b"); + if (errc) + goto leave; + errc = point_from_keyparam (&G, keyparam, "g", NULL); + if (errc) + goto leave; + errc = mpi_from_keyparam (&n, keyparam, "n"); + if (errc) + goto leave; + } + } + else + l1 = NULL; /* No curvename. */ + + /* Check whether a curve parameter is available and use that to fill + in missing values. If no curve parameter is available try an + optional provided curvename. If only the curvename has been + given use that one. */ + if (l1 || curvename) + { + char *name; + elliptic_curve_t *E; + + if (l1) + { + name = sexp_nth_string (l1, 1); + sexp_release (l1); + if (!name) + { + errc = GPG_ERR_INV_OBJ; /* Name missing or out of core. */ + goto leave; + } + } + else + name = NULL; + + E = xtrycalloc (1, sizeof *E); + if (!E) + { + errc = gpg_err_code_from_syserror (); + xfree (name); + goto leave; + } + + errc = _gcry_ecc_fill_in_curve (0, name? name : curvename, E, NULL); + xfree (name); + if (errc) + { + xfree (E); + goto leave; + } + + model = E->model; + dialect = E->dialect; + + if (!p) + { + p = E->p; + E->p = NULL; + } + if (!a) + { + a = E->a; + E->a = NULL; + } + if (!b) + { + b = E->b; + E->b = NULL; + } + if (!G) + { + G = mpi_point_snatch_set (NULL, E->G.x, E->G.y, E->G.z); + E->G.x = NULL; + E->G.y = NULL; + E->G.z = NULL; + } + if (!n) + { + n = E->n; + E->n = NULL; + } + _gcry_ecc_curve_free (E); + xfree (E); + } + + + errc = _gcry_mpi_ec_p_new (&ctx, model, dialect, flags, p, a, b); + if (!errc) + { + mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC); + + if (b) + { + mpi_free (ec->b); + ec->b = b; + b = NULL; + } + if (G) + { + ec->G = G; + G = NULL; + } + if (n) + { + ec->n = n; + n = NULL; + } + + /* Now that we know the curve name we can look for the public key + Q. point_from_keyparam needs to know the curve parameters so + that it is able to use the correct decompression. Parsing + the private key D could have been done earlier but it is less + surprising if we do it here as well. */ + if (keyparam) + { + errc = point_from_keyparam (&Q, keyparam, "q", ec); + if (errc) + goto leave; + errc = mpi_from_keyparam (&d, keyparam, "d"); + if (errc) + goto leave; + } + + if (Q) + { + ec->Q = Q; + Q = NULL; + } + if (d) + { + ec->d = d; + d = NULL; + } + + *r_ctx = ctx; + ctx = NULL; + } + + leave: + _gcry_ctx_release (ctx); + mpi_free (p); + mpi_free (a); + mpi_free (b); + _gcry_mpi_point_release (G); + mpi_free (n); + _gcry_mpi_point_release (Q); + mpi_free (d); + return errc; +} + + +/* Return the parameters of the curve NAME as an S-expression. */ +gcry_sexp_t +_gcry_ecc_get_param_sexp (const char *name) +{ + unsigned int nbits; + elliptic_curve_t E; + mpi_ec_t ctx; + gcry_mpi_t g_x, g_y; + gcry_mpi_t pkey[6]; + gcry_sexp_t result; + int i; + + memset (&E, 0, sizeof E); + if (_gcry_ecc_fill_in_curve (0, name, &E, &nbits)) + return NULL; + + g_x = mpi_new (0); + g_y = mpi_new (0); + ctx = _gcry_mpi_ec_p_internal_new (MPI_EC_WEIERSTRASS, + ECC_DIALECT_STANDARD, + 0, + E.p, E.a, NULL); + if (_gcry_mpi_ec_get_affine (g_x, g_y, &E.G, ctx)) + log_fatal ("ecc get param: Failed to get affine coordinates\n"); + _gcry_mpi_ec_free (ctx); + _gcry_mpi_point_free_parts (&E.G); + + pkey[0] = E.p; + pkey[1] = E.a; + pkey[2] = E.b; + pkey[3] = _gcry_ecc_ec2os (g_x, g_y, E.p); + pkey[4] = E.n; + pkey[5] = NULL; + + mpi_free (g_x); + mpi_free (g_y); + + if (sexp_build (&result, NULL, + "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)))", + pkey[0], pkey[1], pkey[2], pkey[3], pkey[4])) + result = NULL; + + for (i=0; pkey[i]; i++) + _gcry_mpi_release (pkey[i]); + + return result; +} + + +/* Return an MPI (or opaque MPI) described by NAME and the context EC. + If COPY is true a copy is returned, if not a const MPI may be + returned. In any case mpi_free must be used. */ +gcry_mpi_t +_gcry_ecc_get_mpi (const char *name, mpi_ec_t ec, int copy) +{ + if (!*name) + return NULL; + + if (!strcmp (name, "p") && ec->p) + return mpi_is_const (ec->p) && !copy? ec->p : mpi_copy (ec->p); + if (!strcmp (name, "a") && ec->a) + return mpi_is_const (ec->a) && !copy? ec->a : mpi_copy (ec->a); + if (!strcmp (name, "b") && ec->b) + return mpi_is_const (ec->b) && !copy? ec->b : mpi_copy (ec->b); + if (!strcmp (name, "n") && ec->n) + return mpi_is_const (ec->n) && !copy? ec->n : mpi_copy (ec->n); + if (!strcmp (name, "d") && ec->d) + return mpi_is_const (ec->d) && !copy? ec->d : mpi_copy (ec->d); + + /* Return a requested point coordinate. */ + if (!strcmp (name, "g.x") && ec->G && ec->G->x) + return mpi_is_const (ec->G->x) && !copy? ec->G->x : mpi_copy (ec->G->x); + if (!strcmp (name, "g.y") && ec->G && ec->G->y) + return mpi_is_const (ec->G->y) && !copy? ec->G->y : mpi_copy (ec->G->y); + if (!strcmp (name, "q.x") && ec->Q && ec->Q->x) + return mpi_is_const (ec->Q->x) && !copy? ec->Q->x : mpi_copy (ec->Q->x); + if (!strcmp (name, "q.y") && ec->Q && ec->Q->y) + return mpi_is_const (ec->G->y) && !copy? ec->Q->y : mpi_copy (ec->Q->y); + + /* If the base point has been requested, return it in standard + encoding. */ + if (!strcmp (name, "g") && ec->G) + return _gcry_mpi_ec_ec2os (ec->G, ec); + + /* If the public key has been requested, return it by default in + standard uncompressed encoding or if requested in other + encodings. */ + if (*name == 'q' && (!name[1] || name[1] == '@')) + { + /* If only the private key is given, compute the public key. */ + if (!ec->Q) + ec->Q = _gcry_ecc_compute_public (NULL, ec, NULL, NULL); + + if (!ec->Q) + return NULL; + + if (name[1] != '@') + return _gcry_mpi_ec_ec2os (ec->Q, ec); + + if (!strcmp (name+2, "eddsa") && ec->model == MPI_EC_TWISTEDEDWARDS) + { + unsigned char *encpk; + unsigned int encpklen; + + if (!_gcry_ecc_eddsa_encodepoint (ec->Q, ec, NULL, NULL, 0, + &encpk, &encpklen)) + return mpi_set_opaque (NULL, encpk, encpklen*8); + } + } + + return NULL; +} + + +/* Return a point described by NAME and the context EC. */ +gcry_mpi_point_t +_gcry_ecc_get_point (const char *name, mpi_ec_t ec) +{ + if (!strcmp (name, "g") && ec->G) + return point_copy (ec->G); + if (!strcmp (name, "q")) + { + /* If only the private key is given, compute the public key. */ + if (!ec->Q) + ec->Q = _gcry_ecc_compute_public (NULL, ec, NULL, NULL); + + if (ec->Q) + return point_copy (ec->Q); + } + + return NULL; +} + + +/* Store the MPI NEWVALUE into the context EC under NAME. */ +gpg_err_code_t +_gcry_ecc_set_mpi (const char *name, gcry_mpi_t newvalue, mpi_ec_t ec) +{ + gpg_err_code_t rc = 0; + + if (!*name) + ; + else if (!strcmp (name, "p")) + { + mpi_free (ec->p); + ec->p = mpi_copy (newvalue); + _gcry_mpi_ec_get_reset (ec); + } + else if (!strcmp (name, "a")) + { + mpi_free (ec->a); + ec->a = mpi_copy (newvalue); + _gcry_mpi_ec_get_reset (ec); + } + else if (!strcmp (name, "b")) + { + mpi_free (ec->b); + ec->b = mpi_copy (newvalue); + } + else if (!strcmp (name, "n")) + { + mpi_free (ec->n); + ec->n = mpi_copy (newvalue); + } + else if (*name == 'q' && (!name[1] || name[1] == '@')) + { + if (newvalue) + { + if (!ec->Q) + ec->Q = mpi_point_new (0); + if (ec->dialect == ECC_DIALECT_ED25519) + rc = _gcry_ecc_eddsa_decodepoint (newvalue, ec, ec->Q, NULL, NULL); + else + rc = _gcry_ecc_os2ec (ec->Q, newvalue); + } + if (rc || !newvalue) + { + _gcry_mpi_point_release (ec->Q); + ec->Q = NULL; + } + /* Note: We assume that Q matches d and thus do not reset d. */ + } + else if (!strcmp (name, "d")) + { + mpi_free (ec->d); + ec->d = mpi_copy (newvalue); + if (ec->d) + { + /* We need to reset the public key because it may not + anymore match. */ + _gcry_mpi_point_release (ec->Q); + ec->Q = NULL; + } + } + else + rc = GPG_ERR_UNKNOWN_NAME; + + return rc; +} + + +/* Store the point NEWVALUE into the context EC under NAME. */ +gpg_err_code_t +_gcry_ecc_set_point (const char *name, gcry_mpi_point_t newvalue, mpi_ec_t ec) +{ + if (!strcmp (name, "g")) + { + _gcry_mpi_point_release (ec->G); + ec->G = point_copy (newvalue); + } + else if (!strcmp (name, "q")) + { + _gcry_mpi_point_release (ec->Q); + ec->Q = point_copy (newvalue); + } + else + return GPG_ERR_UNKNOWN_NAME; + + return 0; +} diff --git a/plugins/MirOTR/Libgcrypt/cipher/ecc-ecdsa.c b/plugins/MirOTR/Libgcrypt/cipher/ecc-ecdsa.c new file mode 100644 index 0000000000..1484830ba6 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/ecc-ecdsa.c @@ -0,0 +1,234 @@ +/* ecc-ecdsa.c - Elliptic Curve ECDSA signatures + * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "context.h" +#include "ec-context.h" +#include "pubkey-internal.h" +#include "ecc-common.h" + + +/* Compute an ECDSA signature. + * Return the signature struct (r,s) from the message hash. The caller + * must have allocated R and S. + */ +gpg_err_code_t +_gcry_ecc_ecdsa_sign (gcry_mpi_t input, ECC_secret_key *skey, + gcry_mpi_t r, gcry_mpi_t s, + int flags, int hashalgo) +{ + gpg_err_code_t rc = 0; + int extraloops = 0; + gcry_mpi_t k, dr, sum, k_1, x; + mpi_point_struct I; + gcry_mpi_t hash; + const void *abuf; + unsigned int abits, qbits; + mpi_ec_t ctx; + + if (DBG_CIPHER) + log_mpidump ("ecdsa sign hash ", input ); + + qbits = mpi_get_nbits (skey->E.n); + + /* Convert the INPUT into an MPI if needed. */ + rc = _gcry_dsa_normalize_hash (input, &hash, qbits); + if (rc) + return rc; + + k = NULL; + dr = mpi_alloc (0); + sum = mpi_alloc (0); + k_1 = mpi_alloc (0); + x = mpi_alloc (0); + point_init (&I); + + ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect, 0, + skey->E.p, skey->E.a, skey->E.b); + + /* Two loops to avoid R or S are zero. This is more of a joke than + a real demand because the probability of them being zero is less + than any hardware failure. Some specs however require it. */ + do + { + do + { + mpi_free (k); + k = NULL; + if ((flags & PUBKEY_FLAG_RFC6979) && hashalgo) + { + /* Use Pornin's method for deterministic DSA. If this + flag is set, it is expected that HASH is an opaque + MPI with the to be signed hash. That hash is also + used as h1 from 3.2.a. */ + if (!mpi_is_opaque (input)) + { + rc = GPG_ERR_CONFLICT; + goto leave; + } + + abuf = mpi_get_opaque (input, &abits); + rc = _gcry_dsa_gen_rfc6979_k (&k, skey->E.n, skey->d, + abuf, (abits+7)/8, + hashalgo, extraloops); + if (rc) + goto leave; + extraloops++; + } + else + k = _gcry_dsa_gen_k (skey->E.n, GCRY_STRONG_RANDOM); + + _gcry_mpi_ec_mul_point (&I, k, &skey->E.G, ctx); + if (_gcry_mpi_ec_get_affine (x, NULL, &I, ctx)) + { + if (DBG_CIPHER) + log_debug ("ecc sign: Failed to get affine coordinates\n"); + rc = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + mpi_mod (r, x, skey->E.n); /* r = x mod n */ + } + while (!mpi_cmp_ui (r, 0)); + + mpi_mulm (dr, skey->d, r, skey->E.n); /* dr = d*r mod n */ + mpi_addm (sum, hash, dr, skey->E.n); /* sum = hash + (d*r) mod n */ + mpi_invm (k_1, k, skey->E.n); /* k_1 = k^(-1) mod n */ + mpi_mulm (s, k_1, sum, skey->E.n); /* s = k^(-1)*(hash+(d*r)) mod n */ + } + while (!mpi_cmp_ui (s, 0)); + + if (DBG_CIPHER) + { + log_mpidump ("ecdsa sign result r ", r); + log_mpidump ("ecdsa sign result s ", s); + } + + leave: + _gcry_mpi_ec_free (ctx); + point_free (&I); + mpi_free (x); + mpi_free (k_1); + mpi_free (sum); + mpi_free (dr); + mpi_free (k); + + if (hash != input) + mpi_free (hash); + + return rc; +} + + +/* Verify an ECDSA signature. + * Check if R and S verifies INPUT. + */ +gpg_err_code_t +_gcry_ecc_ecdsa_verify (gcry_mpi_t input, ECC_public_key *pkey, + gcry_mpi_t r, gcry_mpi_t s) +{ + gpg_err_code_t err = 0; + gcry_mpi_t hash, h, h1, h2, x; + mpi_point_struct Q, Q1, Q2; + mpi_ec_t ctx; + unsigned int nbits; + + if( !(mpi_cmp_ui (r, 0) > 0 && mpi_cmp (r, pkey->E.n) < 0) ) + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */ + if( !(mpi_cmp_ui (s, 0) > 0 && mpi_cmp (s, pkey->E.n) < 0) ) + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */ + + nbits = mpi_get_nbits (pkey->E.n); + err = _gcry_dsa_normalize_hash (input, &hash, nbits); + if (err) + return err; + + h = mpi_alloc (0); + h1 = mpi_alloc (0); + h2 = mpi_alloc (0); + x = mpi_alloc (0); + point_init (&Q); + point_init (&Q1); + point_init (&Q2); + + ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect, 0, + pkey->E.p, pkey->E.a, pkey->E.b); + + /* h = s^(-1) (mod n) */ + mpi_invm (h, s, pkey->E.n); + /* h1 = hash * s^(-1) (mod n) */ + mpi_mulm (h1, hash, h, pkey->E.n); + /* Q1 = [ hash * s^(-1) ]G */ + _gcry_mpi_ec_mul_point (&Q1, h1, &pkey->E.G, ctx); + /* h2 = r * s^(-1) (mod n) */ + mpi_mulm (h2, r, h, pkey->E.n); + /* Q2 = [ r * s^(-1) ]Q */ + _gcry_mpi_ec_mul_point (&Q2, h2, &pkey->Q, ctx); + /* Q = ([hash * s^(-1)]G) + ([r * s^(-1)]Q) */ + _gcry_mpi_ec_add_points (&Q, &Q1, &Q2, ctx); + + if (!mpi_cmp_ui (Q.z, 0)) + { + if (DBG_CIPHER) + log_debug ("ecc verify: Rejected\n"); + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + if (_gcry_mpi_ec_get_affine (x, NULL, &Q, ctx)) + { + if (DBG_CIPHER) + log_debug ("ecc verify: Failed to get affine coordinates\n"); + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + mpi_mod (x, x, pkey->E.n); /* x = x mod E_n */ + if (mpi_cmp (x, r)) /* x != r */ + { + if (DBG_CIPHER) + { + log_mpidump (" x", x); + log_mpidump (" r", r); + log_mpidump (" s", s); + } + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + + leave: + _gcry_mpi_ec_free (ctx); + point_free (&Q2); + point_free (&Q1); + point_free (&Q); + mpi_free (x); + mpi_free (h2); + mpi_free (h1); + mpi_free (h); + if (hash != input) + mpi_free (hash); + + return err; +} diff --git a/plugins/MirOTR/Libgcrypt/cipher/ecc-eddsa.c b/plugins/MirOTR/Libgcrypt/cipher/ecc-eddsa.c new file mode 100644 index 0000000000..65024a30a0 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/ecc-eddsa.c @@ -0,0 +1,840 @@ +/* ecc-eddsa.c - Elliptic Curve EdDSA signatures + * Copyright (C) 2013, 2014 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "context.h" +#include "ec-context.h" +#include "ecc-common.h" + + + +static void +reverse_buffer (unsigned char *buffer, unsigned int length) +{ + unsigned int tmp, i; + + for (i=0; i < length/2; i++) + { + tmp = buffer[i]; + buffer[i] = buffer[length-1-i]; + buffer[length-1-i] = tmp; + } +} + + +/* Helper to scan a hex string. */ +static gcry_mpi_t +scanval (const char *string) +{ + gpg_err_code_t rc; + gcry_mpi_t val; + + rc = _gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL); + if (rc) + log_fatal ("scanning ECC parameter failed: %s\n", gpg_strerror (rc)); + return val; +} + + + +/* Encode MPI using the EdDSA scheme. MINLEN specifies the required + length of the buffer in bytes. On success 0 is returned an a + malloced buffer with the encoded point is stored at R_BUFFER; the + length of this buffer is stored at R_BUFLEN. */ +static gpg_err_code_t +eddsa_encodempi (gcry_mpi_t mpi, unsigned int minlen, + unsigned char **r_buffer, unsigned int *r_buflen) +{ + unsigned char *rawmpi; + unsigned int rawmpilen; + + rawmpi = _gcry_mpi_get_buffer (mpi, minlen, &rawmpilen, NULL); + if (!rawmpi) + return gpg_err_code_from_syserror (); + + *r_buffer = rawmpi; + *r_buflen = rawmpilen; + return 0; +} + + +/* Encode (X,Y) using the EdDSA scheme. MINLEN is the required length + in bytes for the result. If WITH_PREFIX is set the returned buffer + is prefixed with a 0x40 byte. On success 0 is returned and a + malloced buffer with the encoded point is stored at R_BUFFER; the + length of this buffer is stored at R_BUFLEN. */ +static gpg_err_code_t +eddsa_encode_x_y (gcry_mpi_t x, gcry_mpi_t y, unsigned int minlen, + int with_prefix, + unsigned char **r_buffer, unsigned int *r_buflen) +{ + unsigned char *rawmpi; + unsigned int rawmpilen; + int off = with_prefix? 1:0; + + rawmpi = _gcry_mpi_get_buffer_extra (y, minlen, off?-1:0, &rawmpilen, NULL); + if (!rawmpi) + return gpg_err_code_from_syserror (); + if (mpi_test_bit (x, 0) && rawmpilen) + rawmpi[off + rawmpilen - 1] |= 0x80; /* Set sign bit. */ + if (off) + rawmpi[0] = 0x40; + + *r_buffer = rawmpi; + *r_buflen = rawmpilen + off; + return 0; +} + +/* Encode POINT using the EdDSA scheme. X and Y are either scratch + variables supplied by the caller or NULL. CTX is the usual + context. If WITH_PREFIX is set the returned buffer is prefixed + with a 0x40 byte. On success 0 is returned and a malloced buffer + with the encoded point is stored at R_BUFFER; the length of this + buffer is stored at R_BUFLEN. */ +gpg_err_code_t +_gcry_ecc_eddsa_encodepoint (mpi_point_t point, mpi_ec_t ec, + gcry_mpi_t x_in, gcry_mpi_t y_in, + int with_prefix, + unsigned char **r_buffer, unsigned int *r_buflen) +{ + gpg_err_code_t rc; + gcry_mpi_t x, y; + + x = x_in? x_in : mpi_new (0); + y = y_in? y_in : mpi_new (0); + + if (_gcry_mpi_ec_get_affine (x, y, point, ec)) + { + log_error ("eddsa_encodepoint: Failed to get affine coordinates\n"); + rc = GPG_ERR_INTERNAL; + } + else + rc = eddsa_encode_x_y (x, y, ec->nbits/8, with_prefix, r_buffer, r_buflen); + + if (!x_in) + mpi_free (x); + if (!y_in) + mpi_free (y); + return rc; +} + + +/* Make sure that the opaque MPI VALUE is in compact EdDSA format. + This function updates MPI if needed. */ +gpg_err_code_t +_gcry_ecc_eddsa_ensure_compact (gcry_mpi_t value, unsigned int nbits) +{ + gpg_err_code_t rc; + const unsigned char *buf; + unsigned int rawmpilen; + gcry_mpi_t x, y; + unsigned char *enc; + unsigned int enclen; + + if (!mpi_is_opaque (value)) + return GPG_ERR_INV_OBJ; + buf = mpi_get_opaque (value, &rawmpilen); + if (!buf) + return GPG_ERR_INV_OBJ; + rawmpilen = (rawmpilen + 7)/8; + + if (rawmpilen > 1 && (rawmpilen%2)) + { + if (buf[0] == 0x04) + { + /* Buffer is in SEC1 uncompressed format. Extract y and + compress. */ + rc = _gcry_mpi_scan (&x, GCRYMPI_FMT_STD, + buf+1, (rawmpilen-1)/2, NULL); + if (rc) + return rc; + rc = _gcry_mpi_scan (&y, GCRYMPI_FMT_STD, + buf+1+(rawmpilen-1)/2, (rawmpilen-1)/2, NULL); + if (rc) + { + mpi_free (x); + return rc; + } + + rc = eddsa_encode_x_y (x, y, nbits/8, 0, &enc, &enclen); + mpi_free (x); + mpi_free (y); + if (rc) + return rc; + + mpi_set_opaque (value, enc, 8*enclen); + } + else if (buf[0] == 0x40) + { + /* Buffer is compressed but with our SEC1 alike compression + indicator. Remove that byte. FIXME: We should write and + use a function to manipulate an opaque MPI in place. */ + if (!_gcry_mpi_set_opaque_copy (value, buf + 1, (rawmpilen - 1)*8)) + return gpg_err_code_from_syserror (); + } + } + + return 0; +} + + +/* Recover X from Y and SIGN (which actually is a parity bit). */ +gpg_err_code_t +_gcry_ecc_eddsa_recover_x (gcry_mpi_t x, gcry_mpi_t y, int sign, mpi_ec_t ec) +{ + gpg_err_code_t rc = 0; + gcry_mpi_t u, v, v3, t; + static gcry_mpi_t p58, seven; + + if (ec->dialect != ECC_DIALECT_ED25519) + return GPG_ERR_NOT_IMPLEMENTED; + + if (!p58) + p58 = scanval ("0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD"); + if (!seven) + seven = mpi_set_ui (NULL, 7); + + u = mpi_new (0); + v = mpi_new (0); + v3 = mpi_new (0); + t = mpi_new (0); + + /* Compute u and v */ + /* u = y^2 */ + mpi_mulm (u, y, y, ec->p); + /* v = b*y^2 */ + mpi_mulm (v, ec->b, u, ec->p); + /* u = y^2-1 */ + mpi_sub_ui (u, u, 1); + /* v = b*y^2+1 */ + mpi_add_ui (v, v, 1); + + /* Compute sqrt(u/v) */ + /* v3 = v^3 */ + mpi_powm (v3, v, mpi_const (MPI_C_THREE), ec->p); + /* t = v3 * v3 * u * v = u * v^7 */ + mpi_powm (t, v, seven, ec->p); + mpi_mulm (t, t, u, ec->p); + /* t = t^((p-5)/8) = (u * v^7)^((p-5)/8) */ + mpi_powm (t, t, p58, ec->p); + /* x = t * u * v^3 = (u * v^3) * (u * v^7)^((p-5)/8) */ + mpi_mulm (t, t, u, ec->p); + mpi_mulm (x, t, v3, ec->p); + + /* Adjust if needed. */ + /* t = v * x^2 */ + mpi_mulm (t, x, x, ec->p); + mpi_mulm (t, t, v, ec->p); + /* -t == u ? x = x * sqrt(-1) */ + mpi_neg (t, t); + if (!mpi_cmp (t, u)) + { + static gcry_mpi_t m1; /* Fixme: this is not thread-safe. */ + if (!m1) + m1 = scanval ("2B8324804FC1DF0B2B4D00993DFBD7A7" + "2F431806AD2FE478C4EE1B274A0EA0B0"); + mpi_mulm (x, x, m1, ec->p); + /* t = v * x^2 */ + mpi_mulm (t, x, x, ec->p); + mpi_mulm (t, t, v, ec->p); + /* -t == u ? x = x * sqrt(-1) */ + mpi_neg (t, t); + if (!mpi_cmp (t, u)) + rc = GPG_ERR_INV_OBJ; + } + + /* Choose the desired square root according to parity */ + if (mpi_test_bit (x, 0) != !!sign) + mpi_sub (x, ec->p, x); + + mpi_free (t); + mpi_free (v3); + mpi_free (v); + mpi_free (u); + + return rc; +} + + +/* Decode the EdDSA style encoded PK and set it into RESULT. CTX is + the usual curve context. If R_ENCPK is not NULL, the encoded PK is + stored at that address; this is a new copy to be released by the + caller. In contrast to the supplied PK, this is not an MPI and + thus guaranteed to be properly padded. R_ENCPKLEN receives the + length of that encoded key. */ +gpg_err_code_t +_gcry_ecc_eddsa_decodepoint (gcry_mpi_t pk, mpi_ec_t ctx, mpi_point_t result, + unsigned char **r_encpk, unsigned int *r_encpklen) +{ + gpg_err_code_t rc; + unsigned char *rawmpi; + unsigned int rawmpilen; + int sign; + + if (mpi_is_opaque (pk)) + { + const unsigned char *buf; + + buf = mpi_get_opaque (pk, &rawmpilen); + if (!buf) + return GPG_ERR_INV_OBJ; + rawmpilen = (rawmpilen + 7)/8; + + /* Handle compression prefixes. The size of the buffer will be + odd in this case. */ + if (rawmpilen > 1 && (rawmpilen%2)) + { + /* First check whether the public key has been given in + standard uncompressed format (SEC1). No need to recover + x in this case. */ + if (buf[0] == 0x04) + { + gcry_mpi_t x, y; + + rc = _gcry_mpi_scan (&x, GCRYMPI_FMT_STD, + buf+1, (rawmpilen-1)/2, NULL); + if (rc) + return rc; + rc = _gcry_mpi_scan (&y, GCRYMPI_FMT_STD, + buf+1+(rawmpilen-1)/2, (rawmpilen-1)/2,NULL); + if (rc) + { + mpi_free (x); + return rc; + } + + if (r_encpk) + { + rc = eddsa_encode_x_y (x, y, ctx->nbits/8, 0, + r_encpk, r_encpklen); + if (rc) + { + mpi_free (x); + mpi_free (y); + return rc; + } + } + mpi_snatch (result->x, x); + mpi_snatch (result->y, y); + mpi_set_ui (result->z, 1); + return 0; + } + + /* Check whether the public key has been prefixed with a 0x40 + byte to explicitly indicate compressed format using a SEC1 + alike prefix byte. This is a Libgcrypt extension. */ + if (buf[0] == 0x40) + { + rawmpilen--; + buf++; + } + } + + /* EdDSA compressed point. */ + rawmpi = xtrymalloc (rawmpilen? rawmpilen:1); + if (!rawmpi) + return gpg_err_code_from_syserror (); + memcpy (rawmpi, buf, rawmpilen); + reverse_buffer (rawmpi, rawmpilen); + } + else + { + /* Note: Without using an opaque MPI it is not reliable possible + to find out whether the public key has been given in + uncompressed format. Thus we expect native EdDSA format. */ + rawmpi = _gcry_mpi_get_buffer (pk, ctx->nbits/8, &rawmpilen, NULL); + if (!rawmpi) + return gpg_err_code_from_syserror (); + } + + if (rawmpilen) + { + sign = !!(rawmpi[0] & 0x80); + rawmpi[0] &= 0x7f; + } + else + sign = 0; + _gcry_mpi_set_buffer (result->y, rawmpi, rawmpilen, 0); + if (r_encpk) + { + /* Revert to little endian. */ + if (sign && rawmpilen) + rawmpi[0] |= 0x80; + reverse_buffer (rawmpi, rawmpilen); + *r_encpk = rawmpi; + if (r_encpklen) + *r_encpklen = rawmpilen; + } + else + xfree (rawmpi); + + rc = _gcry_ecc_eddsa_recover_x (result->x, result->y, sign, ctx); + mpi_set_ui (result->z, 1); + + return rc; +} + + +/* Compute the A value as used by EdDSA. The caller needs to provide + the context EC and the actual secret D as an MPI. The function + returns a newly allocated 64 byte buffer at r_digest; the first 32 + bytes represent the A value. NULL is returned on error and NULL + stored at R_DIGEST. */ +gpg_err_code_t +_gcry_ecc_eddsa_compute_h_d (unsigned char **r_digest, + gcry_mpi_t d, mpi_ec_t ec) +{ + gpg_err_code_t rc; + unsigned char *rawmpi = NULL; + unsigned int rawmpilen; + unsigned char *digest; + gcry_buffer_t hvec[2]; + int hashalgo, b; + + *r_digest = NULL; + + hashalgo = GCRY_MD_SHA512; + if (hashalgo != GCRY_MD_SHA512) + return GPG_ERR_DIGEST_ALGO; + + b = (ec->nbits+7)/8; + if (b != 256/8) + return GPG_ERR_INTERNAL; /* We only support 256 bit. */ + + /* Note that we clear DIGEST so we can use it as input to left pad + the key with zeroes for hashing. */ + digest = xtrycalloc_secure (2, b); + if (!digest) + return gpg_err_code_from_syserror (); + + memset (hvec, 0, sizeof hvec); + + rawmpi = _gcry_mpi_get_buffer (d, 0, &rawmpilen, NULL); + if (!rawmpi) + { + xfree (digest); + return gpg_err_code_from_syserror (); + } + + hvec[0].data = digest; + hvec[0].off = 0; + hvec[0].len = b > rawmpilen? b - rawmpilen : 0; + hvec[1].data = rawmpi; + hvec[1].off = 0; + hvec[1].len = rawmpilen; + rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 2); + xfree (rawmpi); + if (rc) + { + xfree (digest); + return rc; + } + + /* Compute the A value. */ + reverse_buffer (digest, 32); /* Only the first half of the hash. */ + digest[0] = (digest[0] & 0x7f) | 0x40; + digest[31] &= 0xf8; + + *r_digest = digest; + return 0; +} + + +/* Ed25519 version of the key generation. */ +gpg_err_code_t +_gcry_ecc_eddsa_genkey (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx, + gcry_random_level_t random_level) +{ + gpg_err_code_t rc; + int b = 256/8; /* The only size we currently support. */ + gcry_mpi_t a, x, y; + mpi_point_struct Q; + char *dbuf; + size_t dlen; + gcry_buffer_t hvec[1]; + unsigned char *hash_d = NULL; + + point_init (&Q); + memset (hvec, 0, sizeof hvec); + + a = mpi_snew (0); + x = mpi_new (0); + y = mpi_new (0); + + /* Generate a secret. */ + hash_d = xtrymalloc_secure (2*b); + if (!hash_d) + { + rc = gpg_error_from_syserror (); + goto leave; + } + dlen = b; + dbuf = _gcry_random_bytes_secure (dlen, random_level); + + /* Compute the A value. */ + hvec[0].data = dbuf; + hvec[0].len = dlen; + rc = _gcry_md_hash_buffers (GCRY_MD_SHA512, 0, hash_d, hvec, 1); + if (rc) + goto leave; + sk->d = _gcry_mpi_set_opaque (NULL, dbuf, dlen*8); + dbuf = NULL; + reverse_buffer (hash_d, 32); /* Only the first half of the hash. */ + hash_d[0] = (hash_d[0] & 0x7f) | 0x40; + hash_d[31] &= 0xf8; + _gcry_mpi_set_buffer (a, hash_d, 32, 0); + xfree (hash_d); hash_d = NULL; + /* log_printmpi ("ecgen a", a); */ + + /* Compute Q. */ + _gcry_mpi_ec_mul_point (&Q, a, &E->G, ctx); + if (DBG_CIPHER) + log_printpnt ("ecgen pk", &Q, ctx); + + /* Copy the stuff to the key structures. */ + sk->E.model = E->model; + sk->E.dialect = E->dialect; + sk->E.p = mpi_copy (E->p); + sk->E.a = mpi_copy (E->a); + sk->E.b = mpi_copy (E->b); + point_init (&sk->E.G); + point_set (&sk->E.G, &E->G); + sk->E.n = mpi_copy (E->n); + point_init (&sk->Q); + point_set (&sk->Q, &Q); + + leave: + point_free (&Q); + _gcry_mpi_release (a); + _gcry_mpi_release (x); + _gcry_mpi_release (y); + xfree (hash_d); + return rc; +} + + +/* Compute an EdDSA signature. See: + * [ed25519] 23pp. (PDF) Daniel J. Bernstein, Niels Duif, Tanja + * Lange, Peter Schwabe, Bo-Yin Yang. High-speed high-security + * signatures. Journal of Cryptographic Engineering 2 (2012), 77-89. + * Document ID: a1a62a2f76d23f65d622484ddd09caf8. + * URL: http://cr.yp.to/papers.html#ed25519. Date: 2011.09.26. + * + * Despite that this function requires the specification of a hash + * algorithm, we only support what has been specified by the paper. + * This may change in the future. Note that we don't check the used + * curve; the user is responsible to use Ed25519. + * + * Return the signature struct (r,s) from the message hash. The caller + * must have allocated R_R and S. + */ +gpg_err_code_t +_gcry_ecc_eddsa_sign (gcry_mpi_t input, ECC_secret_key *skey, + gcry_mpi_t r_r, gcry_mpi_t s, int hashalgo, gcry_mpi_t pk) +{ + int rc; + mpi_ec_t ctx = NULL; + int b; + unsigned int tmp; + unsigned char *digest; + gcry_buffer_t hvec[3]; + const void *mbuf; + size_t mlen; + unsigned char *rawmpi = NULL; + unsigned int rawmpilen; + unsigned char *encpk = NULL; /* Encoded public key. */ + unsigned int encpklen; + mpi_point_struct I; /* Intermediate value. */ + mpi_point_struct Q; /* Public key. */ + gcry_mpi_t a, x, y, r; + + memset (hvec, 0, sizeof hvec); + + if (!mpi_is_opaque (input)) + return GPG_ERR_INV_DATA; + + /* Initialize some helpers. */ + point_init (&I); + point_init (&Q); + a = mpi_snew (0); + x = mpi_new (0); + y = mpi_new (0); + r = mpi_new (0); + ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect, 0, + skey->E.p, skey->E.a, skey->E.b); + b = (ctx->nbits+7)/8; + if (b != 256/8) + return GPG_ERR_INTERNAL; /* We only support 256 bit. */ + + rc = _gcry_ecc_eddsa_compute_h_d (&digest, skey->d, ctx); + if (rc) + goto leave; + _gcry_mpi_set_buffer (a, digest, 32, 0); + + /* Compute the public key if it has not been supplied as optional + parameter. */ + if (pk) + { + rc = _gcry_ecc_eddsa_decodepoint (pk, ctx, &Q, &encpk, &encpklen); + if (rc) + goto leave; + if (DBG_CIPHER) + log_printhex ("* e_pk", encpk, encpklen); + if (!_gcry_mpi_ec_curve_point (&Q, ctx)) + { + rc = GPG_ERR_BROKEN_PUBKEY; + goto leave; + } + } + else + { + _gcry_mpi_ec_mul_point (&Q, a, &skey->E.G, ctx); + rc = _gcry_ecc_eddsa_encodepoint (&Q, ctx, x, y, 0, &encpk, &encpklen); + if (rc) + goto leave; + if (DBG_CIPHER) + log_printhex (" e_pk", encpk, encpklen); + } + + /* Compute R. */ + mbuf = mpi_get_opaque (input, &tmp); + mlen = (tmp +7)/8; + if (DBG_CIPHER) + log_printhex (" m", mbuf, mlen); + + hvec[0].data = digest; + hvec[0].off = 32; + hvec[0].len = 32; + hvec[1].data = (char*)mbuf; + hvec[1].len = mlen; + rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 2); + if (rc) + goto leave; + reverse_buffer (digest, 64); + if (DBG_CIPHER) + log_printhex (" r", digest, 64); + _gcry_mpi_set_buffer (r, digest, 64, 0); + _gcry_mpi_ec_mul_point (&I, r, &skey->E.G, ctx); + if (DBG_CIPHER) + log_printpnt (" r", &I, ctx); + + /* Convert R into affine coordinates and apply encoding. */ + rc = _gcry_ecc_eddsa_encodepoint (&I, ctx, x, y, 0, &rawmpi, &rawmpilen); + if (rc) + goto leave; + if (DBG_CIPHER) + log_printhex (" e_r", rawmpi, rawmpilen); + + /* S = r + a * H(encodepoint(R) + encodepoint(pk) + m) mod n */ + hvec[0].data = rawmpi; /* (this is R) */ + hvec[0].off = 0; + hvec[0].len = rawmpilen; + hvec[1].data = encpk; + hvec[1].off = 0; + hvec[1].len = encpklen; + hvec[2].data = (char*)mbuf; + hvec[2].off = 0; + hvec[2].len = mlen; + rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 3); + if (rc) + goto leave; + + /* No more need for RAWMPI thus we now transfer it to R_R. */ + mpi_set_opaque (r_r, rawmpi, rawmpilen*8); + rawmpi = NULL; + + reverse_buffer (digest, 64); + if (DBG_CIPHER) + log_printhex (" H(R+)", digest, 64); + _gcry_mpi_set_buffer (s, digest, 64, 0); + mpi_mulm (s, s, a, skey->E.n); + mpi_addm (s, s, r, skey->E.n); + rc = eddsa_encodempi (s, b, &rawmpi, &rawmpilen); + if (rc) + goto leave; + if (DBG_CIPHER) + log_printhex (" e_s", rawmpi, rawmpilen); + mpi_set_opaque (s, rawmpi, rawmpilen*8); + rawmpi = NULL; + + rc = 0; + + leave: + _gcry_mpi_release (a); + _gcry_mpi_release (x); + _gcry_mpi_release (y); + _gcry_mpi_release (r); + xfree (digest); + _gcry_mpi_ec_free (ctx); + point_free (&I); + point_free (&Q); + xfree (encpk); + xfree (rawmpi); + return rc; +} + + +/* Verify an EdDSA signature. See sign_eddsa for the reference. + * Check if R_IN and S_IN verifies INPUT. PKEY has the curve + * parameters and PK is the EdDSA style encoded public key. + */ +gpg_err_code_t +_gcry_ecc_eddsa_verify (gcry_mpi_t input, ECC_public_key *pkey, + gcry_mpi_t r_in, gcry_mpi_t s_in, int hashalgo, + gcry_mpi_t pk) +{ + int rc; + mpi_ec_t ctx = NULL; + int b; + unsigned int tmp; + mpi_point_struct Q; /* Public key. */ + unsigned char *encpk = NULL; /* Encoded public key. */ + unsigned int encpklen; + const void *mbuf, *rbuf; + unsigned char *tbuf = NULL; + size_t mlen, rlen; + unsigned int tlen; + unsigned char digest[64]; + gcry_buffer_t hvec[3]; + gcry_mpi_t h, s; + mpi_point_struct Ia, Ib; + + if (!mpi_is_opaque (input) || !mpi_is_opaque (r_in) || !mpi_is_opaque (s_in)) + return GPG_ERR_INV_DATA; + if (hashalgo != GCRY_MD_SHA512) + return GPG_ERR_DIGEST_ALGO; + + point_init (&Q); + point_init (&Ia); + point_init (&Ib); + h = mpi_new (0); + s = mpi_new (0); + + ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect, 0, + pkey->E.p, pkey->E.a, pkey->E.b); + b = ctx->nbits/8; + if (b != 256/8) + return GPG_ERR_INTERNAL; /* We only support 256 bit. */ + + /* Decode and check the public key. */ + rc = _gcry_ecc_eddsa_decodepoint (pk, ctx, &Q, &encpk, &encpklen); + if (rc) + goto leave; + if (!_gcry_mpi_ec_curve_point (&Q, ctx)) + { + rc = GPG_ERR_BROKEN_PUBKEY; + goto leave; + } + if (DBG_CIPHER) + log_printhex (" e_pk", encpk, encpklen); + if (encpklen != b) + { + rc = GPG_ERR_INV_LENGTH; + goto leave; + } + + /* Convert the other input parameters. */ + mbuf = mpi_get_opaque (input, &tmp); + mlen = (tmp +7)/8; + if (DBG_CIPHER) + log_printhex (" m", mbuf, mlen); + rbuf = mpi_get_opaque (r_in, &tmp); + rlen = (tmp +7)/8; + if (DBG_CIPHER) + log_printhex (" r", rbuf, rlen); + if (rlen != b) + { + rc = GPG_ERR_INV_LENGTH; + goto leave; + } + + /* h = H(encodepoint(R) + encodepoint(pk) + m) */ + hvec[0].data = (char*)rbuf; + hvec[0].off = 0; + hvec[0].len = rlen; + hvec[1].data = encpk; + hvec[1].off = 0; + hvec[1].len = encpklen; + hvec[2].data = (char*)mbuf; + hvec[2].off = 0; + hvec[2].len = mlen; + rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 3); + if (rc) + goto leave; + reverse_buffer (digest, 64); + if (DBG_CIPHER) + log_printhex (" H(R+)", digest, 64); + _gcry_mpi_set_buffer (h, digest, 64, 0); + + /* According to the paper the best way for verification is: + encodepoint(sG - h·Q) = encodepoint(r) + because we don't need to decode R. */ + { + void *sbuf; + unsigned int slen; + + sbuf = _gcry_mpi_get_opaque_copy (s_in, &tmp); + slen = (tmp +7)/8; + reverse_buffer (sbuf, slen); + if (DBG_CIPHER) + log_printhex (" s", sbuf, slen); + _gcry_mpi_set_buffer (s, sbuf, slen, 0); + xfree (sbuf); + if (slen != b) + { + rc = GPG_ERR_INV_LENGTH; + goto leave; + } + } + + _gcry_mpi_ec_mul_point (&Ia, s, &pkey->E.G, ctx); + _gcry_mpi_ec_mul_point (&Ib, h, &Q, ctx); + _gcry_mpi_neg (Ib.x, Ib.x); + _gcry_mpi_ec_add_points (&Ia, &Ia, &Ib, ctx); + rc = _gcry_ecc_eddsa_encodepoint (&Ia, ctx, s, h, 0, &tbuf, &tlen); + if (rc) + goto leave; + if (tlen != rlen || memcmp (tbuf, rbuf, tlen)) + { + rc = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + + rc = 0; + + leave: + xfree (encpk); + xfree (tbuf); + _gcry_mpi_ec_free (ctx); + _gcry_mpi_release (s); + _gcry_mpi_release (h); + point_free (&Ia); + point_free (&Ib); + point_free (&Q); + return rc; +} diff --git a/plugins/MirOTR/Libgcrypt/cipher/ecc-gost.c b/plugins/MirOTR/Libgcrypt/cipher/ecc-gost.c new file mode 100644 index 0000000000..a34fa08446 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/ecc-gost.c @@ -0,0 +1,233 @@ +/* ecc-gots.c - Elliptic Curve GOST signatures + * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013 Dmitry Eremin-Solenikov + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "context.h" +#include "ec-context.h" +#include "ecc-common.h" +#include "pubkey-internal.h" + + +/* Compute an GOST R 34.10-01/-12 signature. + * Return the signature struct (r,s) from the message hash. The caller + * must have allocated R and S. + */ +gpg_err_code_t +_gcry_ecc_gost_sign (gcry_mpi_t input, ECC_secret_key *skey, + gcry_mpi_t r, gcry_mpi_t s) +{ + gpg_err_code_t rc = 0; + gcry_mpi_t k, dr, sum, ke, x, e; + mpi_point_struct I; + gcry_mpi_t hash; + const void *abuf; + unsigned int abits, qbits; + mpi_ec_t ctx; + + if (DBG_CIPHER) + log_mpidump ("gost sign hash ", input ); + + qbits = mpi_get_nbits (skey->E.n); + + /* Convert the INPUT into an MPI if needed. */ + if (mpi_is_opaque (input)) + { + abuf = mpi_get_opaque (input, &abits); + rc = _gcry_mpi_scan (&hash, GCRYMPI_FMT_USG, abuf, (abits+7)/8, NULL); + if (rc) + return rc; + if (abits > qbits) + mpi_rshift (hash, hash, abits - qbits); + } + else + hash = input; + + + k = NULL; + dr = mpi_alloc (0); + sum = mpi_alloc (0); + ke = mpi_alloc (0); + e = mpi_alloc (0); + x = mpi_alloc (0); + point_init (&I); + + ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect, 0, + skey->E.p, skey->E.a, skey->E.b); + + mpi_mod (e, input, skey->E.n); /* e = hash mod n */ + + if (!mpi_cmp_ui (e, 0)) + mpi_set_ui (e, 1); + + /* Two loops to avoid R or S are zero. This is more of a joke than + a real demand because the probability of them being zero is less + than any hardware failure. Some specs however require it. */ + do + { + do + { + mpi_free (k); + k = _gcry_dsa_gen_k (skey->E.n, GCRY_STRONG_RANDOM); + + _gcry_mpi_ec_mul_point (&I, k, &skey->E.G, ctx); + if (_gcry_mpi_ec_get_affine (x, NULL, &I, ctx)) + { + if (DBG_CIPHER) + log_debug ("ecc sign: Failed to get affine coordinates\n"); + rc = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + mpi_mod (r, x, skey->E.n); /* r = x mod n */ + } + while (!mpi_cmp_ui (r, 0)); + mpi_mulm (dr, skey->d, r, skey->E.n); /* dr = d*r mod n */ + mpi_mulm (ke, k, e, skey->E.n); /* ke = k*e mod n */ + mpi_addm (s, ke, dr, skey->E.n); /* sum = (k*e+ d*r) mod n */ + } + while (!mpi_cmp_ui (s, 0)); + + if (DBG_CIPHER) + { + log_mpidump ("gost sign result r ", r); + log_mpidump ("gost sign result s ", s); + } + + leave: + _gcry_mpi_ec_free (ctx); + point_free (&I); + mpi_free (x); + mpi_free (e); + mpi_free (ke); + mpi_free (sum); + mpi_free (dr); + mpi_free (k); + + if (hash != input) + mpi_free (hash); + + return rc; +} + + +/* Verify a GOST R 34.10-01/-12 signature. + * Check if R and S verifies INPUT. + */ +gpg_err_code_t +_gcry_ecc_gost_verify (gcry_mpi_t input, ECC_public_key *pkey, + gcry_mpi_t r, gcry_mpi_t s) +{ + gpg_err_code_t err = 0; + gcry_mpi_t e, x, z1, z2, v, rv, zero; + mpi_point_struct Q, Q1, Q2; + mpi_ec_t ctx; + + if( !(mpi_cmp_ui (r, 0) > 0 && mpi_cmp (r, pkey->E.n) < 0) ) + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */ + if( !(mpi_cmp_ui (s, 0) > 0 && mpi_cmp (s, pkey->E.n) < 0) ) + return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */ + + x = mpi_alloc (0); + e = mpi_alloc (0); + z1 = mpi_alloc (0); + z2 = mpi_alloc (0); + v = mpi_alloc (0); + rv = mpi_alloc (0); + zero = mpi_alloc (0); + + point_init (&Q); + point_init (&Q1); + point_init (&Q2); + + ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect, 0, + pkey->E.p, pkey->E.a, pkey->E.b); + + mpi_mod (e, input, pkey->E.n); /* e = hash mod n */ + if (!mpi_cmp_ui (e, 0)) + mpi_set_ui (e, 1); + mpi_invm (v, e, pkey->E.n); /* v = e^(-1) (mod n) */ + mpi_mulm (z1, s, v, pkey->E.n); /* z1 = s*v (mod n) */ + mpi_mulm (rv, r, v, pkey->E.n); /* rv = s*v (mod n) */ + mpi_subm (z2, zero, rv, pkey->E.n); /* z2 = -r*v (mod n) */ + + _gcry_mpi_ec_mul_point (&Q1, z1, &pkey->E.G, ctx); +/* log_mpidump ("Q1.x", Q1.x); */ +/* log_mpidump ("Q1.y", Q1.y); */ +/* log_mpidump ("Q1.z", Q1.z); */ + _gcry_mpi_ec_mul_point (&Q2, z2, &pkey->Q, ctx); +/* log_mpidump ("Q2.x", Q2.x); */ +/* log_mpidump ("Q2.y", Q2.y); */ +/* log_mpidump ("Q2.z", Q2.z); */ + _gcry_mpi_ec_add_points (&Q, &Q1, &Q2, ctx); +/* log_mpidump (" Q.x", Q.x); */ +/* log_mpidump (" Q.y", Q.y); */ +/* log_mpidump (" Q.z", Q.z); */ + + if (!mpi_cmp_ui (Q.z, 0)) + { + if (DBG_CIPHER) + log_debug ("ecc verify: Rejected\n"); + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + if (_gcry_mpi_ec_get_affine (x, NULL, &Q, ctx)) + { + if (DBG_CIPHER) + log_debug ("ecc verify: Failed to get affine coordinates\n"); + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + mpi_mod (x, x, pkey->E.n); /* x = x mod E_n */ + if (mpi_cmp (x, r)) /* x != r */ + { + if (DBG_CIPHER) + { + log_mpidump (" x", x); + log_mpidump (" r", r); + log_mpidump (" s", s); + log_debug ("ecc verify: Not verified\n"); + } + err = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + if (DBG_CIPHER) + log_debug ("ecc verify: Accepted\n"); + + leave: + _gcry_mpi_ec_free (ctx); + point_free (&Q2); + point_free (&Q1); + point_free (&Q); + mpi_free (zero); + mpi_free (rv); + mpi_free (v); + mpi_free (z2); + mpi_free (z1); + mpi_free (x); + mpi_free (e); + return err; +} diff --git a/plugins/MirOTR/Libgcrypt/cipher/ecc-misc.c b/plugins/MirOTR/Libgcrypt/cipher/ecc-misc.c new file mode 100644 index 0000000000..7b750c015e --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/ecc-misc.c @@ -0,0 +1,287 @@ +/* ecc-misc.c - Elliptic Curve miscellaneous functions + * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "context.h" +#include "ec-context.h" +#include "ecc-common.h" + + +/* + * Release a curve object. + */ +void +_gcry_ecc_curve_free (elliptic_curve_t *E) +{ + mpi_free (E->p); E->p = NULL; + mpi_free (E->a); E->a = NULL; + mpi_free (E->b); E->b = NULL; + _gcry_mpi_point_free_parts (&E->G); + mpi_free (E->n); E->n = NULL; +} + + +/* + * Return a copy of a curve object. + */ +elliptic_curve_t +_gcry_ecc_curve_copy (elliptic_curve_t E) +{ + elliptic_curve_t R; + + R.model = E.model; + R.dialect = E.dialect; + R.name = E.name; + R.p = mpi_copy (E.p); + R.a = mpi_copy (E.a); + R.b = mpi_copy (E.b); + _gcry_mpi_point_init (&R.G); + point_set (&R.G, &E.G); + R.n = mpi_copy (E.n); + + return R; +} + + +/* + * Return a description of the curve model. + */ +const char * +_gcry_ecc_model2str (enum gcry_mpi_ec_models model) +{ + const char *str = "?"; + switch (model) + { + case MPI_EC_WEIERSTRASS: str = "Weierstrass"; break; + case MPI_EC_MONTGOMERY: str = "Montgomery"; break; + case MPI_EC_TWISTEDEDWARDS: str = "Twisted Edwards"; break; + } + return str; +} + + +/* + * Return a description of the curve dialect. + */ +const char * +_gcry_ecc_dialect2str (enum ecc_dialects dialect) +{ + const char *str = "?"; + switch (dialect) + { + case ECC_DIALECT_STANDARD: str = "Standard"; break; + case ECC_DIALECT_ED25519: str = "Ed25519"; break; + } + return str; +} + + +gcry_mpi_t +_gcry_ecc_ec2os (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t p) +{ + gpg_err_code_t rc; + int pbytes = (mpi_get_nbits (p)+7)/8; + size_t n; + unsigned char *buf, *ptr; + gcry_mpi_t result; + + buf = xmalloc ( 1 + 2*pbytes ); + *buf = 04; /* Uncompressed point. */ + ptr = buf+1; + rc = _gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, x); + if (rc) + log_fatal ("mpi_print failed: %s\n", gpg_strerror (rc)); + if (n < pbytes) + { + memmove (ptr+(pbytes-n), ptr, n); + memset (ptr, 0, (pbytes-n)); + } + ptr += pbytes; + rc = _gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, y); + if (rc) + log_fatal ("mpi_print failed: %s\n", gpg_strerror (rc)); + if (n < pbytes) + { + memmove (ptr+(pbytes-n), ptr, n); + memset (ptr, 0, (pbytes-n)); + } + + rc = _gcry_mpi_scan (&result, GCRYMPI_FMT_USG, buf, 1+2*pbytes, NULL); + if (rc) + log_fatal ("mpi_scan failed: %s\n", gpg_strerror (rc)); + xfree (buf); + + return result; +} + + +/* Convert POINT into affine coordinates using the context CTX and + return a newly allocated MPI. If the conversion is not possible + NULL is returned. This function won't print an error message. */ +gcry_mpi_t +_gcry_mpi_ec_ec2os (gcry_mpi_point_t point, mpi_ec_t ectx) +{ + gcry_mpi_t g_x, g_y, result; + + g_x = mpi_new (0); + g_y = mpi_new (0); + if (_gcry_mpi_ec_get_affine (g_x, g_y, point, ectx)) + result = NULL; + else + result = _gcry_ecc_ec2os (g_x, g_y, ectx->p); + mpi_free (g_x); + mpi_free (g_y); + + return result; +} + + +/* RESULT must have been initialized and is set on success to the + point given by VALUE. */ +gcry_err_code_t +_gcry_ecc_os2ec (mpi_point_t result, gcry_mpi_t value) +{ + gcry_err_code_t rc; + size_t n; + const unsigned char *buf; + unsigned char *buf_memory; + gcry_mpi_t x, y; + + if (mpi_is_opaque (value)) + { + unsigned int nbits; + + buf = mpi_get_opaque (value, &nbits); + if (!buf) + return GPG_ERR_INV_OBJ; + n = (nbits + 7)/8; + buf_memory = NULL; + } + else + { + n = (mpi_get_nbits (value)+7)/8; + buf_memory = xmalloc (n); + rc = _gcry_mpi_print (GCRYMPI_FMT_USG, buf_memory, n, &n, value); + if (rc) + { + xfree (buf_memory); + return rc; + } + buf = buf_memory; + } + + if (n < 1) + { + xfree (buf_memory); + return GPG_ERR_INV_OBJ; + } + if (*buf != 4) + { + xfree (buf_memory); + return GPG_ERR_NOT_IMPLEMENTED; /* No support for point compression. */ + } + if ( ((n-1)%2) ) + { + xfree (buf_memory); + return GPG_ERR_INV_OBJ; + } + n = (n-1)/2; + rc = _gcry_mpi_scan (&x, GCRYMPI_FMT_USG, buf+1, n, NULL); + if (rc) + { + xfree (buf_memory); + return rc; + } + rc = _gcry_mpi_scan (&y, GCRYMPI_FMT_USG, buf+1+n, n, NULL); + xfree (buf_memory); + if (rc) + { + mpi_free (x); + return rc; + } + + mpi_set (result->x, x); + mpi_set (result->y, y); + mpi_set_ui (result->z, 1); + + mpi_free (x); + mpi_free (y); + + return 0; +} + + +/* Compute the public key from the the context EC. Obviously a + requirement is that the secret key is available in EC. On success + Q is returned; on error NULL. If Q is NULL a newly allocated point + is returned. If G or D are given they override the values taken + from EC. */ +mpi_point_t +_gcry_ecc_compute_public (mpi_point_t Q, mpi_ec_t ec, + mpi_point_t G, gcry_mpi_t d) +{ + if (!G) + G = ec->G; + if (!d) + d = ec->d; + + if (!d || !G || !ec->p || !ec->a) + return NULL; + if (ec->model == MPI_EC_TWISTEDEDWARDS && !ec->b) + return NULL; + + if (ec->dialect == ECC_DIALECT_ED25519 + && (ec->flags & PUBKEY_FLAG_EDDSA)) + { + gcry_mpi_t a; + unsigned char *digest; + + if (_gcry_ecc_eddsa_compute_h_d (&digest, d, ec)) + return NULL; + + a = mpi_snew (0); + _gcry_mpi_set_buffer (a, digest, 32, 0); + xfree (digest); + + /* And finally the public key. */ + if (!Q) + Q = mpi_point_new (0); + if (Q) + _gcry_mpi_ec_mul_point (Q, a, G, ec); + mpi_free (a); + } + else + { + if (!Q) + Q = mpi_point_new (0); + if (Q) + _gcry_mpi_ec_mul_point (Q, d, G, ec); + } + + return Q; +} diff --git a/plugins/MirOTR/Libgcrypt/cipher/ecc.c b/plugins/MirOTR/Libgcrypt/cipher/ecc.c index fcbd8e3a9d..885ff096ba 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/ecc.c +++ b/plugins/MirOTR/Libgcrypt/cipher/ecc.c @@ -1,22 +1,22 @@ /* ecc.c - Elliptic Curve Cryptography - Copyright (C) 2007, 2008 Free Software Foundation, Inc. - - This file is part of Libgcrypt. - - Libgcrypt is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of - the License, or (at your option) any later version. - - Libgcrypt is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - USA. */ + * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ /* This code is originally based on the Patch 0.1.6 for the gnupg 1.4.x branch as retrieved on 2007-03-21 from @@ -33,20 +33,17 @@ up. In fact there is not much left of the orginally code except for some variable names and the text book implementaion of the sign and verification algorithms. The arithmetic functions have entirely - been rewritten and moved to mpi/ec.c. */ + been rewritten and moved to mpi/ec.c. + ECDH encrypt and decrypt code written by Andrey Jivsov. +*/ -/* TODO: - - If we support point compression we need to decide how to compute - the keygrip - it should not change due to compression. +/* TODO: - In mpi/ec.c we use mpi_powm for x^2 mod p: Either implement a special case in mpi_powm or check whether mpi_mulm is faster. - - Decide whether we should hide the mpi_point_t definition. - - - Support more than just ECDSA. */ @@ -54,231 +51,25 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <errno.h> #include "g10lib.h" #include "mpi.h" #include "cipher.h" +#include "context.h" +#include "ec-context.h" +#include "pubkey-internal.h" +#include "ecc-common.h" -/* Definition of a curve. */ -typedef struct -{ - gcry_mpi_t p; /* Prime specifying the field GF(p). */ - gcry_mpi_t a; /* First coefficient of the Weierstrass equation. */ - gcry_mpi_t b; /* Second coefficient of the Weierstrass equation. */ - mpi_point_t G; /* Base point (generator). */ - gcry_mpi_t n; /* Order of G. */ -} elliptic_curve_t; - - -typedef struct -{ - elliptic_curve_t E; - mpi_point_t Q; /* Q = [d]G */ -} ECC_public_key; - -typedef struct -{ - elliptic_curve_t E; - mpi_point_t Q; - gcry_mpi_t d; -} ECC_secret_key; - - -/* This tables defines aliases for curve names. */ -static const struct -{ - const char *name; /* Our name. */ - const char *other; /* Other name. */ -} curve_aliases[] = +static const char *ecc_names[] = { - { "NIST P-192", "1.2.840.10045.3.1.1" }, /* X9.62 OID */ - { "NIST P-192", "prime192v1" }, /* X9.62 name. */ - { "NIST P-192", "secp192r1" }, /* SECP name. */ - - { "NIST P-224", "secp224r1" }, - { "NIST P-224", "1.3.132.0.33" }, /* SECP OID. */ - - { "NIST P-256", "1.2.840.10045.3.1.7" }, /* From NIST SP 800-78-1. */ - { "NIST P-256", "prime256v1" }, - { "NIST P-256", "secp256r1" }, - - { "NIST P-384", "secp384r1" }, - { "NIST P-384", "1.3.132.0.34" }, - - { "NIST P-521", "secp521r1" }, - { "NIST P-521", "1.3.132.0.35" }, - - { "brainpoolP160r1", "1.3.36.3.3.2.8.1.1.1" }, - { "brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3" }, - { "brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5" }, - { "brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7" }, - { "brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9" }, - { "brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11"}, - { "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13"}, - - { NULL, NULL} - }; - - - -/* This static table defines all available curves. */ -static const struct -{ - const char *desc; /* Description of the curve. */ - unsigned int nbits; /* Number of bits. */ - unsigned int fips:1; /* True if this is a FIPS140-2 approved curve. */ - const char *p; /* Order of the prime field. */ - const char *a, *b; /* The coefficients. */ - const char *n; /* The order of the base point. */ - const char *g_x, *g_y; /* Base point. */ -} domain_parms[] = - { - { - "NIST P-192", 192, 1, - "0xfffffffffffffffffffffffffffffffeffffffffffffffff", - "0xfffffffffffffffffffffffffffffffefffffffffffffffc", - "0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", - "0xffffffffffffffffffffffff99def836146bc9b1b4d22831", - - "0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012", - "0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811" - }, - { - "NIST P-224", 224, 1, - "0xffffffffffffffffffffffffffffffff000000000000000000000001", - "0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe", - "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", - "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d" , - - "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", - "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34" - }, - { - "NIST P-256", 256, 1, - "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff", - "0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc", - "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", - "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", - - "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", - "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5" - }, - { - "NIST P-384", 384, 1, - "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe" - "ffffffff0000000000000000ffffffff", - "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe" - "ffffffff0000000000000000fffffffc", - "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a" - "c656398d8a2ed19d2a85c8edd3ec2aef", - "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf" - "581a0db248b0a77aecec196accc52973", - - "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38" - "5502f25dbf55296c3a545e3872760ab7", - "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0" - "0a60b1ce1d7e819d7a431d7c90ea0e5f" - }, - { - "NIST P-521", 521, 1, - "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc", - "0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef10" - "9e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", - "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - "ffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409", - - "0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3d" - "baa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", - "0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e6" - "62c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650" - }, - - { "brainpoolP160r1", 160, 0, - "0xe95e4a5f737059dc60dfc7ad95b3d8139515620f", - "0x340e7be2a280eb74e2be61bada745d97e8f7c300", - "0x1e589a8595423412134faa2dbdec95c8d8675e58", - "0xe95e4a5f737059dc60df5991d45029409e60fc09", - "0xbed5af16ea3f6a4f62938c4631eb5af7bdbcdbc3", - "0x1667cb477a1a8ec338f94741669c976316da6321" - }, - - { "brainpoolP192r1", 192, 0, - "0xc302f41d932a36cda7a3463093d18db78fce476de1a86297", - "0x6a91174076b1e0e19c39c031fe8685c1cae040e5c69a28ef", - "0x469a28ef7c28cca3dc721d044f4496bcca7ef4146fbf25c9", - "0xc302f41d932a36cda7a3462f9e9e916b5be8f1029ac4acc1", - "0xc0a0647eaab6a48753b033c56cb0f0900a2f5c4853375fd6", - "0x14b690866abd5bb88b5f4828c1490002e6773fa2fa299b8f" - }, - - { "brainpoolP224r1", 224, 0, - "0xd7c134aa264366862a18302575d1d787b09f075797da89f57ec8c0ff", - "0x68a5e62ca9ce6c1c299803a6c1530b514e182ad8b0042a59cad29f43", - "0x2580f63ccfe44138870713b1a92369e33e2135d266dbb372386c400b", - "0xd7c134aa264366862a18302575d0fb98d116bc4b6ddebca3a5a7939f", - "0x0d9029ad2c7e5cf4340823b2a87dc68c9e4ce3174c1e6efdee12c07d", - "0x58aa56f772c0726f24c6b89e4ecdac24354b9e99caa3f6d3761402cd" - }, - - { "brainpoolP256r1", 256, 0, - "0xa9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e5377", - "0x7d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9", - "0x26dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b6", - "0xa9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a7", - "0x8bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262", - "0x547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f046997" - }, - - { "brainpoolP320r1", 320, 0, - "0xd35e472036bc4fb7e13c785ed201e065f98fcfa6f6f40def4f92b9ec7893ec28" - "fcd412b1f1b32e27", - "0x3ee30b568fbab0f883ccebd46d3f3bb8a2a73513f5eb79da66190eb085ffa9f4" - "92f375a97d860eb4", - "0x520883949dfdbc42d3ad198640688a6fe13f41349554b49acc31dccd88453981" - "6f5eb4ac8fb1f1a6", - "0xd35e472036bc4fb7e13c785ed201e065f98fcfa5b68f12a32d482ec7ee8658e9" - "8691555b44c59311", - "0x43bd7e9afb53d8b85289bcc48ee5bfe6f20137d10a087eb6e7871e2a10a599c7" - "10af8d0d39e20611", - "0x14fdd05545ec1cc8ab4093247f77275e0743ffed117182eaa9c77877aaac6ac7" - "d35245d1692e8ee1" - }, - - { "brainpoolP384r1", 384, 0, - "0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b412b1da197fb71123" - "acd3a729901d1a71874700133107ec53", - "0x7bc382c63d8c150c3c72080ace05afa0c2bea28e4fb22787139165efba91f90f" - "8aa5814a503ad4eb04a8c7dd22ce2826", - "0x04a8c7dd22ce28268b39b55416f0447c2fb77de107dcd2a62e880ea53eeb62d5" - "7cb4390295dbc9943ab78696fa504c11", - "0x8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7" - "cf3ab6af6b7fc3103b883202e9046565", - "0x1d1c64f068cf45ffa2a63a81b7c13f6b8847a3e77ef14fe3db7fcafe0cbd10e8" - "e826e03436d646aaef87b2e247d4af1e", - "0x8abe1d7520f9c2a45cb1eb8e95cfd55262b70b29feec5864e19c054ff9912928" - "0e4646217791811142820341263c5315" - }, - - { "brainpoolP512r1", 512, 0, - "0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330871" - "7d4d9b009bc66842aecda12ae6a380e62881ff2f2d82c68528aa6056583a48f3", - "0x7830a3318b603b89e2327145ac234cc594cbdd8d3df91610a83441caea9863bc" - "2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a72bf2c7b9e7c1ac4d77fc94ca", - "0x3df91610a83441caea9863bc2ded5d5aa8253aa10a2ef1c98b9ac8b57f1117a7" - "2bf2c7b9e7c1ac4d77fc94cadc083e67984050b75ebae5dd2809bd638016f723", - "0xaadd9db8dbe9c48b3fd4e6ae33c9fc07cb308db3b3c9d20ed6639cca70330870" - "553e5c414ca92619418661197fac10471db1d381085ddaddb58796829ca90069", - "0x81aee4bdd82ed9645a21322e9c4c6a9385ed9f70b5d916c1b43b62eef4d0098e" - "ff3b1f78e2d0d48d50d1687b93b97d5f7c6d5047406a5e688b352209bcb9f822", - "0x7dde385d566332ecc0eabfa9cf7822fdf209f70024a57b1aa000c55b881f8111" - "b2dcde494a5f485e5bca4bd88a2763aed1ca2b2fa8f0540678cd1e0f3ad80892" - }, - - { NULL, 0, 0, NULL, NULL, NULL, NULL } + "ecc", + "ecdsa", + "ecdh", + "eddsa", + "gost", + NULL, }; @@ -287,22 +78,10 @@ static void (*progress_cb) (void *, const char*, int, int, int); static void *progress_cb_data; -#define point_init(a) _gcry_mpi_ec_point_init ((a)) -#define point_free(a) _gcry_mpi_ec_point_free ((a)) - - /* Local prototypes. */ -static gcry_mpi_t gen_k (gcry_mpi_t p, int security_level); static void test_keys (ECC_secret_key * sk, unsigned int nbits); -static int check_secret_key (ECC_secret_key * sk); -static gpg_err_code_t sign (gcry_mpi_t input, ECC_secret_key *skey, - gcry_mpi_t r, gcry_mpi_t s); -static gpg_err_code_t verify (gcry_mpi_t input, ECC_public_key *pkey, - gcry_mpi_t r, gcry_mpi_t s); - - -static gcry_mpi_t gen_y_2 (gcry_mpi_t x, elliptic_curve_t * base); +static unsigned int ecc_get_nbits (gcry_sexp_t parms); @@ -325,254 +104,117 @@ _gcry_register_pk_ecc_progress (void (*cb) (void *, const char *, - -/* Set the value from S into D. */ -static void -point_set (mpi_point_t *d, mpi_point_t *s) -{ - mpi_set (d->x, s->x); - mpi_set (d->y, s->y); - mpi_set (d->z, s->z); -} - - -/* - * Release a curve object. - */ -static void -curve_free (elliptic_curve_t *E) -{ - mpi_free (E->p); E->p = NULL; - mpi_free (E->a); E->a = NULL; - mpi_free (E->b); E->b = NULL; - point_free (&E->G); - mpi_free (E->n); E->n = NULL; -} - - -/* - * Return a copy of a curve object. - */ -static elliptic_curve_t -curve_copy (elliptic_curve_t E) -{ - elliptic_curve_t R; - - R.p = mpi_copy (E.p); - R.a = mpi_copy (E.a); - R.b = mpi_copy (E.b); - point_init (&R.G); - point_set (&R.G, &E.G); - R.n = mpi_copy (E.n); - - return R; -} - - - -/* Helper to scan a hex string. */ -static gcry_mpi_t -scanval (const char *string) -{ - gpg_error_t err; - gcry_mpi_t val; - - err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL); - if (err) - log_fatal ("scanning ECC parameter failed: %s\n", gpg_strerror (err)); - return val; -} - - - - - -/**************** - * Solve the right side of the equation that defines a curve. - */ -static gcry_mpi_t -gen_y_2 (gcry_mpi_t x, elliptic_curve_t *base) -{ - gcry_mpi_t three, x_3, axb, y; - - three = mpi_alloc_set_ui (3); - x_3 = mpi_new (0); - axb = mpi_new (0); - y = mpi_new (0); - - mpi_powm (x_3, x, three, base->p); - mpi_mulm (axb, base->a, x, base->p); - mpi_addm (axb, axb, base->b, base->p); - mpi_addm (y, x_3, axb, base->p); - - mpi_free (x_3); - mpi_free (axb); - mpi_free (three); - return y; /* The quadratic value of the coordinate if it exist. */ -} - - - - - -/* Generate a random secret scalar k with an order of p - - At the beginning this was identical to the code is in elgamal.c. - Later imporved by mmr. Further simplified by wk. */ -static gcry_mpi_t -gen_k (gcry_mpi_t p, int security_level) +/* Standard version of the key generation. */ +static gpg_err_code_t +nist_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx, + gcry_random_level_t random_level, unsigned int nbits) { - gcry_mpi_t k; - unsigned int nbits; + mpi_point_struct Q; - nbits = mpi_get_nbits (p); - k = mpi_snew (nbits); - if (DBG_CIPHER) - log_debug ("choosing a random k of %u bits\n", nbits); + point_init (&Q); - gcry_mpi_randomize (k, nbits, security_level); + /* Generate a secret. */ + if (ctx->dialect == ECC_DIALECT_ED25519) + { + char *rndbuf; + + sk->d = mpi_snew (256); + rndbuf = _gcry_random_bytes_secure (32, random_level); + rndbuf[0] &= 0x7f; /* Clear bit 255. */ + rndbuf[0] |= 0x40; /* Set bit 254. */ + rndbuf[31] &= 0xf8; /* Clear bits 2..0 so that d mod 8 == 0 */ + _gcry_mpi_set_buffer (sk->d, rndbuf, 32, 0); + xfree (rndbuf); + } + else + sk->d = _gcry_dsa_gen_k (E->n, random_level); - mpi_mod (k, k, p); /* k = k mod p */ - return k; -} + /* Compute Q. */ + _gcry_mpi_ec_mul_point (&Q, sk->d, &E->G, ctx); -/**************** - * Generate the crypto system setup. - * As of now the fix NIST recommended values are used. - * The subgroup generator point is in another function: gen_big_point. - */ -static gpg_err_code_t -generate_curve (unsigned int nbits, const char *name, - elliptic_curve_t *curve, unsigned int *r_nbits) -{ - int idx, aliasno; + /* Copy the stuff to the key structures. */ + sk->E.model = E->model; + sk->E.dialect = E->dialect; + sk->E.p = mpi_copy (E->p); + sk->E.a = mpi_copy (E->a); + sk->E.b = mpi_copy (E->b); + point_init (&sk->E.G); + point_set (&sk->E.G, &E->G); + sk->E.n = mpi_copy (E->n); + point_init (&sk->Q); - if (name) - { - /* First check nor native curves. */ - for (idx = 0; domain_parms[idx].desc; idx++) - if (!strcmp (name, domain_parms[idx].desc)) - break; - /* If not found consult the alias table. */ - if (!domain_parms[idx].desc) - { - for (aliasno = 0; curve_aliases[aliasno].name; aliasno++) - if (!strcmp (name, curve_aliases[aliasno].other)) - break; - if (curve_aliases[aliasno].name) - { - for (idx = 0; domain_parms[idx].desc; idx++) - if (!strcmp (curve_aliases[aliasno].name, - domain_parms[idx].desc)) - break; - } - } - } + /* We want the Q=(x,y) be a "compliant key" in terms of the + * http://tools.ietf.org/html/draft-jivsov-ecc-compact, which simply + * means that we choose either Q=(x,y) or -Q=(x,p-y) such that we + * end up with the min(y,p-y) as the y coordinate. Such a public + * key allows the most efficient compression: y can simply be + * dropped because we know that it's a minimum of the two + * possibilities without any loss of security. Note that we don't + * do that for Ed25519 so that we do not violate the special + * construction of the secret key. */ + if (E->dialect == ECC_DIALECT_ED25519) + point_set (&sk->Q, &Q); else { - for (idx = 0; domain_parms[idx].desc; idx++) - if (nbits == domain_parms[idx].nbits) - break; - } - if (!domain_parms[idx].desc) - return GPG_ERR_INV_VALUE; - - /* In fips mode we only support NIST curves. Note that it is - possible to bypass this check by specifying the curve parameters - directly. */ - if (fips_mode () && !domain_parms[idx].fips ) - return GPG_ERR_NOT_SUPPORTED; - - - *r_nbits = domain_parms[idx].nbits; - curve->p = scanval (domain_parms[idx].p); - curve->a = scanval (domain_parms[idx].a); - curve->b = scanval (domain_parms[idx].b); - curve->n = scanval (domain_parms[idx].n); - curve->G.x = scanval (domain_parms[idx].g_x); - curve->G.y = scanval (domain_parms[idx].g_y); - curve->G.z = mpi_alloc_set_ui (1); - - return 0; -} + gcry_mpi_t x, y, negative; + const unsigned int pbits = mpi_get_nbits (E->p); + x = mpi_new (pbits); + y = mpi_new (pbits); + negative = mpi_new (pbits); -/* - * First obtain the setup. Over the finite field randomize an scalar - * secret value, and calculate the public point. - */ -static gpg_err_code_t -generate_key (ECC_secret_key *sk, unsigned int nbits, const char *name, - gcry_mpi_t g_x, gcry_mpi_t g_y, - gcry_mpi_t q_x, gcry_mpi_t q_y) -{ - gpg_err_code_t err; - elliptic_curve_t E; - gcry_mpi_t d; - mpi_point_t Q; - mpi_ec_t ctx; + if (_gcry_mpi_ec_get_affine (x, y, &Q, ctx)) + log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "Q"); - err = generate_curve (nbits, name, &E, &nbits); - if (err) - return err; + if (E->model == MPI_EC_WEIERSTRASS) + mpi_sub (negative, E->p, y); /* negative = p - y */ + else + mpi_sub (negative, E->p, x); /* negative = p - x */ - if (DBG_CIPHER) - { - log_mpidump ("ecc generation p", E.p); - log_mpidump ("ecc generation a", E.a); - log_mpidump ("ecc generation b", E.b); - log_mpidump ("ecc generation n", E.n); - log_mpidump ("ecc generation Gx", E.G.x); - log_mpidump ("ecc generation Gy", E.G.y); - log_mpidump ("ecc generation Gz", E.G.z); - } - - if (DBG_CIPHER) - log_debug ("choosing a random x of size %u\n", nbits); - d = gen_k (E.n, GCRY_VERY_STRONG_RANDOM); + if (mpi_cmp (negative, y) < 0) /* p - y < p */ + { + /* We need to end up with -Q; this assures that new Q's y is + the smallest one */ + mpi_sub (sk->d, E->n, sk->d); /* d = order - d */ + if (E->model == MPI_EC_WEIERSTRASS) + mpi_point_snatch_set (&sk->Q, x, negative, + mpi_alloc_set_ui (1)); + else + mpi_point_snatch_set (&sk->Q, negative, y, mpi_alloc_set_ui (1)); - /* Compute Q. */ - point_init (&Q); - ctx = _gcry_mpi_ec_init (E.p, E.a); - _gcry_mpi_ec_mul_point (&Q, d, &E.G, ctx); + if (DBG_CIPHER) + log_debug ("ecgen converted Q to a compliant point\n"); + } + else /* p - y >= p */ + { + /* No change is needed exactly 50% of the time: just copy. */ + point_set (&sk->Q, &Q); + if (DBG_CIPHER) + log_debug ("ecgen didn't need to convert Q to a compliant point\n"); + + mpi_free (negative); + if (E->model == MPI_EC_WEIERSTRASS) + mpi_free (x); + else + mpi_free (y); + } - /* Copy the stuff to the key structures. */ - sk->E.p = mpi_copy (E.p); - sk->E.a = mpi_copy (E.a); - sk->E.b = mpi_copy (E.b); - point_init (&sk->E.G); - point_set (&sk->E.G, &E.G); - sk->E.n = mpi_copy (E.n); - point_init (&sk->Q); - point_set (&sk->Q, &Q); - sk->d = mpi_copy (d); - /* We also return copies of G and Q in affine coordinates if - requested. */ - if (g_x && g_y) - { - if (_gcry_mpi_ec_get_affine (g_x, g_y, &sk->E.G, ctx)) - log_fatal ("ecc generate: Failed to get affine coordinates\n"); - } - if (q_x && q_y) - { - if (_gcry_mpi_ec_get_affine (q_x, q_y, &sk->Q, ctx)) - log_fatal ("ecc generate: Failed to get affine coordinates\n"); + if (E->model == MPI_EC_WEIERSTRASS) + mpi_free (y); + else + mpi_free (x); } - _gcry_mpi_ec_free (ctx); point_free (&Q); - mpi_free (d); - curve_free (&E); - - /* Now we can test our keys (this should never fail!). */ + /* Now we can test our keys (this should never fail!). */ test_keys (sk, nbits - 64); return 0; } -/**************** +/* * To verify correct skey it use a random information. * First, encrypt and decrypt this dummy value, * test if the information is recuperated. @@ -583,7 +225,7 @@ test_keys (ECC_secret_key *sk, unsigned int nbits) { ECC_public_key pk; gcry_mpi_t test = mpi_new (nbits); - mpi_point_t R_; + mpi_point_struct R_; gcry_mpi_t c = mpi_new (nbits); gcry_mpi_t out = mpi_new (nbits); gcry_mpi_t r = mpi_new (nbits); @@ -594,16 +236,16 @@ test_keys (ECC_secret_key *sk, unsigned int nbits) point_init (&R_); - pk.E = curve_copy (sk->E); + pk.E = _gcry_ecc_curve_copy (sk->E); point_init (&pk.Q); point_set (&pk.Q, &sk->Q); - gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM); + _gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM); - if (sign (test, sk, r, s) ) + if (_gcry_ecc_ecdsa_sign (test, sk, r, s, 0, 0) ) log_fatal ("ECDSA operation: sign failed\n"); - if (verify (test, &pk, r, s)) + if (_gcry_ecc_ecdsa_verify (test, &pk, r, s)) { log_fatal ("ECDSA operation: sign, verify failed\n"); } @@ -612,7 +254,7 @@ test_keys (ECC_secret_key *sk, unsigned int nbits) log_debug ("ECDSA operation: sign, verify ok.\n"); point_free (&pk.Q); - curve_free (&pk.E); + _gcry_ecc_curve_free (&pk.E); point_free (&R_); mpi_free (s); @@ -622,693 +264,1440 @@ test_keys (ECC_secret_key *sk, unsigned int nbits) mpi_free (test); } -/**************** + +/* * To check the validity of the value, recalculate the correspondence * between the public value and the secret one. */ static int -check_secret_key (ECC_secret_key * sk) +check_secret_key (ECC_secret_key *sk, mpi_ec_t ec, int flags) { - mpi_point_t Q; - gcry_mpi_t y_2, y2 = mpi_alloc (0); - mpi_ec_t ctx; + int rc = 1; + mpi_point_struct Q; + gcry_mpi_t x1, y1; + gcry_mpi_t x2 = NULL; + gcry_mpi_t y2 = NULL; + + point_init (&Q); + x1 = mpi_new (0); + y1 = mpi_new (0); - /* ?primarity test of 'p' */ - /* (...) //!! */ /* G in E(F_p) */ - y_2 = gen_y_2 (sk->E.G.x, &sk->E); /* y^2=x^3+a*x+b */ - mpi_mulm (y2, sk->E.G.y, sk->E.G.y, sk->E.p); /* y^2=y*y */ - if (mpi_cmp (y_2, y2)) + if (!_gcry_mpi_ec_curve_point (&sk->E.G, ec)) { if (DBG_CIPHER) log_debug ("Bad check: Point 'G' does not belong to curve 'E'!\n"); - return (1); + goto leave; } + /* G != PaI */ if (!mpi_cmp_ui (sk->E.G.z, 0)) { if (DBG_CIPHER) log_debug ("Bad check: 'G' cannot be Point at Infinity!\n"); - return (1); + goto leave; } - point_init (&Q); - ctx = _gcry_mpi_ec_init (sk->E.p, sk->E.a); - _gcry_mpi_ec_mul_point (&Q, sk->E.n, &sk->E.G, ctx); - if (mpi_cmp_ui (Q.z, 0)) + /* Check order of curve. */ + if (sk->E.dialect != ECC_DIALECT_ED25519) { - if (DBG_CIPHER) - log_debug ("check_secret_key: E is not a curve of order n\n"); - point_free (&Q); - _gcry_mpi_ec_free (ctx); - return 1; + _gcry_mpi_ec_mul_point (&Q, sk->E.n, &sk->E.G, ec); + if (mpi_cmp_ui (Q.z, 0)) + { + if (DBG_CIPHER) + log_debug ("check_secret_key: E is not a curve of order n\n"); + goto leave; + } } - /* pubkey cannot be PaI */ + + /* Pubkey cannot be PaI */ if (!mpi_cmp_ui (sk->Q.z, 0)) { if (DBG_CIPHER) log_debug ("Bad check: Q can not be a Point at Infinity!\n"); - _gcry_mpi_ec_free (ctx); - return (1); + goto leave; } + /* pubkey = [d]G over E */ - _gcry_mpi_ec_mul_point (&Q, sk->d, &sk->E.G, ctx); - if ((Q.x == sk->Q.x) && (Q.y == sk->Q.y) && (Q.z == sk->Q.z)) + if (!_gcry_ecc_compute_public (&Q, ec, &sk->E.G, sk->d)) { if (DBG_CIPHER) - log_debug - ("Bad check: There is NO correspondence between 'd' and 'Q'!\n"); - _gcry_mpi_ec_free (ctx); - return (1); + log_debug ("Bad check: computation of dG failed\n"); + goto leave; } - _gcry_mpi_ec_free (ctx); - point_free (&Q); - return 0; -} - - -/* - * Return the signature struct (r,s) from the message hash. The caller - * must have allocated R and S. - */ -static gpg_err_code_t -sign (gcry_mpi_t input, ECC_secret_key *skey, gcry_mpi_t r, gcry_mpi_t s) -{ - gpg_err_code_t err = 0; - gcry_mpi_t k, dr, sum, k_1, x; - mpi_point_t I; - mpi_ec_t ctx; - - k = NULL; - dr = mpi_alloc (0); - sum = mpi_alloc (0); - k_1 = mpi_alloc (0); - x = mpi_alloc (0); - point_init (&I); - - mpi_set_ui (s, 0); - mpi_set_ui (r, 0); - - ctx = _gcry_mpi_ec_init (skey->E.p, skey->E.a); - - while (!mpi_cmp_ui (s, 0)) /* s == 0 */ - { - while (!mpi_cmp_ui (r, 0)) /* r == 0 */ - { - /* Note, that we are guaranteed to enter this loop at least - once because r has been intialized to 0. We can't use a - do_while because we want to keep the value of R even if S - has to be recomputed. */ - mpi_free (k); - k = gen_k (skey->E.n, GCRY_STRONG_RANDOM); - _gcry_mpi_ec_mul_point (&I, k, &skey->E.G, ctx); - if (_gcry_mpi_ec_get_affine (x, NULL, &I, ctx)) - { - if (DBG_CIPHER) - log_debug ("ecc sign: Failed to get affine coordinates\n"); - err = GPG_ERR_BAD_SIGNATURE; - goto leave; - } - mpi_mod (r, x, skey->E.n); /* r = x mod n */ - } - mpi_mulm (dr, skey->d, r, skey->E.n); /* dr = d*r mod n */ - mpi_addm (sum, input, dr, skey->E.n); /* sum = hash + (d*r) mod n */ - mpi_invm (k_1, k, skey->E.n); /* k_1 = k^(-1) mod n */ - mpi_mulm (s, k_1, sum, skey->E.n); /* s = k^(-1)*(hash+(d*r)) mod n */ - } - - leave: - _gcry_mpi_ec_free (ctx); - point_free (&I); - mpi_free (x); - mpi_free (k_1); - mpi_free (sum); - mpi_free (dr); - mpi_free (k); - - return err; -} - -/* - * Check if R and S verifies INPUT. - */ -static gpg_err_code_t -verify (gcry_mpi_t input, ECC_public_key *pkey, gcry_mpi_t r, gcry_mpi_t s) -{ - gpg_err_code_t err = 0; - gcry_mpi_t h, h1, h2, x, y; - mpi_point_t Q, Q1, Q2; - mpi_ec_t ctx; - - if( !(mpi_cmp_ui (r, 0) > 0 && mpi_cmp (r, pkey->E.n) < 0) ) - return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */ - if( !(mpi_cmp_ui (s, 0) > 0 && mpi_cmp (s, pkey->E.n) < 0) ) - return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */ - - h = mpi_alloc (0); - h1 = mpi_alloc (0); - h2 = mpi_alloc (0); - x = mpi_alloc (0); - y = mpi_alloc (0); - point_init (&Q); - point_init (&Q1); - point_init (&Q2); - - ctx = _gcry_mpi_ec_init (pkey->E.p, pkey->E.a); - - /* h = s^(-1) (mod n) */ - mpi_invm (h, s, pkey->E.n); -/* log_mpidump (" h", h); */ - /* h1 = hash * s^(-1) (mod n) */ - mpi_mulm (h1, input, h, pkey->E.n); -/* log_mpidump (" h1", h1); */ - /* Q1 = [ hash * s^(-1) ]G */ - _gcry_mpi_ec_mul_point (&Q1, h1, &pkey->E.G, ctx); -/* log_mpidump ("Q1.x", Q1.x); */ -/* log_mpidump ("Q1.y", Q1.y); */ -/* log_mpidump ("Q1.z", Q1.z); */ - /* h2 = r * s^(-1) (mod n) */ - mpi_mulm (h2, r, h, pkey->E.n); -/* log_mpidump (" h2", h2); */ - /* Q2 = [ r * s^(-1) ]Q */ - _gcry_mpi_ec_mul_point (&Q2, h2, &pkey->Q, ctx); -/* log_mpidump ("Q2.x", Q2.x); */ -/* log_mpidump ("Q2.y", Q2.y); */ -/* log_mpidump ("Q2.z", Q2.z); */ - /* Q = ([hash * s^(-1)]G) + ([r * s^(-1)]Q) */ - _gcry_mpi_ec_add_points (&Q, &Q1, &Q2, ctx); -/* log_mpidump (" Q.x", Q.x); */ -/* log_mpidump (" Q.y", Q.y); */ -/* log_mpidump (" Q.z", Q.z); */ - - if (!mpi_cmp_ui (Q.z, 0)) + if (_gcry_mpi_ec_get_affine (x1, y1, &Q, ec)) { if (DBG_CIPHER) - log_debug ("ecc verify: Rejected\n"); - err = GPG_ERR_BAD_SIGNATURE; + log_debug ("Bad check: Q can not be a Point at Infinity!\n"); goto leave; } - if (_gcry_mpi_ec_get_affine (x, y, &Q, ctx)) + + if ((flags & PUBKEY_FLAG_EDDSA)) + ; /* Fixme: EdDSA is special. */ + else if (!mpi_cmp_ui (sk->Q.z, 1)) { - if (DBG_CIPHER) - log_debug ("ecc verify: Failed to get affine coordinates\n"); - err = GPG_ERR_BAD_SIGNATURE; - goto leave; + /* Fast path if Q is already in affine coordinates. */ + if (mpi_cmp (x1, sk->Q.x) || mpi_cmp (y1, sk->Q.y)) + { + if (DBG_CIPHER) + log_debug + ("Bad check: There is NO correspondence between 'd' and 'Q'!\n"); + goto leave; + } } - mpi_mod (x, x, pkey->E.n); /* x = x mod E_n */ - if (mpi_cmp (x, r)) /* x != r */ + else { - if (DBG_CIPHER) + x2 = mpi_new (0); + y2 = mpi_new (0); + if (_gcry_mpi_ec_get_affine (x2, y2, &sk->Q, ec)) { - log_mpidump (" x", x); - log_mpidump (" y", y); - log_mpidump (" r", r); - log_mpidump (" s", s); - log_debug ("ecc verify: Not verified\n"); + if (DBG_CIPHER) + log_debug ("Bad check: Q can not be a Point at Infinity!\n"); + goto leave; + } + + if (mpi_cmp (x1, x2) || mpi_cmp (y1, y2)) + { + if (DBG_CIPHER) + log_debug + ("Bad check: There is NO correspondence between 'd' and 'Q'!\n"); + goto leave; } - err = GPG_ERR_BAD_SIGNATURE; - goto leave; } - if (DBG_CIPHER) - log_debug ("ecc verify: Accepted\n"); + rc = 0; /* Okay. */ leave: - _gcry_mpi_ec_free (ctx); - point_free (&Q2); - point_free (&Q1); + mpi_free (x2); + mpi_free (x1); + mpi_free (y1); + mpi_free (y2); point_free (&Q); - mpi_free (y); - mpi_free (x); - mpi_free (h2); - mpi_free (h1); - mpi_free (h); - return err; + return rc; } - + /********************************************* ************** interface ****************** *********************************************/ -static gcry_mpi_t -ec2os (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t p) + +static gcry_err_code_t +ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) { - gpg_error_t err; - int pbytes = (mpi_get_nbits (p)+7)/8; - size_t n; - unsigned char *buf, *ptr; - gcry_mpi_t result; - - buf = gcry_xmalloc ( 1 + 2*pbytes ); - *buf = 04; /* Uncompressed point. */ - ptr = buf+1; - err = gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, x); - if (err) - log_fatal ("mpi_print failed: %s\n", gpg_strerror (err)); - if (n < pbytes) - { - memmove (ptr+(pbytes-n), ptr, n); - memset (ptr, 0, (pbytes-n)); - } - ptr += pbytes; - err = gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, y); - if (err) - log_fatal ("mpi_print failed: %s\n", gpg_strerror (err)); - if (n < pbytes) - { - memmove (ptr+(pbytes-n), ptr, n); - memset (ptr, 0, (pbytes-n)); - } - - err = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, buf, 1+2*pbytes, NULL); - if (err) - log_fatal ("mpi_scan failed: %s\n", gpg_strerror (err)); - gcry_free (buf); + gpg_err_code_t rc; + unsigned int nbits; + elliptic_curve_t E; + ECC_secret_key sk; + gcry_mpi_t x = NULL; + gcry_mpi_t y = NULL; + char *curve_name = NULL; + gcry_sexp_t l1; + gcry_random_level_t random_level; + mpi_ec_t ctx = NULL; + gcry_sexp_t curve_info = NULL; + gcry_sexp_t curve_flags = NULL; + gcry_mpi_t base = NULL; + gcry_mpi_t public = NULL; + gcry_mpi_t secret = NULL; + int flags = 0; + + memset (&E, 0, sizeof E); + memset (&sk, 0, sizeof sk); + + rc = _gcry_pk_util_get_nbits (genparms, &nbits); + if (rc) + return rc; + + /* Parse the optional "curve" parameter. */ + l1 = sexp_find_token (genparms, "curve", 0); + if (l1) + { + curve_name = _gcry_sexp_nth_string (l1, 1); + sexp_release (l1); + if (!curve_name) + return GPG_ERR_INV_OBJ; /* No curve name or value too large. */ + } - mpi_free (x); - mpi_free (y); + /* Parse the optional flags list. */ + l1 = sexp_find_token (genparms, "flags", 0); + if (l1) + { + rc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL); + sexp_release (l1); + if (rc) + goto leave; + } - return result; -} + /* Parse the deprecated optional transient-key flag. */ + l1 = sexp_find_token (genparms, "transient-key", 0); + if (l1) + { + flags |= PUBKEY_FLAG_TRANSIENT_KEY; + sexp_release (l1); + } -/* RESULT must have been initialized and is set on success to the - point given by VALUE. */ -static gcry_error_t -os2ec (mpi_point_t *result, gcry_mpi_t value) -{ - gcry_error_t err; - size_t n; - unsigned char *buf; - gcry_mpi_t x, y; + /* NBITS is required if no curve name has been given. */ + if (!nbits && !curve_name) + return GPG_ERR_NO_OBJ; /* No NBITS parameter. */ - n = (mpi_get_nbits (value)+7)/8; - buf = gcry_xmalloc (n); - err = gcry_mpi_print (GCRYMPI_FMT_USG, buf, n, &n, value); - if (err) + rc = _gcry_ecc_fill_in_curve (nbits, curve_name, &E, &nbits); + xfree (curve_name); curve_name = NULL; + if (rc) + goto leave; + + if (DBG_CIPHER) { - gcry_free (buf); - return err; + log_debug ("ecgen curve info: %s/%s\n", + _gcry_ecc_model2str (E.model), + _gcry_ecc_dialect2str (E.dialect)); + if (E.name) + log_debug ("ecgen curve used: %s\n", E.name); + log_printmpi ("ecgen curve p", E.p); + log_printmpi ("ecgen curve a", E.a); + log_printmpi ("ecgen curve b", E.b); + log_printmpi ("ecgen curve n", E.n); + log_printpnt ("ecgen curve G", &E.G, NULL); } - if (n < 1) + + if ((flags & PUBKEY_FLAG_TRANSIENT_KEY)) + random_level = GCRY_STRONG_RANDOM; + else + random_level = GCRY_VERY_STRONG_RANDOM; + + ctx = _gcry_mpi_ec_p_internal_new (E.model, E.dialect, 0, E.p, E.a, E.b); + x = mpi_new (0); + y = mpi_new (0); + + if ((flags & PUBKEY_FLAG_EDDSA)) + rc = _gcry_ecc_eddsa_genkey (&sk, &E, ctx, random_level); + else + rc = nist_generate_key (&sk, &E, ctx, random_level, nbits); + if (rc) + goto leave; + + /* Copy data to the result. */ + if (_gcry_mpi_ec_get_affine (x, y, &sk.E.G, ctx)) + log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "G"); + base = _gcry_ecc_ec2os (x, y, sk.E.p); + if (sk.E.dialect == ECC_DIALECT_ED25519 && !(flags & PUBKEY_FLAG_NOCOMP)) { - gcry_free (buf); - return GPG_ERR_INV_OBJ; + unsigned char *encpk; + unsigned int encpklen; + + rc = _gcry_ecc_eddsa_encodepoint (&sk.Q, ctx, x, y, + !!(flags & PUBKEY_FLAG_COMP), + &encpk, &encpklen); + if (rc) + return rc; + public = mpi_new (0); + mpi_set_opaque (public, encpk, encpklen*8); + encpk = NULL; } - if (*buf != 4) + else { - gcry_free (buf); - return GPG_ERR_NOT_IMPLEMENTED; /* No support for point compression. */ + if (_gcry_mpi_ec_get_affine (x, y, &sk.Q, ctx)) + log_fatal ("ecgen: Failed to get affine coordinates for %s\n", "Q"); + public = _gcry_ecc_ec2os (x, y, sk.E.p); } - if ( ((n-1)%2) ) + secret = sk.d; sk.d = NULL; + if (E.name) { - gcry_free (buf); - return GPG_ERR_INV_OBJ; + rc = sexp_build (&curve_info, NULL, "(curve %s)", E.name); + if (rc) + goto leave; } - n = (n-1)/2; - err = gcry_mpi_scan (&x, GCRYMPI_FMT_USG, buf+1, n, NULL); - if (err) + + if ((flags & PUBKEY_FLAG_PARAM) || (flags & PUBKEY_FLAG_EDDSA)) { - gcry_free (buf); - return err; + rc = sexp_build + (&curve_flags, NULL, + ((flags & PUBKEY_FLAG_PARAM) && (flags & PUBKEY_FLAG_EDDSA))? + "(flags param eddsa)" : + ((flags & PUBKEY_FLAG_PARAM))? + "(flags param)" : + "(flags eddsa)"); + if (rc) + goto leave; } - err = gcry_mpi_scan (&y, GCRYMPI_FMT_USG, buf+1+n, n, NULL); - gcry_free (buf); - if (err) + + if ((flags & PUBKEY_FLAG_PARAM) && E.name) + rc = sexp_build (r_skey, NULL, + "(key-data" + " (public-key" + " (ecc%S%S(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)))" + " (private-key" + " (ecc%S%S(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)(d%m)))" + " )", + curve_info, curve_flags, + sk.E.p, sk.E.a, sk.E.b, base, sk.E.n, public, + curve_info, curve_flags, + sk.E.p, sk.E.a, sk.E.b, base, sk.E.n, public, secret); + else + rc = sexp_build (r_skey, NULL, + "(key-data" + " (public-key" + " (ecc%S%S(q%m)))" + " (private-key" + " (ecc%S%S(q%m)(d%m)))" + " )", + curve_info, curve_flags, + public, + curve_info, curve_flags, + public, secret); + if (rc) + goto leave; + + if (DBG_CIPHER) { - mpi_free (x); - return err; + log_printmpi ("ecgen result p", sk.E.p); + log_printmpi ("ecgen result a", sk.E.a); + log_printmpi ("ecgen result b", sk.E.b); + log_printmpi ("ecgen result G", base); + log_printmpi ("ecgen result n", sk.E.n); + log_printmpi ("ecgen result Q", public); + log_printmpi ("ecgen result d", secret); + if ((flags & PUBKEY_FLAG_EDDSA)) + log_debug ("ecgen result using Ed25519+EdDSA\n"); } - mpi_set (result->x, x); - mpi_set (result->y, y); - mpi_set_ui (result->z, 1); - + leave: + mpi_free (secret); + mpi_free (public); + mpi_free (base); + { + _gcry_ecc_curve_free (&sk.E); + point_free (&sk.Q); + mpi_free (sk.d); + } + _gcry_ecc_curve_free (&E); mpi_free (x); mpi_free (y); - - return 0; + _gcry_mpi_ec_free (ctx); + sexp_release (curve_flags); + sexp_release (curve_info); + return rc; } -/* Extended version of ecc_generate. */ static gcry_err_code_t -ecc_generate_ext (int algo, unsigned int nbits, unsigned long evalue, - const gcry_sexp_t genparms, - gcry_mpi_t *skey, gcry_mpi_t **retfactors, - gcry_sexp_t *r_extrainfo) +ecc_check_secret_key (gcry_sexp_t keyparms) { - gpg_err_code_t ec; + gcry_err_code_t rc; + gcry_sexp_t l1 = NULL; + int flags = 0; + char *curvename = NULL; + gcry_mpi_t mpi_g = NULL; + gcry_mpi_t mpi_q = NULL; ECC_secret_key sk; - gcry_mpi_t g_x, g_y, q_x, q_y; - char *curve_name = NULL; - gcry_sexp_t l1; + mpi_ec_t ec = NULL; - (void)algo; - (void)evalue; - (void)r_extrainfo; + memset (&sk, 0, sizeof sk); - if (genparms) + /* Look for flags. */ + l1 = sexp_find_token (keyparms, "flags", 0); + if (l1) { - /* Parse the optional "curve" parameter. */ - l1 = gcry_sexp_find_token (genparms, "curve", 0); - if (l1) + rc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL); + if (rc) + goto leave; + } + + /* Extract the parameters. */ + if ((flags & PUBKEY_FLAG_PARAM)) + rc = sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?/q?+d", + &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n, + &mpi_q, &sk.d, NULL); + else + rc = sexp_extract_param (keyparms, NULL, "/q?+d", + &mpi_q, &sk.d, NULL); + if (rc) + goto leave; + + /* Add missing parameters using the optional curve parameter. */ + sexp_release (l1); + l1 = sexp_find_token (keyparms, "curve", 5); + if (l1) + { + curvename = sexp_nth_string (l1, 1); + if (curvename) { - curve_name = _gcry_sexp_nth_string (l1, 1); - gcry_sexp_release (l1); - if (!curve_name) - return GPG_ERR_INV_OBJ; /* No curve name or value too large. */ + rc = _gcry_ecc_update_curve_param (curvename, + &sk.E.model, &sk.E.dialect, + &sk.E.p, &sk.E.a, &sk.E.b, + &mpi_g, &sk.E.n); + if (rc) + return rc; } } + if (mpi_g) + { + point_init (&sk.E.G); + rc = _gcry_ecc_os2ec (&sk.E.G, mpi_g); + if (rc) + goto leave; + } - /* NBITS is required if no curve name has been given. */ - if (!nbits && !curve_name) - return GPG_ERR_NO_OBJ; /* No NBITS parameter. */ - - g_x = mpi_new (0); - g_y = mpi_new (0); - q_x = mpi_new (0); - q_y = mpi_new (0); - ec = generate_key (&sk, nbits, curve_name, g_x, g_y, q_x, q_y); - gcry_free (curve_name); - if (ec) - return ec; - - skey[0] = sk.E.p; - skey[1] = sk.E.a; - skey[2] = sk.E.b; - /* The function ec2os releases g_x and g_y. */ - skey[3] = ec2os (g_x, g_y, sk.E.p); - skey[4] = sk.E.n; - /* The function ec2os releases g_x and g_y. */ - skey[5] = ec2os (q_x, q_y, sk.E.p); - skey[6] = sk.d; - - point_free (&sk.E.G); - point_free (&sk.Q); - - /* Make an empty list of factors. */ - *retfactors = gcry_calloc ( 1, sizeof **retfactors ); - if (!*retfactors) - return gpg_err_code_from_syserror (); - - return 0; -} - - -static gcry_err_code_t -ecc_generate (int algo, unsigned int nbits, unsigned long evalue, - gcry_mpi_t *skey, gcry_mpi_t **retfactors) -{ - (void)evalue; - return ecc_generate_ext (algo, nbits, 0, NULL, skey, retfactors, NULL); -} + /* Guess required fields if a curve parameter has not been given. + FIXME: This is a crude hacks. We need to fix that. */ + if (!curvename) + { + sk.E.model = ((flags & PUBKEY_FLAG_EDDSA) + ? MPI_EC_TWISTEDEDWARDS + : MPI_EC_WEIERSTRASS); + sk.E.dialect = ((flags & PUBKEY_FLAG_EDDSA) + ? ECC_DIALECT_ED25519 + : ECC_DIALECT_STANDARD); + } + if (DBG_CIPHER) + { + log_debug ("ecc_testkey inf: %s/%s\n", + _gcry_ecc_model2str (sk.E.model), + _gcry_ecc_dialect2str (sk.E.dialect)); + if (sk.E.name) + log_debug ("ecc_testkey nam: %s\n", sk.E.name); + log_printmpi ("ecc_testkey p", sk.E.p); + log_printmpi ("ecc_testkey a", sk.E.a); + log_printmpi ("ecc_testkey b", sk.E.b); + log_printpnt ("ecc_testkey g", &sk.E.G, NULL); + log_printmpi ("ecc_testkey n", sk.E.n); + log_printmpi ("ecc_testkey q", mpi_q); + if (!fips_mode ()) + log_printmpi ("ecc_testkey d", sk.d); + } + if (!sk.E.p || !sk.E.a || !sk.E.b || !sk.E.G.x || !sk.E.n || !sk.d) + { + rc = GPG_ERR_NO_OBJ; + goto leave; + } + ec = _gcry_mpi_ec_p_internal_new (sk.E.model, sk.E.dialect, 0, + sk.E.p, sk.E.a, sk.E.b); -/* Return the parameters of the curve NAME. */ -static gcry_err_code_t -ecc_get_param (const char *name, gcry_mpi_t *pkey) -{ - gpg_err_code_t err; - unsigned int nbits; - elliptic_curve_t E; - mpi_ec_t ctx; - gcry_mpi_t g_x, g_y; - - err = generate_curve (0, name, &E, &nbits); - if (err) - return err; - - g_x = mpi_new (0); - g_y = mpi_new (0); - ctx = _gcry_mpi_ec_init (E.p, E.a); - if (_gcry_mpi_ec_get_affine (g_x, g_y, &E.G, ctx)) - log_fatal ("ecc get param: Failed to get affine coordinates\n"); - _gcry_mpi_ec_free (ctx); - point_free (&E.G); + if (mpi_q) + { + point_init (&sk.Q); + if (ec->dialect == ECC_DIALECT_ED25519) + rc = _gcry_ecc_eddsa_decodepoint (mpi_q, ec, &sk.Q, NULL, NULL); + else + rc = _gcry_ecc_os2ec (&sk.Q, mpi_q); + if (rc) + goto leave; + } + else + { + /* The secret key test requires Q. */ + rc = GPG_ERR_NO_OBJ; + goto leave; + } - pkey[0] = E.p; - pkey[1] = E.a; - pkey[2] = E.b; - pkey[3] = ec2os (g_x, g_y, E.p); - pkey[4] = E.n; - pkey[5] = NULL; + if (check_secret_key (&sk, ec, flags)) + rc = GPG_ERR_BAD_SECKEY; - return 0; + leave: + _gcry_mpi_ec_free (ec); + _gcry_mpi_release (sk.E.p); + _gcry_mpi_release (sk.E.a); + _gcry_mpi_release (sk.E.b); + _gcry_mpi_release (mpi_g); + point_free (&sk.E.G); + _gcry_mpi_release (sk.E.n); + _gcry_mpi_release (mpi_q); + point_free (&sk.Q); + _gcry_mpi_release (sk.d); + xfree (curvename); + sexp_release (l1); + if (DBG_CIPHER) + log_debug ("ecc_testkey => %s\n", gpg_strerror (rc)); + return rc; } static gcry_err_code_t -ecc_check_secret_key (int algo, gcry_mpi_t *skey) +ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) { - gpg_err_code_t err; + gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_mpi_t data = NULL; + gcry_sexp_t l1 = NULL; + char *curvename = NULL; + gcry_mpi_t mpi_g = NULL; + gcry_mpi_t mpi_q = NULL; ECC_secret_key sk; + gcry_mpi_t sig_r = NULL; + gcry_mpi_t sig_s = NULL; - (void)algo; + memset (&sk, 0, sizeof sk); - if (!skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] || !skey[5] - || !skey[6] || !skey[7] || !skey[8] || !skey[9] || !skey[10]) - return GPG_ERR_BAD_MPI; + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN, 0); - sk.E.p = skey[0]; - sk.E.a = skey[1]; - sk.E.b = skey[2]; - point_init (&sk.E.G); - err = os2ec (&sk.E.G, skey[3]); - if (err) + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_mpidump ("ecc_sign data", data); + + /* + * Extract the key. + */ + if ((ctx.flags & PUBKEY_FLAG_PARAM)) + rc = sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?/q?+d", + &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n, + &mpi_q, &sk.d, NULL); + else + rc = sexp_extract_param (keyparms, NULL, "/q?+d", + &mpi_q, &sk.d, NULL); + if (rc) + goto leave; + if (mpi_g) { - point_free (&sk.E.G); - return err; + point_init (&sk.E.G); + rc = _gcry_ecc_os2ec (&sk.E.G, mpi_g); + if (rc) + goto leave; } - sk.E.n = skey[4]; - point_init (&sk.Q); - err = os2ec (&sk.Q, skey[5]); - if (err) + /* Add missing parameters using the optional curve parameter. */ + sexp_release (l1); + l1 = sexp_find_token (keyparms, "curve", 5); + if (l1) + { + curvename = sexp_nth_string (l1, 1); + if (curvename) + { + rc = _gcry_ecc_fill_in_curve (0, curvename, &sk.E, NULL); + if (rc) + return rc; + } + } + /* Guess required fields if a curve parameter has not been given. + FIXME: This is a crude hacks. We need to fix that. */ + if (!curvename) + { + sk.E.model = ((ctx.flags & PUBKEY_FLAG_EDDSA) + ? MPI_EC_TWISTEDEDWARDS + : MPI_EC_WEIERSTRASS); + sk.E.dialect = ((ctx.flags & PUBKEY_FLAG_EDDSA) + ? ECC_DIALECT_ED25519 + : ECC_DIALECT_STANDARD); + } + if (DBG_CIPHER) { - point_free (&sk.E.G); - point_free (&sk.Q); - return err; + log_debug ("ecc_sign info: %s/%s%s\n", + _gcry_ecc_model2str (sk.E.model), + _gcry_ecc_dialect2str (sk.E.dialect), + (ctx.flags & PUBKEY_FLAG_EDDSA)? "+EdDSA":""); + if (sk.E.name) + log_debug ("ecc_sign name: %s\n", sk.E.name); + log_printmpi ("ecc_sign p", sk.E.p); + log_printmpi ("ecc_sign a", sk.E.a); + log_printmpi ("ecc_sign b", sk.E.b); + log_printpnt ("ecc_sign g", &sk.E.G, NULL); + log_printmpi ("ecc_sign n", sk.E.n); + log_printmpi ("ecc_sign q", mpi_q); + if (!fips_mode ()) + log_printmpi ("ecc_sign d", sk.d); + } + if (!sk.E.p || !sk.E.a || !sk.E.b || !sk.E.G.x || !sk.E.n || !sk.d) + { + rc = GPG_ERR_NO_OBJ; + goto leave; } - sk.d = skey[6]; - if (check_secret_key (&sk)) + sig_r = mpi_new (0); + sig_s = mpi_new (0); + if ((ctx.flags & PUBKEY_FLAG_EDDSA)) + { + /* EdDSA requires the public key. */ + rc = _gcry_ecc_eddsa_sign (data, &sk, sig_r, sig_s, ctx.hash_algo, mpi_q); + if (!rc) + rc = sexp_build (r_sig, NULL, + "(sig-val(eddsa(r%M)(s%M)))", sig_r, sig_s); + } + else if ((ctx.flags & PUBKEY_FLAG_GOST)) + { + rc = _gcry_ecc_gost_sign (data, &sk, sig_r, sig_s); + if (!rc) + rc = sexp_build (r_sig, NULL, + "(sig-val(gost(r%M)(s%M)))", sig_r, sig_s); + } + else { - point_free (&sk.E.G); - point_free (&sk.Q); - return GPG_ERR_BAD_SECKEY; + rc = _gcry_ecc_ecdsa_sign (data, &sk, sig_r, sig_s, + ctx.flags, ctx.hash_algo); + if (!rc) + rc = sexp_build (r_sig, NULL, + "(sig-val(ecdsa(r%M)(s%M)))", sig_r, sig_s); } + + + leave: + _gcry_mpi_release (sk.E.p); + _gcry_mpi_release (sk.E.a); + _gcry_mpi_release (sk.E.b); + _gcry_mpi_release (mpi_g); point_free (&sk.E.G); + _gcry_mpi_release (sk.E.n); + _gcry_mpi_release (mpi_q); point_free (&sk.Q); - return 0; + _gcry_mpi_release (sk.d); + _gcry_mpi_release (sig_r); + _gcry_mpi_release (sig_s); + xfree (curvename); + _gcry_mpi_release (data); + sexp_release (l1); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("ecc_sign => %s\n", gpg_strerror (rc)); + return rc; } static gcry_err_code_t -ecc_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey) +ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) { - gpg_err_code_t err; - ECC_secret_key sk; + gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_sexp_t l1 = NULL; + char *curvename = NULL; + gcry_mpi_t mpi_g = NULL; + gcry_mpi_t mpi_q = NULL; + gcry_mpi_t sig_r = NULL; + gcry_mpi_t sig_s = NULL; + gcry_mpi_t data = NULL; + ECC_public_key pk; + int sigflags; - (void)algo; + memset (&pk, 0, sizeof pk); + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY, + ecc_get_nbits (s_keyparms)); + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_mpidump ("ecc_verify data", data); + + /* + * Extract the signature value. + */ + rc = _gcry_pk_util_preparse_sigval (s_sig, ecc_names, &l1, &sigflags); + if (rc) + goto leave; + rc = sexp_extract_param (l1, NULL, (sigflags & PUBKEY_FLAG_EDDSA)? "/rs":"rs", + &sig_r, &sig_s, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_mpidump ("ecc_verify s_r", sig_r); + log_mpidump ("ecc_verify s_s", sig_s); + } + if ((ctx.flags & PUBKEY_FLAG_EDDSA) ^ (sigflags & PUBKEY_FLAG_EDDSA)) + { + rc = GPG_ERR_CONFLICT; /* Inconsistent use of flag/algoname. */ + goto leave; + } - if (!data || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] - || !skey[5] || !skey[6] ) - return GPG_ERR_BAD_MPI; - sk.E.p = skey[0]; - sk.E.a = skey[1]; - sk.E.b = skey[2]; - point_init (&sk.E.G); - err = os2ec (&sk.E.G, skey[3]); - if (err) + /* + * Extract the key. + */ + if ((ctx.flags & PUBKEY_FLAG_PARAM)) + rc = sexp_extract_param (s_keyparms, NULL, "-p?a?b?g?n?/q", + &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n, + &mpi_q, NULL); + else + rc = sexp_extract_param (s_keyparms, NULL, "/q", + &mpi_q, NULL); + if (rc) + goto leave; + if (mpi_g) { - point_free (&sk.E.G); - return err; + point_init (&pk.E.G); + rc = _gcry_ecc_os2ec (&pk.E.G, mpi_g); + if (rc) + goto leave; } - sk.E.n = skey[4]; - point_init (&sk.Q); - err = os2ec (&sk.Q, skey[5]); - if (err) + /* Add missing parameters using the optional curve parameter. */ + sexp_release (l1); + l1 = sexp_find_token (s_keyparms, "curve", 5); + if (l1) { - point_free (&sk.E.G); - point_free (&sk.Q); - return err; + curvename = sexp_nth_string (l1, 1); + if (curvename) + { + rc = _gcry_ecc_fill_in_curve (0, curvename, &pk.E, NULL); + if (rc) + return rc; + } + } + /* Guess required fields if a curve parameter has not been given. + FIXME: This is a crude hacks. We need to fix that. */ + if (!curvename) + { + pk.E.model = ((sigflags & PUBKEY_FLAG_EDDSA) + ? MPI_EC_TWISTEDEDWARDS + : MPI_EC_WEIERSTRASS); + pk.E.dialect = ((sigflags & PUBKEY_FLAG_EDDSA) + ? ECC_DIALECT_ED25519 + : ECC_DIALECT_STANDARD); } - sk.d = skey[6]; - resarr[0] = mpi_alloc (mpi_get_nlimbs (sk.E.p)); - resarr[1] = mpi_alloc (mpi_get_nlimbs (sk.E.p)); - err = sign (data, &sk, resarr[0], resarr[1]); - if (err) + if (DBG_CIPHER) { - mpi_free (resarr[0]); - mpi_free (resarr[1]); - resarr[0] = NULL; /* Mark array as released. */ + log_debug ("ecc_verify info: %s/%s%s\n", + _gcry_ecc_model2str (pk.E.model), + _gcry_ecc_dialect2str (pk.E.dialect), + (sigflags & PUBKEY_FLAG_EDDSA)? "+EdDSA":""); + if (pk.E.name) + log_debug ("ecc_verify name: %s\n", pk.E.name); + log_printmpi ("ecc_verify p", pk.E.p); + log_printmpi ("ecc_verify a", pk.E.a); + log_printmpi ("ecc_verify b", pk.E.b); + log_printpnt ("ecc_verify g", &pk.E.G, NULL); + log_printmpi ("ecc_verify n", pk.E.n); + log_printmpi ("ecc_verify q", mpi_q); } - point_free (&sk.E.G); - point_free (&sk.Q); - return err; + if (!pk.E.p || !pk.E.a || !pk.E.b || !pk.E.G.x || !pk.E.n || !mpi_q) + { + rc = GPG_ERR_NO_OBJ; + goto leave; + } + + + /* + * Verify the signature. + */ + if ((sigflags & PUBKEY_FLAG_EDDSA)) + { + rc = _gcry_ecc_eddsa_verify (data, &pk, sig_r, sig_s, + ctx.hash_algo, mpi_q); + } + else if ((sigflags & PUBKEY_FLAG_GOST)) + { + point_init (&pk.Q); + rc = _gcry_ecc_os2ec (&pk.Q, mpi_q); + if (rc) + goto leave; + + rc = _gcry_ecc_gost_verify (data, &pk, sig_r, sig_s); + } + else + { + point_init (&pk.Q); + if (pk.E.dialect == ECC_DIALECT_ED25519) + { + mpi_ec_t ec; + + /* Fixme: Factor the curve context setup out of eddsa_verify + and ecdsa_verify. So that we don't do it twice. */ + ec = _gcry_mpi_ec_p_internal_new (pk.E.model, pk.E.dialect, 0, + pk.E.p, pk.E.a, pk.E.b); + + rc = _gcry_ecc_eddsa_decodepoint (mpi_q, ec, &pk.Q, NULL, NULL); + _gcry_mpi_ec_free (ec); + } + else + { + rc = _gcry_ecc_os2ec (&pk.Q, mpi_q); + } + if (rc) + goto leave; + + if (mpi_is_opaque (data)) + { + const void *abuf; + unsigned int abits, qbits; + gcry_mpi_t a; + + qbits = mpi_get_nbits (pk.E.n); + + abuf = mpi_get_opaque (data, &abits); + rc = _gcry_mpi_scan (&a, GCRYMPI_FMT_USG, abuf, (abits+7)/8, NULL); + if (!rc) + { + if (abits > qbits) + mpi_rshift (a, a, abits - qbits); + + rc = _gcry_ecc_ecdsa_verify (a, &pk, sig_r, sig_s); + _gcry_mpi_release (a); + } + } + else + rc = _gcry_ecc_ecdsa_verify (data, &pk, sig_r, sig_s); + } + + leave: + _gcry_mpi_release (pk.E.p); + _gcry_mpi_release (pk.E.a); + _gcry_mpi_release (pk.E.b); + _gcry_mpi_release (mpi_g); + point_free (&pk.E.G); + _gcry_mpi_release (pk.E.n); + _gcry_mpi_release (mpi_q); + point_free (&pk.Q); + _gcry_mpi_release (data); + _gcry_mpi_release (sig_r); + _gcry_mpi_release (sig_s); + xfree (curvename); + sexp_release (l1); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("ecc_verify => %s\n", rc?gpg_strerror (rc):"Good"); + return rc; } + +/* ecdh raw is classic 2-round DH protocol published in 1976. + * + * Overview of ecc_encrypt_raw and ecc_decrypt_raw. + * + * As with any PK operation, encrypt version uses a public key and + * decrypt -- private. + * + * Symbols used below: + * G - field generator point + * d - private long-term scalar + * dG - public long-term key + * k - ephemeral scalar + * kG - ephemeral public key + * dkG - shared secret + * + * ecc_encrypt_raw description: + * input: + * data[0] : private scalar (k) + * output: A new S-expression with the parameters: + * s : shared point (kdG) + * e : generated ephemeral public key (kG) + * + * ecc_decrypt_raw description: + * input: + * data[0] : a point kG (ephemeral public key) + * output: + * result[0] : shared point (kdG) + */ static gcry_err_code_t -ecc_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey, - int (*cmp)(void *, gcry_mpi_t), void *opaquev) +ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms) { - gpg_err_code_t err; + gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_sexp_t l1 = NULL; + char *curvename = NULL; + gcry_mpi_t mpi_g = NULL; + gcry_mpi_t mpi_q = NULL; + gcry_mpi_t mpi_s = NULL; + gcry_mpi_t mpi_e = NULL; + gcry_mpi_t data = NULL; ECC_public_key pk; + mpi_ec_t ec = NULL; + + memset (&pk, 0, sizeof pk); + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT, + ecc_get_nbits (keyparms)); + + /* + * Extract the data. + */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_mpidump ("ecc_encrypt data", data); + if (mpi_is_opaque (data)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + } - (void)algo; - (void)cmp; - (void)opaquev; - if (!data[0] || !data[1] || !hash || !pkey[0] || !pkey[1] || !pkey[2] - || !pkey[3] || !pkey[4] || !pkey[5] ) - return GPG_ERR_BAD_MPI; + /* + * Extract the key. + */ + rc = sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?+q", + &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n, + &mpi_q, NULL); + if (rc) + goto leave; + if (mpi_g) + { + point_init (&pk.E.G); + rc = _gcry_ecc_os2ec (&pk.E.G, mpi_g); + if (rc) + goto leave; + } + /* Add missing parameters using the optional curve parameter. */ + sexp_release (l1); + l1 = sexp_find_token (keyparms, "curve", 5); + if (l1) + { + curvename = sexp_nth_string (l1, 1); + if (curvename) + { + rc = _gcry_ecc_fill_in_curve (0, curvename, &pk.E, NULL); + if (rc) + return rc; + } + } + /* Guess required fields if a curve parameter has not been given. */ + if (!curvename) + { + pk.E.model = MPI_EC_WEIERSTRASS; + pk.E.dialect = ECC_DIALECT_STANDARD; + } - pk.E.p = pkey[0]; - pk.E.a = pkey[1]; - pk.E.b = pkey[2]; - point_init (&pk.E.G); - err = os2ec (&pk.E.G, pkey[3]); - if (err) + if (DBG_CIPHER) { - point_free (&pk.E.G); - return err; + log_debug ("ecc_encrypt info: %s/%s\n", + _gcry_ecc_model2str (pk.E.model), + _gcry_ecc_dialect2str (pk.E.dialect)); + if (pk.E.name) + log_debug ("ecc_encrypt name: %s\n", pk.E.name); + log_printmpi ("ecc_encrypt p", pk.E.p); + log_printmpi ("ecc_encrypt a", pk.E.a); + log_printmpi ("ecc_encrypt b", pk.E.b); + log_printpnt ("ecc_encrypt g", &pk.E.G, NULL); + log_printmpi ("ecc_encrypt n", pk.E.n); + log_printmpi ("ecc_encrypt q", mpi_q); } - pk.E.n = pkey[4]; - point_init (&pk.Q); - err = os2ec (&pk.Q, pkey[5]); - if (err) + if (!pk.E.p || !pk.E.a || !pk.E.b || !pk.E.G.x || !pk.E.n || !mpi_q) { - point_free (&pk.E.G); - point_free (&pk.Q); - return err; + rc = GPG_ERR_NO_OBJ; + goto leave; } - err = verify (hash, &pk, data[0], data[1]); + /* Convert the public key. */ + if (mpi_q) + { + point_init (&pk.Q); + rc = _gcry_ecc_os2ec (&pk.Q, mpi_q); + if (rc) + goto leave; + } + + /* Compute the encrypted value. */ + ec = _gcry_mpi_ec_p_internal_new (pk.E.model, pk.E.dialect, 0, + pk.E.p, pk.E.a, pk.E.b); + + /* The following is false: assert( mpi_cmp_ui( R.x, 1 )==0 );, so */ + { + mpi_point_struct R; /* Result that we return. */ + gcry_mpi_t x, y; + + x = mpi_new (0); + y = mpi_new (0); + + point_init (&R); + + /* R = kQ <=> R = kdG */ + _gcry_mpi_ec_mul_point (&R, data, &pk.Q, ec); + if (_gcry_mpi_ec_get_affine (x, y, &R, ec)) + log_fatal ("ecdh: Failed to get affine coordinates for kdG\n"); + mpi_s = _gcry_ecc_ec2os (x, y, pk.E.p); + + /* R = kG */ + _gcry_mpi_ec_mul_point (&R, data, &pk.E.G, ec); + + if (_gcry_mpi_ec_get_affine (x, y, &R, ec)) + log_fatal ("ecdh: Failed to get affine coordinates for kG\n"); + mpi_e = _gcry_ecc_ec2os (x, y, pk.E.p); + + mpi_free (x); + mpi_free (y); + + point_free (&R); + } + + rc = sexp_build (r_ciph, NULL, "(enc-val(ecdh(s%m)(e%m)))", mpi_s, mpi_e); + + leave: + _gcry_mpi_release (pk.E.p); + _gcry_mpi_release (pk.E.a); + _gcry_mpi_release (pk.E.b); + _gcry_mpi_release (mpi_g); point_free (&pk.E.G); + _gcry_mpi_release (pk.E.n); + _gcry_mpi_release (mpi_q); point_free (&pk.Q); - return err; + _gcry_mpi_release (data); + _gcry_mpi_release (mpi_s); + _gcry_mpi_release (mpi_e); + xfree (curvename); + _gcry_mpi_ec_free (ec); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("ecc_encrypt => %s\n", gpg_strerror (rc)); + return rc; } +/* input: + * data[0] : a point kG (ephemeral public key) + * output: + * resaddr[0] : shared point kdG + * + * see ecc_encrypt_raw for details. + */ +static gcry_err_code_t +ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) +{ + gpg_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_sexp_t l1 = NULL; + gcry_mpi_t data_e = NULL; + ECC_secret_key sk; + gcry_mpi_t mpi_g = NULL; + char *curvename = NULL; + mpi_ec_t ec = NULL; + mpi_point_struct kG; + mpi_point_struct R; + gcry_mpi_t r = NULL; + + memset (&sk, 0, sizeof sk); + point_init (&kG); + point_init (&R); + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, + ecc_get_nbits (keyparms)); + + /* + * Extract the data. + */ + rc = _gcry_pk_util_preparse_encval (s_data, ecc_names, &l1, &ctx); + if (rc) + goto leave; + rc = sexp_extract_param (l1, NULL, "e", &data_e, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + log_printmpi ("ecc_decrypt d_e", data_e); + if (mpi_is_opaque (data_e)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + } + /* + * Extract the key. + */ + rc = sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?+d", + &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n, + &sk.d, NULL); + if (rc) + goto leave; + if (mpi_g) + { + point_init (&sk.E.G); + rc = _gcry_ecc_os2ec (&sk.E.G, mpi_g); + if (rc) + goto leave; + } + /* Add missing parameters using the optional curve parameter. */ + sexp_release (l1); + l1 = sexp_find_token (keyparms, "curve", 5); + if (l1) + { + curvename = sexp_nth_string (l1, 1); + if (curvename) + { + rc = _gcry_ecc_fill_in_curve (0, curvename, &sk.E, NULL); + if (rc) + return rc; + } + } + /* Guess required fields if a curve parameter has not been given. */ + if (!curvename) + { + sk.E.model = MPI_EC_WEIERSTRASS; + sk.E.dialect = ECC_DIALECT_STANDARD; + } + if (DBG_CIPHER) + { + log_debug ("ecc_decrypt info: %s/%s\n", + _gcry_ecc_model2str (sk.E.model), + _gcry_ecc_dialect2str (sk.E.dialect)); + if (sk.E.name) + log_debug ("ecc_decrypt name: %s\n", sk.E.name); + log_printmpi ("ecc_decrypt p", sk.E.p); + log_printmpi ("ecc_decrypt a", sk.E.a); + log_printmpi ("ecc_decrypt b", sk.E.b); + log_printpnt ("ecc_decrypt g", &sk.E.G, NULL); + log_printmpi ("ecc_decrypt n", sk.E.n); + if (!fips_mode ()) + log_printmpi ("ecc_decrypt d", sk.d); + } + if (!sk.E.p || !sk.E.a || !sk.E.b || !sk.E.G.x || !sk.E.n || !sk.d) + { + rc = GPG_ERR_NO_OBJ; + goto leave; + } + + + /* + * Compute the plaintext. + */ + rc = _gcry_ecc_os2ec (&kG, data_e); + if (rc) + { + point_free (&kG); + return rc; + } + + ec = _gcry_mpi_ec_p_internal_new (sk.E.model, sk.E.dialect, 0, + sk.E.p, sk.E.a, sk.E.b); + + /* R = dkG */ + _gcry_mpi_ec_mul_point (&R, sk.d, &kG, ec); + + /* The following is false: assert( mpi_cmp_ui( R.x, 1 )==0 );, so: */ + { + gcry_mpi_t x, y; + + x = mpi_new (0); + y = mpi_new (0); + + if (_gcry_mpi_ec_get_affine (x, y, &R, ec)) + log_fatal ("ecdh: Failed to get affine coordinates\n"); + + r = _gcry_ecc_ec2os (x, y, sk.E.p); + if (!r) + rc = gpg_err_code_from_syserror (); + else + rc = 0; + mpi_free (x); + mpi_free (y); + } + if (DBG_CIPHER) + log_printmpi ("ecc_decrypt res", r); + + if (!rc) + rc = sexp_build (r_plain, NULL, "(value %m)", r); + + leave: + point_free (&R); + point_free (&kG); + _gcry_mpi_release (r); + _gcry_mpi_release (sk.E.p); + _gcry_mpi_release (sk.E.a); + _gcry_mpi_release (sk.E.b); + _gcry_mpi_release (mpi_g); + point_free (&sk.E.G); + _gcry_mpi_release (sk.E.n); + _gcry_mpi_release (sk.d); + _gcry_mpi_release (data_e); + xfree (curvename); + sexp_release (l1); + _gcry_mpi_ec_free (ec); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("ecc_decrypt => %s\n", gpg_strerror (rc)); + return rc; +} + + +/* Return the number of bits for the key described by PARMS. On error + * 0 is returned. The format of PARMS starts with the algorithm name; + * for example: + * + * (ecc + * (p <mpi>) + * (a <mpi>) + * (b <mpi>) + * (g <mpi>) + * (n <mpi>) + * (q <mpi>)) + * + * More parameters may be given currently P is needed. FIXME: We + * need allow for a "curve" parameter. + */ static unsigned int -ecc_get_nbits (int algo, gcry_mpi_t *pkey) +ecc_get_nbits (gcry_sexp_t parms) { - (void)algo; + gcry_sexp_t l1; + gcry_mpi_t p; + unsigned int nbits = 0; + char *curve; + + l1 = sexp_find_token (parms, "p", 1); + if (!l1) + { /* Parameter P not found - check whether we have "curve". */ + l1 = sexp_find_token (parms, "curve", 5); + if (!l1) + return 0; /* Neither P nor CURVE found. */ + + curve = sexp_nth_string (l1, 1); + sexp_release (l1); + if (!curve) + return 0; /* No curve name given (or out of core). */ - return mpi_get_nbits (pkey[0]); + if (_gcry_ecc_fill_in_curve (0, curve, NULL, &nbits)) + nbits = 0; + xfree (curve); + } + else + { + p = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + sexp_release (l1); + if (p) + { + nbits = mpi_get_nbits (p); + _gcry_mpi_release (p); + } + } + return nbits; } - /* See rsa.c for a description of this function. */ static gpg_err_code_t -compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam) +compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparms) { - static const char names[] = "pabgnq"; - gpg_err_code_t ec = 0; +#define N_COMPONENTS 6 + static const char names[N_COMPONENTS+1] = "pabgnq"; + gpg_err_code_t rc; gcry_sexp_t l1; - gcry_mpi_t values[6]; + gcry_mpi_t values[N_COMPONENTS]; int idx; + char *curvename = NULL; + int flags = 0; + enum gcry_mpi_ec_models model = 0; + enum ecc_dialects dialect = 0; - /* Clear the values for easier error cleanup. */ - for (idx=0; idx < 6; idx++) + /* Clear the values first. */ + for (idx=0; idx < N_COMPONENTS; idx++) values[idx] = NULL; - - /* Fill values with all available parameters. */ - for (idx=0; idx < 6; idx++) + + + /* Look for flags. */ + l1 = sexp_find_token (keyparms, "flags", 0); + if (l1) { - l1 = gcry_sexp_find_token (keyparam, names+idx, 1); - if (l1) - { - values[idx] = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (l1); - if (!values[idx]) - { - ec = GPG_ERR_INV_OBJ; - goto leave; - } - } + rc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL); + if (rc) + goto leave; + } + + /* Extract the parameters. */ + if ((flags & PUBKEY_FLAG_PARAM)) + { + if ((flags & PUBKEY_FLAG_EDDSA)) + rc = sexp_extract_param (keyparms, NULL, "p?a?b?g?n?/q", + &values[0], &values[1], &values[2], + &values[3], &values[4], &values[5], + NULL); + else + rc = sexp_extract_param (keyparms, NULL, "p?a?b?g?n?q", + &values[0], &values[1], &values[2], + &values[3], &values[4], &values[5], + NULL); } - + else + { + if ((flags & PUBKEY_FLAG_EDDSA)) + rc = sexp_extract_param (keyparms, NULL, "/q", + &values[5], NULL); + else + rc = sexp_extract_param (keyparms, NULL, "q", + &values[5], NULL); + } + if (rc) + goto leave; + /* Check whether a curve parameter is available and use that to fill in missing values. */ - l1 = gcry_sexp_find_token (keyparam, "curve", 5); + sexp_release (l1); + l1 = sexp_find_token (keyparms, "curve", 5); if (l1) { - char *curve; - gcry_mpi_t tmpvalues[6]; - - for (idx = 0; idx < 6; idx++) - tmpvalues[idx] = NULL; - - curve = _gcry_sexp_nth_string (l1, 1); - if (!curve) + curvename = sexp_nth_string (l1, 1); + if (curvename) { - ec = GPG_ERR_INV_OBJ; /* Name missing or out of core. */ - goto leave; + rc = _gcry_ecc_update_curve_param (curvename, + &model, &dialect, + &values[0], &values[1], &values[2], + &values[3], &values[4]); + if (rc) + goto leave; } - ec = ecc_get_param (curve, tmpvalues); - gcry_free (curve); - if (ec) - goto leave; + } - for (idx = 0; idx < 6; idx++) - { - if (!values[idx]) - values[idx] = tmpvalues[idx]; - else - mpi_free (tmpvalues[idx]); - } + /* Guess required fields if a curve parameter has not been given. + FIXME: This is a crude hacks. We need to fix that. */ + if (!curvename) + { + model = ((flags & PUBKEY_FLAG_EDDSA) + ? MPI_EC_TWISTEDEDWARDS + : MPI_EC_WEIERSTRASS); + dialect = ((flags & PUBKEY_FLAG_EDDSA) + ? ECC_DIALECT_ED25519 + : ECC_DIALECT_STANDARD); } /* Check that all parameters are known and normalize all MPIs (that - should not be required but we use an internal fucntion later and + should not be required but we use an internal function later and thus we better make 100% sure that they are normalized). */ - for (idx = 0; idx < 6; idx++) + for (idx = 0; idx < N_COMPONENTS; idx++) if (!values[idx]) { - ec = GPG_ERR_NO_OBJ; + rc = GPG_ERR_NO_OBJ; goto leave; } else _gcry_mpi_normalize (values[idx]); - + + /* Uncompress the public key with the exception of EdDSA where + compression is the default and we thus compute the keygrip using + the compressed version. Because we don't support any non-eddsa + compression, the only thing we need to do is to compress + EdDSA. */ + if ((flags & PUBKEY_FLAG_EDDSA)) + { + if (dialect == ECC_DIALECT_ED25519) + rc = _gcry_ecc_eddsa_ensure_compact (values[5], 256); + else + rc = GPG_ERR_NOT_IMPLEMENTED; + if (rc) + goto leave; + } + /* Hash them all. */ - for (idx = 0; idx < 6; idx++) + for (idx = 0; idx < N_COMPONENTS; idx++) { char buf[30]; - unsigned char *rawmpi; - unsigned int rawmpilen; - - rawmpi = _gcry_mpi_get_buffer (values[idx], &rawmpilen, NULL); - if (!rawmpi) + + if (mpi_is_opaque (values[idx])) { - ec = gpg_err_code_from_syserror (); - goto leave; + const unsigned char *raw; + unsigned int n; + + raw = mpi_get_opaque (values[idx], &n); + n = (n + 7)/8; + snprintf (buf, sizeof buf, "(1:%c%u:", names[idx], n); + _gcry_md_write (md, buf, strlen (buf)); + _gcry_md_write (md, raw, n); + _gcry_md_write (md, ")", 1); + } + else + { + unsigned char *rawmpi; + unsigned int rawmpilen; + + rawmpi = _gcry_mpi_get_buffer (values[idx], 0, &rawmpilen, NULL); + if (!rawmpi) + { + rc = gpg_err_code_from_syserror (); + goto leave; + } + snprintf (buf, sizeof buf, "(1:%c%u:", names[idx], rawmpilen); + _gcry_md_write (md, buf, strlen (buf)); + _gcry_md_write (md, rawmpi, rawmpilen); + _gcry_md_write (md, ")", 1); + xfree (rawmpi); } - snprintf (buf, sizeof buf, "(1:%c%u:", names[idx], rawmpilen); - gcry_md_write (md, buf, strlen (buf)); - gcry_md_write (md, rawmpi, rawmpilen); - gcry_md_write (md, ")", 1); - gcry_free (rawmpi); } leave: - for (idx = 0; idx < 6; idx++) + xfree (curvename); + sexp_release (l1); + for (idx = 0; idx < N_COMPONENTS; idx++) _gcry_mpi_release (values[idx]); - - return ec; + + return rc; +#undef N_COMPONENTS } + +/* + Low-level API helper functions. + */ + +/* This is the worker function for gcry_pubkey_get_sexp for ECC + algorithms. Note that the caller has already stored NULL at + R_SEXP. */ +gpg_err_code_t +_gcry_pk_ecc_get_sexp (gcry_sexp_t *r_sexp, int mode, mpi_ec_t ec) +{ + gpg_err_code_t rc; + gcry_mpi_t mpi_G = NULL; + gcry_mpi_t mpi_Q = NULL; + + if (!ec->p || !ec->a || !ec->b || !ec->G || !ec->n) + return GPG_ERR_BAD_CRYPT_CTX; + + if (mode == GCRY_PK_GET_SECKEY && !ec->d) + return GPG_ERR_NO_SECKEY; + + /* Compute the public point if it is missing. */ + if (!ec->Q && ec->d) + ec->Q = _gcry_ecc_compute_public (NULL, ec, NULL, NULL); + + /* Encode G and Q. */ + mpi_G = _gcry_mpi_ec_ec2os (ec->G, ec); + if (!mpi_G) + { + rc = GPG_ERR_BROKEN_PUBKEY; + goto leave; + } + if (!ec->Q) + { + rc = GPG_ERR_BAD_CRYPT_CTX; + goto leave; + } + + if (ec->dialect == ECC_DIALECT_ED25519) + { + unsigned char *encpk; + unsigned int encpklen; + + rc = _gcry_ecc_eddsa_encodepoint (ec->Q, ec, NULL, NULL, 0, + &encpk, &encpklen); + if (rc) + goto leave; + mpi_Q = mpi_set_opaque (NULL, encpk, encpklen*8); + encpk = NULL; + } + else + { + mpi_Q = _gcry_mpi_ec_ec2os (ec->Q, ec); + } + if (!mpi_Q) + { + rc = GPG_ERR_BROKEN_PUBKEY; + goto leave; + } + + /* Fixme: We should return a curve name instead of the parameters if + if know that they match a curve. */ + + if (ec->d && (!mode || mode == GCRY_PK_GET_SECKEY)) + { + /* Let's return a private key. */ + rc = sexp_build (r_sexp, NULL, + "(private-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)(d%m)))", + ec->p, ec->a, ec->b, mpi_G, ec->n, mpi_Q, ec->d); + } + else if (ec->Q) + { + /* Let's return a public key. */ + rc = sexp_build (r_sexp, NULL, + "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)))", + ec->p, ec->a, ec->b, mpi_G, ec->n, mpi_Q); + } + else + rc = GPG_ERR_BAD_CRYPT_CTX; + + leave: + mpi_free (mpi_Q); + mpi_free (mpi_G); + return rc; +} -/* +/* Self-test section. */ @@ -1318,7 +1707,7 @@ selftests_ecdsa (selftest_report_func_t report) { const char *what; const char *errtxt; - + what = "low-level"; errtxt = NULL; /*selftest ();*/ if (errtxt) @@ -1330,7 +1719,7 @@ selftests_ecdsa (selftest_report_func_t report) failed: if (report) - report ("pubkey", GCRY_PK_ECDSA, what, errtxt); + report ("pubkey", GCRY_PK_ECC, what, errtxt); return GPG_ERR_SELFTEST_FAILED; } @@ -1339,52 +1728,32 @@ selftests_ecdsa (selftest_report_func_t report) static gpg_err_code_t run_selftests (int algo, int extended, selftest_report_func_t report) { - gpg_err_code_t ec; - (void)extended; - switch (algo) - { - case GCRY_PK_ECDSA: - ec = selftests_ecdsa (report); - break; - default: - ec = GPG_ERR_PUBKEY_ALGO; - break; - - } - return ec; + if (algo != GCRY_PK_ECC) + return GPG_ERR_PUBKEY_ALGO; + + return selftests_ecdsa (report); } -static const char *ecdsa_names[] = +gcry_pk_spec_t _gcry_pubkey_spec_ecc = { - "ecdsa", - "ecc", - NULL, - }; - -gcry_pk_spec_t _gcry_pubkey_spec_ecdsa = - { - "ECDSA", ecdsa_names, - "pabgnq", "pabgnqd", "", "rs", "pabgnq", - GCRY_PK_USAGE_SIGN, + GCRY_PK_ECC, { 0, 0 }, + (GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR), + "ECC", ecc_names, + "pabgnq", "pabgnqd", "sw", "rs", "pabgnq", ecc_generate, ecc_check_secret_key, - NULL, - NULL, + ecc_encrypt_raw, + ecc_decrypt_raw, ecc_sign, ecc_verify, - ecc_get_nbits - }; - -pk_extra_spec_t _gcry_pubkey_extraspec_ecdsa = - { + ecc_get_nbits, run_selftests, - ecc_generate_ext, compute_keygrip, - ecc_get_param + _gcry_ecc_get_curve, + _gcry_ecc_get_param_sexp }; - diff --git a/plugins/MirOTR/Libgcrypt/cipher/elgamal.c b/plugins/MirOTR/Libgcrypt/cipher/elgamal.c index 0b0c07cb4b..4eb52d620b 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/elgamal.c +++ b/plugins/MirOTR/Libgcrypt/cipher/elgamal.c @@ -1,6 +1,7 @@ /* Elgamal.c - Elgamal Public Key encryption * Copyright (C) 1998, 2000, 2001, 2002, 2003, * 2008 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH * * This file is part of Libgcrypt. * @@ -29,6 +30,14 @@ #include "g10lib.h" #include "mpi.h" #include "cipher.h" +#include "pubkey-internal.h" + + +/* Blinding is used to mitigate side-channel attacks. You may undef + this to speed up the operation in case the system is secured + against physical and network mounted side-channel attacks. */ +#define USE_BLINDING 1 + typedef struct { @@ -47,9 +56,19 @@ typedef struct } ELG_secret_key; +static const char *elg_names[] = + { + "elg", + "openpgp-elg", + "openpgp-elg-sig", + NULL, + }; + + static int test_keys (ELG_secret_key *sk, unsigned int nbits, int nodie); static gcry_mpi_t gen_k (gcry_mpi_t p, int small_k); -static void generate (ELG_secret_key *sk, unsigned nbits, gcry_mpi_t **factors); +static gcry_err_code_t generate (ELG_secret_key *sk, unsigned nbits, + gcry_mpi_t **factors); static int check_secret_key (ELG_secret_key *sk); static void do_encrypt (gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_public_key *pkey); @@ -59,6 +78,7 @@ static void sign (gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_secret_key *skey); static int verify (gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_public_key *pkey); +static unsigned int elg_get_nbits (gcry_sexp_t parms); static void (*progress_cb) (void *, const char *, int, int, int); @@ -115,7 +135,7 @@ wiener_map( unsigned int n ) }; int i; - for(i=0; t[i].p_n; i++ ) + for(i=0; t[i].p_n; i++ ) { if( n <= t[i].p_n ) return t[i].q_n; @@ -128,17 +148,17 @@ static int test_keys ( ELG_secret_key *sk, unsigned int nbits, int nodie ) { ELG_public_key pk; - gcry_mpi_t test = gcry_mpi_new ( 0 ); - gcry_mpi_t out1_a = gcry_mpi_new ( nbits ); - gcry_mpi_t out1_b = gcry_mpi_new ( nbits ); - gcry_mpi_t out2 = gcry_mpi_new ( nbits ); + gcry_mpi_t test = mpi_new ( 0 ); + gcry_mpi_t out1_a = mpi_new ( nbits ); + gcry_mpi_t out1_b = mpi_new ( nbits ); + gcry_mpi_t out2 = mpi_new ( nbits ); int failed = 0; pk.p = sk->p; pk.g = sk->g; pk.y = sk->y; - gcry_mpi_randomize ( test, nbits, GCRY_WEAK_RANDOM ); + _gcry_mpi_randomize ( test, nbits, GCRY_WEAK_RANDOM ); do_encrypt ( out1_a, out1_b, test, &pk ); decrypt ( out2, out1_a, out1_b, sk ); @@ -149,16 +169,16 @@ test_keys ( ELG_secret_key *sk, unsigned int nbits, int nodie ) if ( !verify( out1_a, out1_b, test, &pk ) ) failed |= 2; - gcry_mpi_release ( test ); - gcry_mpi_release ( out1_a ); - gcry_mpi_release ( out1_b ); - gcry_mpi_release ( out2 ); + _gcry_mpi_release ( test ); + _gcry_mpi_release ( out1_a ); + _gcry_mpi_release ( out1_b ); + _gcry_mpi_release ( out2 ); if (failed && !nodie) log_fatal ("Elgamal test key for %s %s failed\n", (failed & 1)? "encrypt+decrypt":"", (failed & 2)? "sign+verify":""); - if (failed && DBG_CIPHER) + if (failed && DBG_CIPHER) log_debug ("Elgamal test key for %s %s failed\n", (failed & 1)? "encrypt+decrypt":"", (failed & 2)? "sign+verify":""); @@ -197,28 +217,28 @@ gen_k( gcry_mpi_t p, int small_k ) nbytes = (nbits+7)/8; if( DBG_CIPHER ) - log_debug("choosing a random k "); + log_debug("choosing a random k\n"); mpi_sub_ui( p_1, p, 1); - for(;;) + for(;;) { - if( !rndbuf || nbits < 32 ) + if( !rndbuf || nbits < 32 ) { - gcry_free(rndbuf); - rndbuf = gcry_random_bytes_secure( nbytes, GCRY_STRONG_RANDOM ); + xfree(rndbuf); + rndbuf = _gcry_random_bytes_secure( nbytes, GCRY_STRONG_RANDOM ); } else - { + { /* Change only some of the higher bits. We could improve this by directly requesting more memory at the first call to get_random_bytes() and use this the here maybe it is easier to do this directly in random.c Anyway, it is highly inlikely that we will ever reach this code. */ - char *pp = gcry_random_bytes_secure( 4, GCRY_STRONG_RANDOM ); + char *pp = _gcry_random_bytes_secure( 4, GCRY_STRONG_RANDOM ); memcpy( rndbuf, pp, 4 ); - gcry_free(pp); + xfree(pp); } _gcry_mpi_set_buffer( k, rndbuf, nbytes, 0 ); - + for(;;) { if( !(mpi_cmp( k, p_1 ) < 0) ) /* check: k < (p-1) */ @@ -233,7 +253,7 @@ gen_k( gcry_mpi_t p, int small_k ) progress('-'); break; /* no */ } - if (gcry_mpi_gcd( temp, k, p_1 )) + if (mpi_gcd( temp, k, p_1 )) goto found; /* okay, k is relative prime to (p-1) */ mpi_add_ui( k, k, 1 ); if( DBG_CIPHER ) @@ -241,7 +261,7 @@ gen_k( gcry_mpi_t p, int small_k ) } } found: - gcry_free(rndbuf); + xfree (rndbuf); if( DBG_CIPHER ) progress('\n'); mpi_free(p_1); @@ -255,9 +275,10 @@ gen_k( gcry_mpi_t p, int small_k ) * Returns: 2 structures filled with all needed values * and an array with n-1 factors of (p-1) */ -static void +static gcry_err_code_t generate ( ELG_secret_key *sk, unsigned int nbits, gcry_mpi_t **ret_factors ) { + gcry_err_code_t rc; gcry_mpi_t p; /* the prime */ gcry_mpi_t p_min1; gcry_mpi_t g; @@ -267,12 +288,18 @@ generate ( ELG_secret_key *sk, unsigned int nbits, gcry_mpi_t **ret_factors ) unsigned int xbits; byte *rndbuf; - p_min1 = gcry_mpi_new ( nbits ); + p_min1 = mpi_new ( nbits ); qbits = wiener_map( nbits ); if( qbits & 1 ) /* better have a even one */ qbits++; g = mpi_alloc(1); - p = _gcry_generate_elg_prime( 0, nbits, qbits, g, ret_factors ); + rc = _gcry_generate_elg_prime (0, nbits, qbits, g, &p, ret_factors); + if (rc) + { + mpi_free (p_min1); + mpi_free (g); + return rc; + } mpi_sub_ui(p_min1, p, 1); @@ -290,11 +317,11 @@ generate ( ELG_secret_key *sk, unsigned int nbits, gcry_mpi_t **ret_factors ) xbits = qbits * 3 / 2; if( xbits >= nbits ) BUG(); - x = gcry_mpi_snew ( xbits ); + x = mpi_snew ( xbits ); if( DBG_CIPHER ) - log_debug("choosing a random x of size %u", xbits ); + log_debug("choosing a random x of size %u\n", xbits ); rndbuf = NULL; - do + do { if( DBG_CIPHER ) progress('.'); @@ -302,39 +329,38 @@ generate ( ELG_secret_key *sk, unsigned int nbits, gcry_mpi_t **ret_factors ) { /* Change only some of the higher bits */ if( xbits < 16 ) /* should never happen ... */ { - gcry_free(rndbuf); - rndbuf = gcry_random_bytes_secure( (xbits+7)/8, - GCRY_VERY_STRONG_RANDOM ); + xfree(rndbuf); + rndbuf = _gcry_random_bytes_secure ((xbits+7)/8, + GCRY_VERY_STRONG_RANDOM); } else { - char *r = gcry_random_bytes_secure( 2, - GCRY_VERY_STRONG_RANDOM ); + char *r = _gcry_random_bytes_secure (2, GCRY_VERY_STRONG_RANDOM); memcpy(rndbuf, r, 2 ); - gcry_free(r); + xfree (r); } } - else + else { - rndbuf = gcry_random_bytes_secure( (xbits+7)/8, - GCRY_VERY_STRONG_RANDOM ); + rndbuf = _gcry_random_bytes_secure ((xbits+7)/8, + GCRY_VERY_STRONG_RANDOM ); } _gcry_mpi_set_buffer( x, rndbuf, (xbits+7)/8, 0 ); mpi_clear_highbit( x, xbits+1 ); - } + } while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, p_min1 )<0 ) ); - gcry_free(rndbuf); + xfree(rndbuf); - y = gcry_mpi_new (nbits); - gcry_mpi_powm( y, g, x, p ); + y = mpi_new (nbits); + mpi_powm( y, g, x, p ); - if( DBG_CIPHER ) + if( DBG_CIPHER ) { - progress('\n'); - log_mpidump("elg p= ", p ); - log_mpidump("elg g= ", g ); - log_mpidump("elg y= ", y ); - log_mpidump("elg x= ", x ); + progress ('\n'); + log_mpidump ("elg p", p ); + log_mpidump ("elg g", g ); + log_mpidump ("elg y", y ); + log_mpidump ("elg x", x ); } /* Copy the stuff to the key structures */ @@ -343,10 +369,12 @@ generate ( ELG_secret_key *sk, unsigned int nbits, gcry_mpi_t **ret_factors ) sk->y = y; sk->x = x; - gcry_mpi_release ( p_min1 ); + _gcry_mpi_release ( p_min1 ); /* Now we can test our keys (this should never fail!) */ test_keys ( sk, nbits - 64, 0 ); + + return 0; } @@ -354,13 +382,14 @@ generate ( ELG_secret_key *sk, unsigned int nbits, gcry_mpi_t **ret_factors ) value for the secret key but the one given as X. This is useful to implement a passphrase based decryption for a public key based encryption. It has appliactions in backup systems. - + Returns: A structure filled with all needed values and an array with n-1 factors of (p-1). */ static gcry_err_code_t generate_using_x (ELG_secret_key *sk, unsigned int nbits, gcry_mpi_t x, gcry_mpi_t **ret_factors ) { + gcry_err_code_t rc; gcry_mpi_t p; /* The prime. */ gcry_mpi_t p_min1; /* The prime minus 1. */ gcry_mpi_t g; /* The generator. */ @@ -378,51 +407,57 @@ generate_using_x (ELG_secret_key *sk, unsigned int nbits, gcry_mpi_t x, if ( xbits < 64 || xbits >= nbits ) return GPG_ERR_INV_VALUE; - p_min1 = gcry_mpi_new ( nbits ); + p_min1 = mpi_new ( nbits ); qbits = wiener_map ( nbits ); if ( (qbits & 1) ) /* Better have an even one. */ qbits++; g = mpi_alloc (1); - p = _gcry_generate_elg_prime ( 0, nbits, qbits, g, ret_factors ); + rc = _gcry_generate_elg_prime (0, nbits, qbits, g, &p, ret_factors ); + if (rc) + { + mpi_free (p_min1); + mpi_free (g); + return rc; + } mpi_sub_ui (p_min1, p, 1); if (DBG_CIPHER) log_debug ("using a supplied x of size %u", xbits ); if ( !(mpi_cmp_ui ( x, 0 ) > 0 && mpi_cmp ( x, p_min1 ) <0 ) ) { - gcry_mpi_release ( p_min1 ); - gcry_mpi_release ( p ); - gcry_mpi_release ( g ); + _gcry_mpi_release ( p_min1 ); + _gcry_mpi_release ( p ); + _gcry_mpi_release ( g ); return GPG_ERR_INV_VALUE; } - y = gcry_mpi_new (nbits); - gcry_mpi_powm ( y, g, x, p ); + y = mpi_new (nbits); + mpi_powm ( y, g, x, p ); - if ( DBG_CIPHER ) + if ( DBG_CIPHER ) { progress ('\n'); - log_mpidump ("elg p= ", p ); - log_mpidump ("elg g= ", g ); - log_mpidump ("elg y= ", y ); - log_mpidump ("elg x= ", x ); + log_mpidump ("elg p", p ); + log_mpidump ("elg g", g ); + log_mpidump ("elg y", y ); + log_mpidump ("elg x", x ); } /* Copy the stuff to the key structures */ sk->p = p; sk->g = g; sk->y = y; - sk->x = gcry_mpi_copy (x); + sk->x = mpi_copy (x); - gcry_mpi_release ( p_min1 ); + _gcry_mpi_release ( p_min1 ); /* Now we can test our keys. */ if ( test_keys ( sk, nbits - 64, 1 ) ) { - gcry_mpi_release ( sk->p ); sk->p = NULL; - gcry_mpi_release ( sk->g ); sk->g = NULL; - gcry_mpi_release ( sk->y ); sk->y = NULL; - gcry_mpi_release ( sk->x ); sk->x = NULL; + _gcry_mpi_release ( sk->p ); sk->p = NULL; + _gcry_mpi_release ( sk->g ); sk->g = NULL; + _gcry_mpi_release ( sk->y ); sk->y = NULL; + _gcry_mpi_release ( sk->x ); sk->x = NULL; return GPG_ERR_BAD_SECKEY; } @@ -440,7 +475,7 @@ check_secret_key( ELG_secret_key *sk ) int rc; gcry_mpi_t y = mpi_alloc( mpi_get_nlimbs(sk->y) ); - gcry_mpi_powm( y, sk->g, sk->x, sk->p ); + mpi_powm (y, sk->g, sk->x, sk->p); rc = !mpi_cmp( y, sk->y ); mpi_free( y ); return rc; @@ -458,23 +493,24 @@ do_encrypt(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_public_key *pkey ) */ k = gen_k( pkey->p, 1 ); - gcry_mpi_powm( a, pkey->g, k, pkey->p ); + mpi_powm (a, pkey->g, k, pkey->p); + /* b = (y^k * input) mod p * = ((y^k mod p) * (input mod p)) mod p * and because input is < p * = ((y^k mod p) * input) mod p */ - gcry_mpi_powm( b, pkey->y, k, pkey->p ); - gcry_mpi_mulm( b, b, input, pkey->p ); + mpi_powm (b, pkey->y, k, pkey->p); + mpi_mulm (b, b, input, pkey->p); #if 0 if( DBG_CIPHER ) { - log_mpidump("elg encrypted y= ", pkey->y); - log_mpidump("elg encrypted p= ", pkey->p); - log_mpidump("elg encrypted k= ", k); - log_mpidump("elg encrypted M= ", input); - log_mpidump("elg encrypted a= ", a); - log_mpidump("elg encrypted b= ", b); + log_mpidump("elg encrypted y", pkey->y); + log_mpidump("elg encrypted p", pkey->p); + log_mpidump("elg encrypted k", k); + log_mpidump("elg encrypted M", input); + log_mpidump("elg encrypted a", a); + log_mpidump("elg encrypted b", b); } #endif mpi_free(k); @@ -484,25 +520,58 @@ do_encrypt(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_public_key *pkey ) static void -decrypt(gcry_mpi_t output, gcry_mpi_t a, gcry_mpi_t b, ELG_secret_key *skey ) +decrypt (gcry_mpi_t output, gcry_mpi_t a, gcry_mpi_t b, ELG_secret_key *skey ) { - gcry_mpi_t t1 = mpi_alloc_secure( mpi_get_nlimbs( skey->p ) ); + gcry_mpi_t t1, t2, r; + unsigned int nbits = mpi_get_nbits (skey->p); + + mpi_normalize (a); + mpi_normalize (b); + + t1 = mpi_snew (nbits); + +#ifdef USE_BLINDING + + t2 = mpi_snew (nbits); + r = mpi_new (nbits); + + /* We need a random number of about the prime size. The random + number merely needs to be unpredictable; thus we use level 0. */ + _gcry_mpi_randomize (r, nbits, GCRY_WEAK_RANDOM); + + /* t1 = r^x mod p */ + mpi_powm (t1, r, skey->x, skey->p); + /* t2 = (a * r)^-x mod p */ + mpi_mulm (t2, a, r, skey->p); + mpi_powm (t2, t2, skey->x, skey->p); + mpi_invm (t2, t2, skey->p); + /* t1 = (t1 * t2) mod p*/ + mpi_mulm (t1, t1, t2, skey->p); + + mpi_free (r); + mpi_free (t2); + +#else /*!USE_BLINDING*/ /* output = b/(a^x) mod p */ - gcry_mpi_powm( t1, a, skey->x, skey->p ); - mpi_invm( t1, t1, skey->p ); - mpi_mulm( output, b, t1, skey->p ); + mpi_powm (t1, a, skey->x, skey->p); + mpi_invm (t1, t1, skey->p); + +#endif /*!USE_BLINDING*/ + + mpi_mulm (output, b, t1, skey->p); + #if 0 - if( DBG_CIPHER ) + if( DBG_CIPHER ) { - log_mpidump("elg decrypted x= ", skey->x); - log_mpidump("elg decrypted p= ", skey->p); - log_mpidump("elg decrypted a= ", a); - log_mpidump("elg decrypted b= ", b); - log_mpidump("elg decrypted M= ", output); + log_mpidump ("elg decrypted x", skey->x); + log_mpidump ("elg decrypted p", skey->p); + log_mpidump ("elg decrypted a", a); + log_mpidump ("elg decrypted b", b); + log_mpidump ("elg decrypted M", output); } #endif - mpi_free(t1); + mpi_free (t1); } @@ -526,23 +595,23 @@ sign(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_secret_key *skey ) */ mpi_sub_ui(p_1, p_1, 1); k = gen_k( skey->p, 0 /* no small K ! */ ); - gcry_mpi_powm( a, skey->g, k, skey->p ); + mpi_powm( a, skey->g, k, skey->p ); mpi_mul(t, skey->x, a ); mpi_subm(t, input, t, p_1 ); mpi_invm(inv, k, p_1 ); mpi_mulm(b, t, inv, p_1 ); #if 0 - if( DBG_CIPHER ) + if( DBG_CIPHER ) { - log_mpidump("elg sign p= ", skey->p); - log_mpidump("elg sign g= ", skey->g); - log_mpidump("elg sign y= ", skey->y); - log_mpidump("elg sign x= ", skey->x); - log_mpidump("elg sign k= ", k); - log_mpidump("elg sign M= ", input); - log_mpidump("elg sign a= ", a); - log_mpidump("elg sign b= ", b); + log_mpidump ("elg sign p", skey->p); + log_mpidump ("elg sign g", skey->g); + log_mpidump ("elg sign y", skey->y); + log_mpidump ("elg sign x", skey->x); + log_mpidump ("elg sign k", k); + log_mpidump ("elg sign M", input); + log_mpidump ("elg sign a", a); + log_mpidump ("elg sign b", b); } #endif mpi_free(k); @@ -613,234 +682,468 @@ verify(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_public_key *pkey ) *********************************************/ static gpg_err_code_t -elg_generate_ext (int algo, unsigned int nbits, unsigned long evalue, - const gcry_sexp_t genparms, - gcry_mpi_t *skey, gcry_mpi_t **retfactors, - gcry_sexp_t *r_extrainfo) +elg_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) { - gpg_err_code_t ec; + gpg_err_code_t rc; + unsigned int nbits; ELG_secret_key sk; gcry_mpi_t xvalue = NULL; gcry_sexp_t l1; + gcry_mpi_t *factors = NULL; + gcry_sexp_t misc_info = NULL; - (void)algo; - (void)evalue; - (void)r_extrainfo; + memset (&sk, 0, sizeof sk); - if (genparms) + rc = _gcry_pk_util_get_nbits (genparms, &nbits); + if (rc) + return rc; + + /* Parse the optional xvalue element. */ + l1 = sexp_find_token (genparms, "xvalue", 0); + if (l1) { - /* Parse the optional xvalue element. */ - l1 = gcry_sexp_find_token (genparms, "xvalue", 0); - if (l1) - { - xvalue = gcry_sexp_nth_mpi (l1, 1, 0); - gcry_sexp_release (l1); - if (!xvalue) - return GPG_ERR_BAD_MPI; - } + xvalue = sexp_nth_mpi (l1, 1, 0); + sexp_release (l1); + if (!xvalue) + return GPG_ERR_BAD_MPI; } if (xvalue) - ec = generate_using_x (&sk, nbits, xvalue, retfactors); + { + rc = generate_using_x (&sk, nbits, xvalue, &factors); + mpi_free (xvalue); + } else { - generate (&sk, nbits, retfactors); - ec = 0; + rc = generate (&sk, nbits, &factors); + } + if (rc) + goto leave; + + if (factors && factors[0]) + { + int nfac; + void **arg_list; + char *buffer, *p; + + for (nfac = 0; factors[nfac]; nfac++) + ; + arg_list = xtrycalloc (nfac+1, sizeof *arg_list); + if (!arg_list) + { + rc = gpg_err_code_from_syserror (); + goto leave; + } + buffer = xtrymalloc (30 + nfac*2 + 2 + 1); + if (!buffer) + { + rc = gpg_err_code_from_syserror (); + xfree (arg_list); + goto leave; + } + p = stpcpy (buffer, "(misc-key-info(pm1-factors"); + for(nfac = 0; factors[nfac]; nfac++) + { + p = stpcpy (p, "%m"); + arg_list[nfac] = factors + nfac; + } + p = stpcpy (p, "))"); + rc = sexp_build_array (&misc_info, NULL, buffer, arg_list); + xfree (arg_list); + xfree (buffer); + if (rc) + goto leave; + } + + rc = sexp_build (r_skey, NULL, + "(key-data" + " (public-key" + " (elg(p%m)(g%m)(y%m)))" + " (private-key" + " (elg(p%m)(g%m)(y%m)(x%m)))" + " %S)", + sk.p, sk.g, sk.y, + sk.p, sk.g, sk.y, sk.x, + misc_info); + + leave: + mpi_free (sk.p); + mpi_free (sk.g); + mpi_free (sk.y); + mpi_free (sk.x); + sexp_release (misc_info); + if (factors) + { + gcry_mpi_t *mp; + for (mp = factors; *mp; mp++) + mpi_free (*mp); + xfree (factors); } - skey[0] = sk.p; - skey[1] = sk.g; - skey[2] = sk.y; - skey[3] = sk.x; - - return ec; + return rc; } static gcry_err_code_t -elg_generate (int algo, unsigned int nbits, unsigned long evalue, - gcry_mpi_t *skey, gcry_mpi_t **retfactors) +elg_check_secret_key (gcry_sexp_t keyparms) { - ELG_secret_key sk; - - (void)algo; - (void)evalue; - - generate (&sk, nbits, retfactors); - skey[0] = sk.p; - skey[1] = sk.g; - skey[2] = sk.y; - skey[3] = sk.x; - - return GPG_ERR_NO_ERROR; + gcry_err_code_t rc; + ELG_secret_key sk = {NULL, NULL, NULL, NULL}; + + rc = sexp_extract_param (keyparms, NULL, "pgyx", + &sk.p, &sk.g, &sk.y, &sk.x, + NULL); + if (rc) + goto leave; + + if (!check_secret_key (&sk)) + rc = GPG_ERR_BAD_SECKEY; + + leave: + _gcry_mpi_release (sk.p); + _gcry_mpi_release (sk.g); + _gcry_mpi_release (sk.y); + _gcry_mpi_release (sk.x); + if (DBG_CIPHER) + log_debug ("elg_testkey => %s\n", gpg_strerror (rc)); + return rc; } static gcry_err_code_t -elg_check_secret_key (int algo, gcry_mpi_t *skey) +elg_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - ELG_secret_key sk; - - (void)algo; + gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_mpi_t mpi_a = NULL; + gcry_mpi_t mpi_b = NULL; + gcry_mpi_t data = NULL; + ELG_public_key pk = { NULL, NULL, NULL }; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT, + elg_get_nbits (keyparms)); + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_mpidump ("elg_encrypt data", data); + if (mpi_is_opaque (data)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + } - if ((! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3])) - err = GPG_ERR_BAD_MPI; - else + /* Extract the key. */ + rc = sexp_extract_param (keyparms, NULL, "pgy", + &pk.p, &pk.g, &pk.y, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) { - sk.p = skey[0]; - sk.g = skey[1]; - sk.y = skey[2]; - sk.x = skey[3]; - - if (! check_secret_key (&sk)) - err = GPG_ERR_BAD_SECKEY; + log_mpidump ("elg_encrypt p", pk.p); + log_mpidump ("elg_encrypt g", pk.g); + log_mpidump ("elg_encrypt y", pk.y); } - return err; + /* Do Elgamal computation and build result. */ + mpi_a = mpi_new (0); + mpi_b = mpi_new (0); + do_encrypt (mpi_a, mpi_b, data, &pk); + rc = sexp_build (r_ciph, NULL, "(enc-val(elg(a%m)(b%m)))", mpi_a, mpi_b); + + leave: + _gcry_mpi_release (mpi_a); + _gcry_mpi_release (mpi_b); + _gcry_mpi_release (pk.p); + _gcry_mpi_release (pk.g); + _gcry_mpi_release (pk.y); + _gcry_mpi_release (data); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("elg_encrypt => %s\n", gpg_strerror (rc)); + return rc; } static gcry_err_code_t -elg_encrypt (int algo, gcry_mpi_t *resarr, - gcry_mpi_t data, gcry_mpi_t *pkey, int flags) +elg_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - ELG_public_key pk; - - (void)algo; - (void)flags; - - if ((! data) || (! pkey[0]) || (! pkey[1]) || (! pkey[2])) - err = GPG_ERR_BAD_MPI; - else + gpg_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_sexp_t l1 = NULL; + gcry_mpi_t data_a = NULL; + gcry_mpi_t data_b = NULL; + ELG_secret_key sk = {NULL, NULL, NULL, NULL}; + gcry_mpi_t plain = NULL; + unsigned char *unpad = NULL; + size_t unpadlen = 0; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, + elg_get_nbits (keyparms)); + + /* Extract the data. */ + rc = _gcry_pk_util_preparse_encval (s_data, elg_names, &l1, &ctx); + if (rc) + goto leave; + rc = sexp_extract_param (l1, NULL, "ab", &data_a, &data_b, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) { - pk.p = pkey[0]; - pk.g = pkey[1]; - pk.y = pkey[2]; - resarr[0] = mpi_alloc (mpi_get_nlimbs (pk.p)); - resarr[1] = mpi_alloc (mpi_get_nlimbs (pk.p)); - do_encrypt (resarr[0], resarr[1], data, &pk); + log_printmpi ("elg_decrypt d_a", data_a); + log_printmpi ("elg_decrypt d_b", data_b); + } + if (mpi_is_opaque (data_a) || mpi_is_opaque (data_b)) + { + rc = GPG_ERR_INV_DATA; + goto leave; } - return err; -} - -static gcry_err_code_t -elg_decrypt (int algo, gcry_mpi_t *result, - gcry_mpi_t *data, gcry_mpi_t *skey, int flags) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - ELG_secret_key sk; + /* Extract the key. */ + rc = sexp_extract_param (keyparms, NULL, "pgyx", + &sk.p, &sk.g, &sk.y, &sk.x, + NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_printmpi ("elg_decrypt p", sk.p); + log_printmpi ("elg_decrypt g", sk.g); + log_printmpi ("elg_decrypt y", sk.y); + if (!fips_mode ()) + log_printmpi ("elg_decrypt x", sk.x); + } - (void)algo; - (void)flags; + plain = mpi_snew (ctx.nbits); + decrypt (plain, data_a, data_b, &sk); + if (DBG_CIPHER) + log_printmpi ("elg_decrypt res", plain); - if ((! data[0]) || (! data[1]) - || (! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3])) - err = GPG_ERR_BAD_MPI; - else + /* Reverse the encoding and build the s-expression. */ + switch (ctx.encoding) { - sk.p = skey[0]; - sk.g = skey[1]; - sk.y = skey[2]; - sk.x = skey[3]; - *result = mpi_alloc_secure (mpi_get_nlimbs (sk.p)); - decrypt (*result, data[0], data[1], &sk); + case PUBKEY_ENC_PKCS1: + rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, ctx.nbits, plain); + mpi_free (plain); plain = NULL; + if (!rc) + rc = sexp_build (r_plain, NULL, "(value %b)", (int)unpadlen, unpad); + break; + + case PUBKEY_ENC_OAEP: + rc = _gcry_rsa_oaep_decode (&unpad, &unpadlen, + ctx.nbits, ctx.hash_algo, plain, + ctx.label, ctx.labellen); + mpi_free (plain); plain = NULL; + if (!rc) + rc = sexp_build (r_plain, NULL, "(value %b)", (int)unpadlen, unpad); + break; + + default: + /* Raw format. For backward compatibility we need to assume a + signed mpi by using the sexp format string "%m". */ + rc = sexp_build (r_plain, NULL, + (ctx.flags & PUBKEY_FLAG_LEGACYRESULT) + ? "%m" : "(value %m)", + plain); + break; } - return err; + + + leave: + xfree (unpad); + _gcry_mpi_release (plain); + _gcry_mpi_release (sk.p); + _gcry_mpi_release (sk.g); + _gcry_mpi_release (sk.y); + _gcry_mpi_release (sk.x); + _gcry_mpi_release (data_a); + _gcry_mpi_release (data_b); + sexp_release (l1); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("elg_decrypt => %s\n", gpg_strerror (rc)); + return rc; } static gcry_err_code_t -elg_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey) +elg_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - ELG_secret_key sk; + gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_mpi_t data = NULL; + ELG_secret_key sk = {NULL, NULL, NULL, NULL}; + gcry_mpi_t sig_r = NULL; + gcry_mpi_t sig_s = NULL; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN, + elg_get_nbits (keyparms)); + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_mpidump ("elg_sign data", data); + if (mpi_is_opaque (data)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + } - (void)algo; + /* Extract the key. */ + rc = sexp_extract_param (keyparms, NULL, "pgyx", + &sk.p, &sk.g, &sk.y, &sk.x, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_mpidump ("elg_sign p", sk.p); + log_mpidump ("elg_sign g", sk.g); + log_mpidump ("elg_sign y", sk.y); + if (!fips_mode ()) + log_mpidump ("elg_sign x", sk.x); + } - if ((! data) - || (! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3])) - err = GPG_ERR_BAD_MPI; - else + sig_r = mpi_new (0); + sig_s = mpi_new (0); + sign (sig_r, sig_s, data, &sk); + if (DBG_CIPHER) { - sk.p = skey[0]; - sk.g = skey[1]; - sk.y = skey[2]; - sk.x = skey[3]; - resarr[0] = mpi_alloc (mpi_get_nlimbs (sk.p)); - resarr[1] = mpi_alloc (mpi_get_nlimbs (sk.p)); - sign (resarr[0], resarr[1], data, &sk); + log_mpidump ("elg_sign sig_r", sig_r); + log_mpidump ("elg_sign sig_s", sig_s); } - - return err; + rc = sexp_build (r_sig, NULL, "(sig-val(elg(r%M)(s%M)))", sig_r, sig_s); + + leave: + _gcry_mpi_release (sig_r); + _gcry_mpi_release (sig_s); + _gcry_mpi_release (sk.p); + _gcry_mpi_release (sk.g); + _gcry_mpi_release (sk.y); + _gcry_mpi_release (sk.x); + _gcry_mpi_release (data); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("elg_sign => %s\n", gpg_strerror (rc)); + return rc; } static gcry_err_code_t -elg_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey, - int (*cmp) (void *, gcry_mpi_t), void *opaquev) +elg_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - ELG_public_key pk; + gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_sexp_t l1 = NULL; + gcry_mpi_t sig_r = NULL; + gcry_mpi_t sig_s = NULL; + gcry_mpi_t data = NULL; + ELG_public_key pk = { NULL, NULL, NULL }; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY, + elg_get_nbits (s_keyparms)); + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_mpidump ("elg_verify data", data); + if (mpi_is_opaque (data)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + } - (void)algo; - (void)cmp; - (void)opaquev; + /* Extract the signature value. */ + rc = _gcry_pk_util_preparse_sigval (s_sig, elg_names, &l1, NULL); + if (rc) + goto leave; + rc = sexp_extract_param (l1, NULL, "rs", &sig_r, &sig_s, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_mpidump ("elg_verify s_r", sig_r); + log_mpidump ("elg_verify s_s", sig_s); + } - if ((! data[0]) || (! data[1]) || (! hash) - || (! pkey[0]) || (! pkey[1]) || (! pkey[2])) - err = GPG_ERR_BAD_MPI; - else + /* Extract the key. */ + rc = sexp_extract_param (s_keyparms, NULL, "pgy", + &pk.p, &pk.g, &pk.y, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) { - pk.p = pkey[0]; - pk.g = pkey[1]; - pk.y = pkey[2]; - if (! verify (data[0], data[1], hash, &pk)) - err = GPG_ERR_BAD_SIGNATURE; + log_mpidump ("elg_verify p", pk.p); + log_mpidump ("elg_verify g", pk.g); + log_mpidump ("elg_verify y", pk.y); } - return err; + /* Verify the signature. */ + if (!verify (sig_r, sig_s, data, &pk)) + rc = GPG_ERR_BAD_SIGNATURE; + + leave: + _gcry_mpi_release (pk.p); + _gcry_mpi_release (pk.g); + _gcry_mpi_release (pk.y); + _gcry_mpi_release (data); + _gcry_mpi_release (sig_r); + _gcry_mpi_release (sig_s); + sexp_release (l1); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("elg_verify => %s\n", rc?gpg_strerror (rc):"Good"); + return rc; } +/* Return the number of bits for the key described by PARMS. On error + * 0 is returned. The format of PARMS starts with the algorithm name; + * for example: + * + * (dsa + * (p <mpi>) + * (g <mpi>) + * (y <mpi>)) + * + * More parameters may be given but we only need P here. + */ static unsigned int -elg_get_nbits (int algo, gcry_mpi_t *pkey) +elg_get_nbits (gcry_sexp_t parms) { - (void)algo; - - return mpi_get_nbits (pkey[0]); + gcry_sexp_t l1; + gcry_mpi_t p; + unsigned int nbits; + + l1 = sexp_find_token (parms, "p", 1); + if (!l1) + return 0; /* Parameter P not found. */ + + p= sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + sexp_release (l1); + nbits = p? mpi_get_nbits (p) : 0; + _gcry_mpi_release (p); + return nbits; } -static const char *elg_names[] = - { - "elg", - "openpgp-elg", - "openpgp-elg-sig", - NULL, - }; - - + gcry_pk_spec_t _gcry_pubkey_spec_elg = { + GCRY_PK_ELG, { 0, 0 }, + (GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR), "ELG", elg_names, "pgy", "pgyx", "ab", "rs", "pgy", - GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR, elg_generate, elg_check_secret_key, elg_encrypt, elg_decrypt, elg_sign, elg_verify, - elg_get_nbits - }; - -pk_extra_spec_t _gcry_pubkey_extraspec_elg = - { - NULL, - elg_generate_ext, - NULL + elg_get_nbits, }; - diff --git a/plugins/MirOTR/Libgcrypt/cipher/gost.h b/plugins/MirOTR/Libgcrypt/cipher/gost.h new file mode 100644 index 0000000000..d058eb220d --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/gost.h @@ -0,0 +1,31 @@ +/* gost.h - GOST 28147-89 implementation + * Copyright (C) 2012 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _GCRY_GOST_H +#define _GCRY_GOST_H + +typedef struct { + u32 key[8]; +} GOST28147_context; + +/* This is a simple interface that will be used by GOST R 34.11-94 */ +extern unsigned int _gcry_gost_enc_one (GOST28147_context *c, const byte *key, + byte *out, byte *in); + +#endif diff --git a/plugins/MirOTR/Libgcrypt/cipher/gost28147.c b/plugins/MirOTR/Libgcrypt/cipher/gost28147.c new file mode 100644 index 0000000000..c094209c2e --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/gost28147.c @@ -0,0 +1,452 @@ +/* gost28147.c - GOST 28147-89 implementation for Libgcrypt + * Copyright (C) 2012 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* GOST 28147-89 defines several modes of encryption: + * - ECB which should be used only for key transfer + * - CFB mode + * - OFB-like mode with additional transformation on keystream + * RFC 5830 names this 'counter encryption' mode + * Original GOST text uses the term 'gammirovanie' + * - MAC mode + * + * This implementation handles ECB and CFB modes via usual libgcrypt handling. + * OFB-like and MAC modes are unsupported. + */ + +#include <config.h> +#include "types.h" +#include "g10lib.h" +#include "cipher.h" + + +/* This is an s-box from RFC4357, named GostR3411-94-TestParamSet + * For now it is the only s-box supported, as libgcrypt lacks mechanism + * for passing parameters to cipher in a usefull way. + * S-boxes was modified from 4->4 to 8->8 bits unit with precalculated + * shift and rotation by optimisation reasons. + */ +static const u32 test_sbox[4][256] = { + /* 0 */ + { 0x00072000, 0x00075000, 0x00074800, 0x00071000, + 0x00076800, 0x00074000, 0x00070000, 0x00077000, + 0x00073000, 0x00075800, 0x00070800, 0x00076000, + 0x00073800, 0x00077800, 0x00072800, 0x00071800, + 0x0005a000, 0x0005d000, 0x0005c800, 0x00059000, + 0x0005e800, 0x0005c000, 0x00058000, 0x0005f000, + 0x0005b000, 0x0005d800, 0x00058800, 0x0005e000, + 0x0005b800, 0X0005F800, 0x0005a800, 0x00059800, + 0x00022000, 0x00025000, 0x00024800, 0x00021000, + 0x00026800, 0x00024000, 0x00020000, 0x00027000, + 0X00023000, 0x00025800, 0x00020800, 0x00026000, + 0x00023800, 0x00027800, 0x00022800, 0x00021800, + 0x00062000, 0x00065000, 0x00064800, 0x00061000, + 0x00066800, 0x00064000, 0x00060000, 0x00067000, + 0x00063000, 0x00065800, 0x00060800, 0x00066000, + 0x00063800, 0x00067800, 0x00062800, 0x00061800, + 0x00032000, 0x00035000, 0x00034800, 0x00031000, + 0x00036800, 0x00034000, 0x00030000, 0x00037000, + 0x00033000, 0x00035800, 0x00030800, 0x00036000, + 0x00033800, 0x00037800, 0x00032800, 0x00031800, + 0x0006a000, 0x0006d000, 0x0006c800, 0x00069000, + 0x0006e800, 0x0006c000, 0x00068000, 0x0006f000, + 0x0006b000, 0x0006d800, 0x00068800, 0x0006e000, + 0x0006b800, 0x0006f800, 0x0006a800, 0x00069800, + 0x0007a000, 0x0007d000, 0x0007c800, 0x00079000, + 0x0007e800, 0x0007c000, 0x00078000, 0x0007f000, + 0x0007b000, 0x0007d800, 0x00078800, 0x0007e000, + 0x0007b800, 0x0007f800, 0x0007a800, 0x00079800, + 0x00052000, 0x00055000, 0x00054800, 0x00051000, + 0x00056800, 0x00054000, 0x00050000, 0x00057000, + 0x00053000, 0x00055800, 0x00050800, 0x00056000, + 0x00053800, 0x00057800, 0x00052800, 0x00051800, + 0x00012000, 0x00015000, 0x00014800, 0x00011000, + 0x00016800, 0x00014000, 0x00010000, 0x00017000, + 0x00013000, 0x00015800, 0x00010800, 0x00016000, + 0x00013800, 0x00017800, 0x00012800, 0x00011800, + 0x0001a000, 0x0001d000, 0x0001c800, 0x00019000, + 0x0001e800, 0x0001c000, 0x00018000, 0x0001f000, + 0x0001b000, 0x0001d800, 0x00018800, 0x0001e000, + 0x0001b800, 0x0001f800, 0x0001a800, 0x00019800, + 0x00042000, 0x00045000, 0x00044800, 0x00041000, + 0x00046800, 0x00044000, 0x00040000, 0x00047000, + 0x00043000, 0x00045800, 0x00040800, 0x00046000, + 0x00043800, 0x00047800, 0x00042800, 0x00041800, + 0x0000a000, 0x0000d000, 0x0000c800, 0x00009000, + 0x0000e800, 0x0000c000, 0x00008000, 0x0000f000, + 0x0000b000, 0x0000d800, 0x00008800, 0x0000e000, + 0x0000b800, 0x0000f800, 0x0000a800, 0x00009800, + 0x00002000, 0x00005000, 0x00004800, 0x00001000, + 0x00006800, 0x00004000, 0x00000000, 0x00007000, + 0x00003000, 0x00005800, 0x00000800, 0x00006000, + 0x00003800, 0x00007800, 0x00002800, 0x00001800, + 0x0003a000, 0x0003d000, 0x0003c800, 0x00039000, + 0x0003e800, 0x0003c000, 0x00038000, 0x0003f000, + 0x0003b000, 0x0003d800, 0x00038800, 0x0003e000, + 0x0003b800, 0x0003f800, 0x0003a800, 0x00039800, + 0x0002a000, 0x0002d000, 0x0002c800, 0x00029000, + 0x0002e800, 0x0002c000, 0x00028000, 0x0002f000, + 0x0002b000, 0x0002d800, 0x00028800, 0x0002e000, + 0x0002b800, 0x0002f800, 0x0002a800, 0x00029800, + 0x0004a000, 0x0004d000, 0x0004c800, 0x00049000, + 0x0004e800, 0x0004c000, 0x00048000, 0x0004f000, + 0x0004b000, 0x0004d800, 0x00048800, 0x0004e000, + 0x0004b800, 0x0004f800, 0x0004a800, 0x00049800 }, + /* 1 */ + { 0x03a80000, 0x03c00000, 0x03880000, 0x03e80000, + 0x03d00000, 0x03980000, 0x03a00000, 0x03900000, + 0x03f00000, 0x03f80000, 0x03e00000, 0x03b80000, + 0x03b00000, 0x03800000, 0x03c80000, 0x03d80000, + 0x06a80000, 0x06c00000, 0x06880000, 0x06e80000, + 0x06d00000, 0x06980000, 0x06a00000, 0x06900000, + 0x06f00000, 0x06f80000, 0x06e00000, 0x06b80000, + 0x06b00000, 0x06800000, 0x06c80000, 0x06d80000, + 0x05280000, 0x05400000, 0x05080000, 0x05680000, + 0x05500000, 0x05180000, 0x05200000, 0x05100000, + 0x05700000, 0x05780000, 0x05600000, 0x05380000, + 0x05300000, 0x05000000, 0x05480000, 0x05580000, + 0x00a80000, 0x00c00000, 0x00880000, 0x00e80000, + 0x00d00000, 0x00980000, 0x00a00000, 0x00900000, + 0x00f00000, 0x00f80000, 0x00e00000, 0x00b80000, + 0x00b00000, 0x00800000, 0x00c80000, 0x00d80000, + 0x00280000, 0x00400000, 0x00080000, 0x00680000, + 0x00500000, 0x00180000, 0x00200000, 0x00100000, + 0x00700000, 0x00780000, 0x00600000, 0x00380000, + 0x00300000, 0x00000000, 0x00480000, 0x00580000, + 0x04280000, 0x04400000, 0x04080000, 0x04680000, + 0x04500000, 0x04180000, 0x04200000, 0x04100000, + 0x04700000, 0x04780000, 0x04600000, 0x04380000, + 0x04300000, 0x04000000, 0x04480000, 0x04580000, + 0x04a80000, 0x04c00000, 0x04880000, 0x04e80000, + 0x04d00000, 0x04980000, 0x04a00000, 0x04900000, + 0x04f00000, 0x04f80000, 0x04e00000, 0x04b80000, + 0x04b00000, 0x04800000, 0x04c80000, 0x04d80000, + 0x07a80000, 0x07c00000, 0x07880000, 0x07e80000, + 0x07d00000, 0x07980000, 0x07a00000, 0x07900000, + 0x07f00000, 0x07f80000, 0x07e00000, 0x07b80000, + 0x07b00000, 0x07800000, 0x07c80000, 0x07d80000, + 0x07280000, 0x07400000, 0x07080000, 0x07680000, + 0x07500000, 0x07180000, 0x07200000, 0x07100000, + 0x07700000, 0x07780000, 0x07600000, 0x07380000, + 0x07300000, 0x07000000, 0x07480000, 0x07580000, + 0x02280000, 0x02400000, 0x02080000, 0x02680000, + 0x02500000, 0x02180000, 0x02200000, 0x02100000, + 0x02700000, 0x02780000, 0x02600000, 0x02380000, + 0x02300000, 0x02000000, 0x02480000, 0x02580000, + 0x03280000, 0x03400000, 0x03080000, 0x03680000, + 0x03500000, 0x03180000, 0x03200000, 0x03100000, + 0x03700000, 0x03780000, 0x03600000, 0x03380000, + 0x03300000, 0x03000000, 0x03480000, 0x03580000, + 0x06280000, 0x06400000, 0x06080000, 0x06680000, + 0x06500000, 0x06180000, 0x06200000, 0x06100000, + 0x06700000, 0x06780000, 0x06600000, 0x06380000, + 0x06300000, 0x06000000, 0x06480000, 0x06580000, + 0x05a80000, 0x05c00000, 0x05880000, 0x05e80000, + 0x05d00000, 0x05980000, 0x05a00000, 0x05900000, + 0x05f00000, 0x05f80000, 0x05e00000, 0x05b80000, + 0x05b00000, 0x05800000, 0x05c80000, 0x05d80000, + 0x01280000, 0x01400000, 0x01080000, 0x01680000, + 0x01500000, 0x01180000, 0x01200000, 0x01100000, + 0x01700000, 0x01780000, 0x01600000, 0x01380000, + 0x01300000, 0x01000000, 0x01480000, 0x01580000, + 0x02a80000, 0x02c00000, 0x02880000, 0x02e80000, + 0x02d00000, 0x02980000, 0x02a00000, 0x02900000, + 0x02f00000, 0x02f80000, 0x02e00000, 0x02b80000, + 0x02b00000, 0x02800000, 0x02c80000, 0x02d80000, + 0x01a80000, 0x01c00000, 0x01880000, 0x01e80000, + 0x01d00000, 0x01980000, 0x01a00000, 0x01900000, + 0x01f00000, 0x01f80000, 0x01e00000, 0x01b80000, + 0x01b00000, 0x01800000, 0x01c80000, 0x01d80000 }, + /* 2 */ + { 0x30000002, 0x60000002, 0x38000002, 0x08000002, + 0x28000002, 0x78000002, 0x68000002, 0x40000002, + 0x20000002, 0x50000002, 0x48000002, 0x70000002, + 0x00000002, 0x18000002, 0x58000002, 0x10000002, + 0xb0000005, 0xe0000005, 0xb8000005, 0x88000005, + 0xa8000005, 0xf8000005, 0xe8000005, 0xc0000005, + 0xa0000005, 0xd0000005, 0xc8000005, 0xf0000005, + 0x80000005, 0x98000005, 0xd8000005, 0x90000005, + 0x30000005, 0x60000005, 0x38000005, 0x08000005, + 0x28000005, 0x78000005, 0x68000005, 0x40000005, + 0x20000005, 0x50000005, 0x48000005, 0x70000005, + 0x00000005, 0x18000005, 0x58000005, 0x10000005, + 0x30000000, 0x60000000, 0x38000000, 0x08000000, + 0x28000000, 0x78000000, 0x68000000, 0x40000000, + 0x20000000, 0x50000000, 0x48000000, 0x70000000, + 0x00000000, 0x18000000, 0x58000000, 0x10000000, + 0xb0000003, 0xe0000003, 0xb8000003, 0x88000003, + 0xa8000003, 0xf8000003, 0xe8000003, 0xc0000003, + 0xa0000003, 0xd0000003, 0xc8000003, 0xf0000003, + 0x80000003, 0x98000003, 0xd8000003, 0x90000003, + 0x30000001, 0x60000001, 0x38000001, 0x08000001, + 0x28000001, 0x78000001, 0x68000001, 0x40000001, + 0x20000001, 0x50000001, 0x48000001, 0x70000001, + 0x00000001, 0x18000001, 0x58000001, 0x10000001, + 0xb0000000, 0xe0000000, 0xb8000000, 0x88000000, + 0xa8000000, 0xf8000000, 0xe8000000, 0xc0000000, + 0xa0000000, 0xd0000000, 0xc8000000, 0xf0000000, + 0x80000000, 0x98000000, 0xd8000000, 0x90000000, + 0xb0000006, 0xe0000006, 0xb8000006, 0x88000006, + 0xa8000006, 0xf8000006, 0xe8000006, 0xc0000006, + 0xa0000006, 0xd0000006, 0xc8000006, 0xf0000006, + 0x80000006, 0x98000006, 0xd8000006, 0x90000006, + 0xb0000001, 0xe0000001, 0xb8000001, 0x88000001, + 0xa8000001, 0xf8000001, 0xe8000001, 0xc0000001, + 0xa0000001, 0xd0000001, 0xc8000001, 0xf0000001, + 0x80000001, 0x98000001, 0xd8000001, 0x90000001, + 0x30000003, 0x60000003, 0x38000003, 0x08000003, + 0x28000003, 0x78000003, 0x68000003, 0x40000003, + 0x20000003, 0x50000003, 0x48000003, 0x70000003, + 0x00000003, 0x18000003, 0x58000003, 0x10000003, + 0x30000004, 0x60000004, 0x38000004, 0x08000004, + 0x28000004, 0x78000004, 0x68000004, 0x40000004, + 0x20000004, 0x50000004, 0x48000004, 0x70000004, + 0x00000004, 0x18000004, 0x58000004, 0x10000004, + 0xb0000002, 0xe0000002, 0xb8000002, 0x88000002, + 0xa8000002, 0xf8000002, 0xe8000002, 0xc0000002, + 0xa0000002, 0xd0000002, 0xc8000002, 0xf0000002, + 0x80000002, 0x98000002, 0xd8000002, 0x90000002, + 0xb0000004, 0xe0000004, 0xb8000004, 0x88000004, + 0xa8000004, 0xf8000004, 0xe8000004, 0xc0000004, + 0xa0000004, 0xd0000004, 0xc8000004, 0xf0000004, + 0x80000004, 0x98000004, 0xd8000004, 0x90000004, + 0x30000006, 0x60000006, 0x38000006, 0x08000006, + 0x28000006, 0x78000006, 0x68000006, 0x40000006, + 0x20000006, 0x50000006, 0x48000006, 0x70000006, + 0x00000006, 0x18000006, 0x58000006, 0x10000006, + 0xb0000007, 0xe0000007, 0xb8000007, 0x88000007, + 0xa8000007, 0xf8000007, 0xe8000007, 0xc0000007, + 0xa0000007, 0xd0000007, 0xc8000007, 0xf0000007, + 0x80000007, 0x98000007, 0xd8000007, 0x90000007, + 0x30000007, 0x60000007, 0x38000007, 0x08000007, + 0x28000007, 0x78000007, 0x68000007, 0x40000007, + 0x20000007, 0x50000007, 0x48000007, 0x70000007, + 0x00000007, 0x18000007, 0x58000007, 0x10000007 }, + /* 3 */ + { 0x000000e8, 0x000000d8, 0x000000a0, 0x00000088, + 0x00000098, 0x000000f8, 0x000000a8, 0x000000c8, + 0x00000080, 0x000000d0, 0x000000f0, 0x000000b8, + 0x000000b0, 0x000000c0, 0x00000090, 0x000000e0, + 0x000007e8, 0x000007d8, 0x000007a0, 0x00000788, + 0x00000798, 0x000007f8, 0x000007a8, 0x000007c8, + 0x00000780, 0x000007d0, 0x000007f0, 0x000007b8, + 0x000007b0, 0x000007c0, 0x00000790, 0x000007e0, + 0x000006e8, 0x000006d8, 0x000006a0, 0x00000688, + 0x00000698, 0x000006f8, 0x000006a8, 0x000006c8, + 0x00000680, 0x000006d0, 0x000006f0, 0x000006b8, + 0x000006b0, 0x000006c0, 0x00000690, 0x000006e0, + 0x00000068, 0x00000058, 0x00000020, 0x00000008, + 0x00000018, 0x00000078, 0x00000028, 0x00000048, + 0x00000000, 0x00000050, 0x00000070, 0x00000038, + 0x00000030, 0x00000040, 0x00000010, 0x00000060, + 0x000002e8, 0x000002d8, 0x000002a0, 0x00000288, + 0x00000298, 0x000002f8, 0x000002a8, 0x000002c8, + 0x00000280, 0x000002d0, 0x000002f0, 0x000002b8, + 0x000002b0, 0x000002c0, 0x00000290, 0x000002e0, + 0x000003e8, 0x000003d8, 0x000003a0, 0x00000388, + 0x00000398, 0x000003f8, 0x000003a8, 0x000003c8, + 0x00000380, 0x000003d0, 0x000003f0, 0x000003b8, + 0x000003b0, 0x000003c0, 0x00000390, 0x000003e0, + 0x00000568, 0x00000558, 0x00000520, 0x00000508, + 0x00000518, 0x00000578, 0x00000528, 0x00000548, + 0x00000500, 0x00000550, 0x00000570, 0x00000538, + 0x00000530, 0x00000540, 0x00000510, 0x00000560, + 0x00000268, 0x00000258, 0x00000220, 0x00000208, + 0x00000218, 0x00000278, 0x00000228, 0x00000248, + 0x00000200, 0x00000250, 0x00000270, 0x00000238, + 0x00000230, 0x00000240, 0x00000210, 0x00000260, + 0x000004e8, 0x000004d8, 0x000004a0, 0x00000488, + 0x00000498, 0x000004f8, 0x000004a8, 0x000004c8, + 0x00000480, 0x000004d0, 0x000004f0, 0x000004b8, + 0x000004b0, 0x000004c0, 0x00000490, 0x000004e0, + 0x00000168, 0x00000158, 0x00000120, 0x00000108, + 0x00000118, 0x00000178, 0x00000128, 0x00000148, + 0x00000100, 0x00000150, 0x00000170, 0x00000138, + 0x00000130, 0x00000140, 0x00000110, 0x00000160, + 0x000001e8, 0x000001d8, 0x000001a0, 0x00000188, + 0x00000198, 0x000001f8, 0x000001a8, 0x000001c8, + 0x00000180, 0x000001d0, 0x000001f0, 0x000001b8, + 0x000001b0, 0x000001c0, 0x00000190, 0x000001e0, + 0x00000768, 0x00000758, 0x00000720, 0x00000708, + 0x00000718, 0x00000778, 0x00000728, 0x00000748, + 0x00000700, 0x00000750, 0x00000770, 0x00000738, + 0x00000730, 0x00000740, 0x00000710, 0x00000760, + 0x00000368, 0x00000358, 0x00000320, 0x00000308, + 0x00000318, 0x00000378, 0x00000328, 0x00000348, + 0x00000300, 0x00000350, 0x00000370, 0x00000338, + 0x00000330, 0x00000340, 0x00000310, 0x00000360, + 0x000005e8, 0x000005d8, 0x000005a0, 0x00000588, + 0x00000598, 0x000005f8, 0x000005a8, 0x000005c8, + 0x00000580, 0x000005d0, 0x000005f0, 0x000005b8, + 0x000005b0, 0x000005c0, 0x00000590, 0x000005e0, + 0x00000468, 0x00000458, 0x00000420, 0x00000408, + 0x00000418, 0x00000478, 0x00000428, 0x00000448, + 0x00000400, 0x00000450, 0x00000470, 0x00000438, + 0x00000430, 0x00000440, 0x00000410, 0x00000460, + 0x00000668, 0x00000658, 0x00000620, 0x00000608, + 0x00000618, 0x00000678, 0x00000628, 0x00000648, + 0x00000600, 0x00000650, 0x00000670, 0x00000638, + 0x00000630, 0x00000640, 0x00000610, 0x00000660 } +}; + +#include "gost.h" + +static gcry_err_code_t +gost_setkey (void *c, const byte *key, unsigned keylen) +{ + int i; + GOST28147_context *ctx = c; + + if (keylen != 256 / 8) + return GPG_ERR_INV_KEYLEN; + + for (i = 0; i < 8; i++) + { + ctx->key[i] = (key[4 * i + 3] << 24) | + (key[4 * i + 2] << 16) | + (key[4 * i + 1] << 8) | + (key[4 * i + 0] << 0); + } + return GPG_ERR_NO_ERROR; +} + +static u32 +gost_val (GOST28147_context *ctx, u32 cm1, int subkey) +{ + cm1 += ctx->key[subkey]; + cm1 = test_sbox[0][ (cm1 >> 0) & 0xff] | + test_sbox[1][ (cm1 >> 8) & 0xff] | + test_sbox[2][ (cm1 >> 16) & 0xff] | + test_sbox[3][ (cm1 >> 24) & 0xff]; + return cm1; +} + +static unsigned int +gost_encrypt_block (void *c, byte *outbuf, const byte *inbuf) +{ + GOST28147_context *ctx = c; + u32 n1, n2; + + n1 = (inbuf[0] << 0) | + (inbuf[1] << 8) | + (inbuf[2] << 16) | + (inbuf[3] << 24); + n2 = (inbuf[4] << 0) | + (inbuf[5] << 8) | + (inbuf[6] << 16) | + (inbuf[7] << 24); + + n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1); + n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3); + n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5); + n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7); + + n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1); + n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3); + n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5); + n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7); + + n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1); + n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3); + n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5); + n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7); + + n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6); + n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4); + n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2); + n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0); + + outbuf[0 + 0] = (n2 >> (0 * 8)) & 0xff; + outbuf[1 + 0] = (n2 >> (1 * 8)) & 0xff; + outbuf[2 + 0] = (n2 >> (2 * 8)) & 0xff; + outbuf[3 + 0] = (n2 >> (3 * 8)) & 0xff; + outbuf[0 + 4] = (n1 >> (0 * 8)) & 0xff; + outbuf[1 + 4] = (n1 >> (1 * 8)) & 0xff; + outbuf[2 + 4] = (n1 >> (2 * 8)) & 0xff; + outbuf[3 + 4] = (n1 >> (3 * 8)) & 0xff; + + return /* burn_stack */ 4*sizeof(void*) /* func call */ + + 3*sizeof(void*) /* stack */ + + 4*sizeof(void*) /* gost_val call */; +} + +unsigned int _gcry_gost_enc_one (GOST28147_context *c, const byte *key, + byte *out, byte *in) +{ + gost_setkey (c, key, 32); + return gost_encrypt_block (c, out, in) + 5 * sizeof(void *); +} + +static unsigned int +gost_decrypt_block (void *c, byte *outbuf, const byte *inbuf) +{ + GOST28147_context *ctx = c; + u32 n1, n2; + + n1 = (inbuf[0] << 0) | + (inbuf[1] << 8) | + (inbuf[2] << 16) | + (inbuf[3] << 24); + n2 = (inbuf[4] << 0) | + (inbuf[5] << 8) | + (inbuf[6] << 16) | + (inbuf[7] << 24); + + n2 ^= gost_val (ctx, n1, 0); n1 ^= gost_val (ctx, n2, 1); + n2 ^= gost_val (ctx, n1, 2); n1 ^= gost_val (ctx, n2, 3); + n2 ^= gost_val (ctx, n1, 4); n1 ^= gost_val (ctx, n2, 5); + n2 ^= gost_val (ctx, n1, 6); n1 ^= gost_val (ctx, n2, 7); + + n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6); + n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4); + n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2); + n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0); + + n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6); + n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4); + n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2); + n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0); + + n2 ^= gost_val (ctx, n1, 7); n1 ^= gost_val (ctx, n2, 6); + n2 ^= gost_val (ctx, n1, 5); n1 ^= gost_val (ctx, n2, 4); + n2 ^= gost_val (ctx, n1, 3); n1 ^= gost_val (ctx, n2, 2); + n2 ^= gost_val (ctx, n1, 1); n1 ^= gost_val (ctx, n2, 0); + + outbuf[0 + 0] = (n2 >> (0 * 8)) & 0xff; + outbuf[1 + 0] = (n2 >> (1 * 8)) & 0xff; + outbuf[2 + 0] = (n2 >> (2 * 8)) & 0xff; + outbuf[3 + 0] = (n2 >> (3 * 8)) & 0xff; + outbuf[0 + 4] = (n1 >> (0 * 8)) & 0xff; + outbuf[1 + 4] = (n1 >> (1 * 8)) & 0xff; + outbuf[2 + 4] = (n1 >> (2 * 8)) & 0xff; + outbuf[3 + 4] = (n1 >> (3 * 8)) & 0xff; + + return /* burn_stack */ 4*sizeof(void*) /* func call */ + + 3*sizeof(void*) /* stack */ + + 4*sizeof(void*) /* gost_val call */; +} + +gcry_cipher_spec_t _gcry_cipher_spec_gost28147 = + { + GCRY_CIPHER_GOST28147, {0, 0}, + "GOST28147", NULL, NULL, 8, 256, + sizeof (GOST28147_context), + gost_setkey, + gost_encrypt_block, + gost_decrypt_block, + }; diff --git a/plugins/MirOTR/Libgcrypt/cipher/gostr3411-94.c b/plugins/MirOTR/Libgcrypt/cipher/gostr3411-94.c new file mode 100644 index 0000000000..5486964db9 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/gostr3411-94.c @@ -0,0 +1,286 @@ +/* gostr3411-94.c - GOST R 34.11-94 hash function + * Copyright (C) 2012 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "g10lib.h" +#include "bithelp.h" +#include "cipher.h" +#include "hash-common.h" + +#include "gost.h" + +#define max(a, b) (((a) > (b)) ? (a) : (b)) + +typedef struct { + gcry_md_block_ctx_t bctx; + GOST28147_context hd; + byte h[32]; + byte sigma[32]; + u32 len; +} GOSTR3411_CONTEXT; + +static unsigned int +transform (void *c, const unsigned char *data); + +static void +gost3411_init (void *context, unsigned int flags) +{ + GOSTR3411_CONTEXT *hd = context; + + (void)flags; + + memset (&hd->hd, 0, sizeof(hd->hd)); + memset (hd->h, 0, 32); + memset (hd->sigma, 0, 32); + + hd->bctx.nblocks = 0; + hd->bctx.count = 0; + hd->bctx.blocksize = 32; + hd->bctx.bwrite = transform; +} + +static void +do_p (unsigned char *p, unsigned char *u, unsigned char *v) +{ + int i, k; + for (k = 0; k < 8; k++) + { + for (i = 0; i < 4; i++) + { + p[i + 4 * k] = u[8 * i + k] ^ v[8 * i + k]; + } + } +} + +static void +do_a (unsigned char *u) +{ + unsigned char temp[8]; + int i; + memcpy (temp, u, 8); + memmove (u, u+8, 24); + for (i = 0; i < 8; i++) + { + u[24 + i] = u[i] ^ temp[i]; + } +} +/* apply do_a twice: 1 2 3 4 -> 3 4 1^2 2^3 */ +static void +do_a2 (unsigned char *u) +{ + unsigned char temp[16]; + int i; + memcpy (temp, u, 16); + memcpy (u, u + 16, 16); + for (i = 0; i < 8; i++) + { + u[16 + i] = temp[i] ^ temp[8 + i]; + u[24 + i] = u[i] ^ temp[8 + i]; + } +} + +static void +do_apply_c2 (unsigned char *u) +{ + u[ 1] ^= 0xff; + u[ 3] ^= 0xff; + u[ 5] ^= 0xff; + u[ 7] ^= 0xff; + + u[ 8] ^= 0xff; + u[10] ^= 0xff; + u[12] ^= 0xff; + u[14] ^= 0xff; + + u[17] ^= 0xff; + u[18] ^= 0xff; + u[20] ^= 0xff; + u[23] ^= 0xff; + + u[24] ^= 0xff; + u[28] ^= 0xff; + u[29] ^= 0xff; + u[31] ^= 0xff; +} + +#define do_phi_step(e, i) \ + e[(0 + 2*i) % 32] ^= e[(2 + 2*i) % 32] ^ e[(4 + 2*i) % 32] ^ e[(6 + 2*i) % 32] ^ e[(24 + 2*i) % 32] ^ e[(30 + 2*i) % 32]; \ + e[(1 + 2*i) % 32] ^= e[(3 + 2*i) % 32] ^ e[(5 + 2*i) % 32] ^ e[(7 + 2*i) % 32] ^ e[(25 + 2*i) % 32] ^ e[(31 + 2*i) % 32]; + +static void +do_phi_submix (unsigned char *e, unsigned char *x, int round) +{ + int i; + round *= 2; + for (i = 0; i < 32; i++) + { + e[(i + round) % 32] ^= x[i]; + } +} + +static void +do_add (unsigned char *s, unsigned char *a) +{ + unsigned temp = 0; + int i; + + for (i = 0; i < 32; i++) + { + temp = s[i] + a[i] + (temp >> 8); + s[i] = temp & 0xff; + } +} + +static unsigned int +do_hash_step (GOST28147_context *hd, unsigned char *h, unsigned char *m) +{ + unsigned char u[32], v[32], s[32]; + unsigned char k[32]; + unsigned int burn; + int i; + + memcpy (u, h, 32); + memcpy (v, m, 32); + + for (i = 0; i < 4; i++) { + do_p (k, u, v); + + burn = _gcry_gost_enc_one (hd, k, s + i*8, h + i*8); + + do_a (u); + if (i == 1) + do_apply_c2 (u); + do_a2 (v); + } + + for (i = 0; i < 5; i++) + { + do_phi_step (s, 0); + do_phi_step (s, 1); + do_phi_step (s, 2); + do_phi_step (s, 3); + do_phi_step (s, 4); + do_phi_step (s, 5); + do_phi_step (s, 6); + do_phi_step (s, 7); + do_phi_step (s, 8); + do_phi_step (s, 9); + /* That is in total 12 + 1 + 61 = 74 = 16 * 4 + 10 rounds */ + if (i == 4) + break; + do_phi_step (s, 10); + do_phi_step (s, 11); + if (i == 0) + do_phi_submix(s, m, 12); + do_phi_step (s, 12); + if (i == 0) + do_phi_submix(s, h, 13); + do_phi_step (s, 13); + do_phi_step (s, 14); + do_phi_step (s, 15); + } + + memcpy (h, s+20, 12); + memcpy (h+12, s, 20); + + return /* burn_stack */ 4 * sizeof(void*) /* func call (ret addr + args) */ + + 4 * 32 + 2 * sizeof(int) /* stack */ + + max(burn /* _gcry_gost_enc_one */, + sizeof(void*) * 2 /* do_a2 call */ + + 16 + sizeof(int) /* do_a2 stack */ ); +} + + +static unsigned int +transform (void *ctx, const unsigned char *data) +{ + GOSTR3411_CONTEXT *hd = ctx; + byte m[32]; + unsigned int burn; + + memcpy (m, data, 32); + burn = do_hash_step (&hd->hd, hd->h, m); + do_add (hd->sigma, m); + + return /* burn_stack */ burn + 3 * sizeof(void*) + 32 + 2 * sizeof(void*); +} + +/* + The routine finally terminates the computation and returns the + digest. The handle is prepared for a new cycle, but adding bytes + to the handle will the destroy the returned buffer. Returns: 32 + bytes with the message the digest. */ +static void +gost3411_final (void *context) +{ + GOSTR3411_CONTEXT *hd = context; + size_t padlen = 0; + byte l[32]; + int i; + u32 nblocks; + + if (hd->bctx.count > 0) + { + padlen = 32 - hd->bctx.count; + memset (hd->bctx.buf + hd->bctx.count, 0, padlen); + hd->bctx.count += padlen; + _gcry_md_block_write (hd, NULL, 0); /* flush */; + } + + if (hd->bctx.count != 0) + return; /* Something went wrong */ + + memset (l, 0, 32); + + nblocks = hd->bctx.nblocks; + if (padlen) + { + nblocks --; + l[0] = 256 - padlen * 8; + } + + for (i = 1; i < 32 && nblocks != 0; i++) + { + l[i] = nblocks % 256; + nblocks /= 256; + } + + do_hash_step (&hd->hd, hd->h, l); + do_hash_step (&hd->hd, hd->h, hd->sigma); +} + +static byte * +gost3411_read (void *context) +{ + GOSTR3411_CONTEXT *hd = context; + + return hd->h; +} +gcry_md_spec_t _gcry_digest_spec_gost3411_94 = + { + GCRY_MD_GOSTR3411_94, {0, 0}, + "GOSTR3411_94", NULL, 0, NULL, 32, + gost3411_init, _gcry_md_block_write, gost3411_final, gost3411_read, + sizeof (GOSTR3411_CONTEXT) + }; diff --git a/plugins/MirOTR/Libgcrypt/cipher/hash-common.c b/plugins/MirOTR/Libgcrypt/cipher/hash-common.c index 656e180e2d..ffbc39ed2b 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/hash-common.c +++ b/plugins/MirOTR/Libgcrypt/cipher/hash-common.c @@ -21,7 +21,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#ifdef HAVE_STDINT_H +#ifdef HAVE_STDINT_H # include <stdint.h> #endif @@ -35,10 +35,10 @@ describing the error. DATAMODE controls what will be hashed according to this table: - + 0 - Hash the supplied DATA of DATALEN. 1 - Hash one million times a 'a'. DATA and DATALEN are ignored. - + */ const char * _gcry_hash_selftest_check_one (int algo, @@ -49,14 +49,14 @@ _gcry_hash_selftest_check_one (int algo, gcry_error_t err = 0; gcry_md_hd_t hd; unsigned char *digest; - + if (_gcry_md_get_algo_dlen (algo) != expectlen) return "digest size does not match expected size"; - + err = _gcry_md_open (&hd, algo, 0); if (err) return "gcry_md_open failed"; - + switch (datamode) { case 0: @@ -64,7 +64,7 @@ _gcry_hash_selftest_check_one (int algo, break; case 1: /* Hash one million times an "a". */ - { + { char aaa[1000]; int i; @@ -82,7 +82,7 @@ _gcry_hash_selftest_check_one (int algo, if (!result) { digest = _gcry_md_read (hd, algo); - + if ( memcmp (digest, expect, expectlen) ) result = "digest mismatch"; } @@ -92,3 +92,54 @@ _gcry_hash_selftest_check_one (int algo, return result; } + +/* Common function to write a chunk of data to the transform function + of a hash algorithm. Note that the use of the term "block" does + not imply a fixed size block. */ +void +_gcry_md_block_write (void *context, const void *inbuf_arg, size_t inlen) +{ + const unsigned char *inbuf = inbuf_arg; + gcry_md_block_ctx_t *hd = context; + unsigned int stack_burn = 0; + + if (sizeof(hd->buf) < hd->blocksize) + BUG(); + + if (hd->buf == NULL || hd->bwrite == NULL) + return; + + if (hd->count == hd->blocksize) /* Flush the buffer. */ + { + stack_burn = hd->bwrite (hd, hd->buf); + _gcry_burn_stack (stack_burn); + stack_burn = 0; + hd->count = 0; + if (!++hd->nblocks) + hd->nblocks_high++; + } + if (!inbuf) + return; + + if (hd->count) + { + for (; inlen && hd->count < hd->blocksize; inlen--) + hd->buf[hd->count++] = *inbuf++; + _gcry_md_block_write (hd, NULL, 0); + if (!inlen) + return; + } + + while (inlen >= hd->blocksize) + { + stack_burn = hd->bwrite (hd, inbuf); + hd->count = 0; + if (!++hd->nblocks) + hd->nblocks_high++; + inlen -= hd->blocksize; + inbuf += hd->blocksize; + } + _gcry_burn_stack (stack_burn); + for (; inlen && hd->count < hd->blocksize; inlen--) + hd->buf[hd->count++] = *inbuf++; +} diff --git a/plugins/MirOTR/Libgcrypt/cipher/hash-common.h b/plugins/MirOTR/Libgcrypt/cipher/hash-common.h index 9c4e333594..aa95365a8c 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/hash-common.h +++ b/plugins/MirOTR/Libgcrypt/cipher/hash-common.h @@ -20,14 +20,39 @@ #ifndef GCRY_HASH_COMMON_H #define GCRY_HASH_COMMON_H +#include "types.h" -const char * _gcry_hash_selftest_check_one -/**/ (int algo, + +const char * _gcry_hash_selftest_check_one +/**/ (int algo, int datamode, const void *data, size_t datalen, const void *expect, size_t expectlen); - +/* Type for the md_write helper function. */ +typedef unsigned int (*_gcry_md_block_write_t) (void *c, + const unsigned char *buf); + +#if defined(HAVE_U64_TYPEDEF) && (defined(USE_SHA512) || defined(USE_WHIRLPOOL)) +/* SHA-512 needs u64 and larger buffer. Whirlpool needs u64. */ +# define MD_BLOCK_MAX_BLOCKSIZE 128 +# define MD_NBLOCKS_TYPE u64 +#else +# define MD_BLOCK_MAX_BLOCKSIZE 64 +# define MD_NBLOCKS_TYPE u32 +#endif + +typedef struct gcry_md_block_ctx +{ + byte buf[MD_BLOCK_MAX_BLOCKSIZE]; + MD_NBLOCKS_TYPE nblocks; + MD_NBLOCKS_TYPE nblocks_high; + int count; + size_t blocksize; + _gcry_md_block_write_t bwrite; +} gcry_md_block_ctx_t; +void +_gcry_md_block_write( void *context, const void *inbuf_arg, size_t inlen); #endif /*GCRY_HASH_COMMON_H*/ diff --git a/plugins/MirOTR/Libgcrypt/cipher/hmac-tests.c b/plugins/MirOTR/Libgcrypt/cipher/hmac-tests.c index 56c9b203c0..7c27342c17 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/hmac-tests.c +++ b/plugins/MirOTR/Libgcrypt/cipher/hmac-tests.c @@ -17,7 +17,7 @@ * License along with this program; if not, see <http://www.gnu.org/licenses/>. */ -/* +/* Although algorithm self-tests are usually implemented in the module implementing the algorithm, the case for HMAC is different because HMAC is implemnetd on a higher level using a special feature of the @@ -33,7 +33,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#ifdef HAVE_STDINT_H +#ifdef HAVE_STDINT_H # include <stdint.h> #endif @@ -47,7 +47,7 @@ succdess or a string describing the failure. */ static const char * check_one (int algo, - const void *data, size_t datalen, + const void *data, size_t datalen, const void *key, size_t keylen, const void *expect, size_t expectlen) { @@ -88,7 +88,7 @@ check_one (int algo, return "does not match"; } _gcry_md_close (hd); - return NULL; + return NULL; } @@ -123,7 +123,7 @@ selftests_sha1 (int extended, selftest_report_func_t report) "\xa4\x58\x30\x73\x7d\x5c\xc6\xc7\x5d\x24", 20); if (errtxt) goto failed; - + what = "FIPS-198a, A.3"; for (i=0, j=0x50; i < 100; i++) key[i] = j++; @@ -134,7 +134,7 @@ selftests_sha1 (int extended, selftest_report_func_t report) "\x5c\xaf\x7c\xb0\x92\xec\xf8\xd1\xa3\xaa", 20 ); if (errtxt) goto failed; - + what = "FIPS-198a, A.4"; for (i=0, j=0x70; i < 49; i++) key[i] = j++; @@ -160,7 +160,7 @@ selftests_sha1 (int extended, selftest_report_func_t report) static gpg_err_code_t selftests_sha224 (int extended, selftest_report_func_t report) { - static struct + static struct { const char * const desc; const char * const data; @@ -169,7 +169,7 @@ selftests_sha224 (int extended, selftest_report_func_t report) } tv[] = { { "data-28 key-4", - "what do ya want for nothing?", + "what do ya want for nothing?", "Jefe", { 0xa3, 0x0e, 0x01, 0x09, 0x8b, 0xc6, 0xdb, 0xbf, 0x45, 0x69, 0x0f, 0x3a, 0x7e, 0x9e, 0x6d, 0x0f, @@ -248,7 +248,7 @@ selftests_sha224 (int extended, selftest_report_func_t report) const char *what; const char *errtxt; int tvidx; - + for (tvidx=0; tv[tvidx].desc; tvidx++) { what = tv[tvidx].desc; @@ -274,7 +274,7 @@ selftests_sha224 (int extended, selftest_report_func_t report) static gpg_err_code_t selftests_sha256 (int extended, selftest_report_func_t report) { - static struct + static struct { const char * const desc; const char * const data; @@ -283,7 +283,7 @@ selftests_sha256 (int extended, selftest_report_func_t report) } tv[] = { { "data-28 key-4", - "what do ya want for nothing?", + "what do ya want for nothing?", "Jefe", { 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, @@ -362,7 +362,7 @@ selftests_sha256 (int extended, selftest_report_func_t report) const char *what; const char *errtxt; int tvidx; - + for (tvidx=0; tv[tvidx].desc; tvidx++) { hmac256_context_t hmachd; @@ -416,7 +416,7 @@ selftests_sha256 (int extended, selftest_report_func_t report) static gpg_err_code_t selftests_sha384 (int extended, selftest_report_func_t report) { - static struct + static struct { const char * const desc; const char * const data; @@ -425,7 +425,7 @@ selftests_sha384 (int extended, selftest_report_func_t report) } tv[] = { { "data-28 key-4", - "what do ya want for nothing?", + "what do ya want for nothing?", "Jefe", { 0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31, 0x61, 0x7f, 0x78, 0xd2, 0xb5, 0x8a, 0x6b, 0x1b, @@ -516,7 +516,7 @@ selftests_sha384 (int extended, selftest_report_func_t report) const char *what; const char *errtxt; int tvidx; - + for (tvidx=0; tv[tvidx].desc; tvidx++) { what = tv[tvidx].desc; @@ -542,7 +542,7 @@ selftests_sha384 (int extended, selftest_report_func_t report) static gpg_err_code_t selftests_sha512 (int extended, selftest_report_func_t report) { - static struct + static struct { const char * const desc; const char * const data; @@ -551,7 +551,7 @@ selftests_sha512 (int extended, selftest_report_func_t report) } tv[] = { { "data-28 key-4", - "what do ya want for nothing?", + "what do ya want for nothing?", "Jefe", { 0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2, 0xe3, 0x95, 0xfb, 0xe7, 0x3b, 0x56, 0xe0, 0xa3, @@ -654,7 +654,7 @@ selftests_sha512 (int extended, selftest_report_func_t report) const char *what; const char *errtxt; int tvidx; - + for (tvidx=0; tv[tvidx].desc; tvidx++) { what = tv[tvidx].desc; @@ -718,7 +718,7 @@ _gcry_hmac_selftest (int algo, int extended, selftest_report_func_t report) { gcry_err_code_t ec = 0; - if (!gcry_md_test_algo (algo)) + if (!_gcry_md_test_algo (algo)) { ec = run_selftests (algo, extended, report); } diff --git a/plugins/MirOTR/Libgcrypt/cipher/idea.c b/plugins/MirOTR/Libgcrypt/cipher/idea.c new file mode 100644 index 0000000000..14234cf07d --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/idea.c @@ -0,0 +1,379 @@ +/* idea.c - IDEA function + * Copyright 1997, 1998, 1999, 2001 Werner Koch (dd9jn) + * Copyright 2013 g10 Code GmbH + * + * 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 + * WERNER KOCH 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. + * + * Except as contained in this notice, the name of Werner Koch shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from Werner Koch. + * + * Patents on IDEA have expired: + * Europe: EP0482154 on 2011-05-16, + * Japan: JP3225440 on 2011-05-16, + * U.S.: 5,214,703 on 2012-01-07. + */ + +/* + * Please see http://www.noepatents.org/ to learn why software patents + * are bad for society and what you can do to fight them. + * + * The code herein is based on the one from: + * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996. + * ISBN 0-471-11709-9. + */ + + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "types.h" /* for byte and u32 typedefs */ +#include "g10lib.h" +#include "cipher.h" + + +#define IDEA_KEYSIZE 16 +#define IDEA_BLOCKSIZE 8 +#define IDEA_ROUNDS 8 +#define IDEA_KEYLEN (6*IDEA_ROUNDS+4) + +typedef struct { + u16 ek[IDEA_KEYLEN]; + u16 dk[IDEA_KEYLEN]; + int have_dk; +} IDEA_context; + +static const char *selftest(void); + + +static u16 +mul_inv( u16 x ) +{ + u16 t0, t1; + u16 q, y; + + if( x < 2 ) + return x; + t1 = 0x10001UL / x; + y = 0x10001UL % x; + if( y == 1 ) + return (1-t1) & 0xffff; + + t0 = 1; + do { + q = x / y; + x = x % y; + t0 += q * t1; + if( x == 1 ) + return t0; + q = y / x; + y = y % x; + t1 += q * t0; + } while( y != 1 ); + return (1-t1) & 0xffff; +} + + + +static void +expand_key( const byte *userkey, u16 *ek ) +{ + int i,j; + + for(j=0; j < 8; j++ ) { + ek[j] = (*userkey << 8) + userkey[1]; + userkey += 2; + } + for(i=0; j < IDEA_KEYLEN; j++ ) { + i++; + ek[i+7] = ek[i&7] << 9 | ek[(i+1)&7] >> 7; + ek += i & 8; + i &= 7; + } +} + + +static void +invert_key( u16 *ek, u16 dk[IDEA_KEYLEN] ) +{ + int i; + u16 t1, t2, t3; + u16 temp[IDEA_KEYLEN]; + u16 *p = temp + IDEA_KEYLEN; + + t1 = mul_inv( *ek++ ); + t2 = -*ek++; + t3 = -*ek++; + *--p = mul_inv( *ek++ ); + *--p = t3; + *--p = t2; + *--p = t1; + + for(i=0; i < IDEA_ROUNDS-1; i++ ) { + t1 = *ek++; + *--p = *ek++; + *--p = t1; + + t1 = mul_inv( *ek++ ); + t2 = -*ek++; + t3 = -*ek++; + *--p = mul_inv( *ek++ ); + *--p = t2; + *--p = t3; + *--p = t1; + } + t1 = *ek++; + *--p = *ek++; + *--p = t1; + + t1 = mul_inv( *ek++ ); + t2 = -*ek++; + t3 = -*ek++; + *--p = mul_inv( *ek++ ); + *--p = t3; + *--p = t2; + *--p = t1; + memcpy(dk, temp, sizeof(temp) ); + memset(temp, 0, sizeof(temp) ); /* burn temp */ +} + + +static void +cipher( byte *outbuf, const byte *inbuf, u16 *key ) +{ + u16 s2, s3; + u16 in[4]; + int r = IDEA_ROUNDS; +#define x1 (in[0]) +#define x2 (in[1]) +#define x3 (in[2]) +#define x4 (in[3]) +#define MUL(x,y) \ + do {u16 _t16; u32 _t32; \ + if( (_t16 = (y)) ) { \ + if( (x = (x)&0xffff) ) { \ + _t32 = (u32)x * _t16; \ + x = _t32 & 0xffff; \ + _t16 = _t32 >> 16; \ + x = ((x)-_t16) + (x<_t16?1:0); \ + } \ + else { \ + x = 1 - _t16; \ + } \ + } \ + else { \ + x = 1 - x; \ + } \ + } while(0) + + memcpy (in, inbuf, sizeof in); +#ifndef WORDS_BIGENDIAN + x1 = (x1>>8) | (x1<<8); + x2 = (x2>>8) | (x2<<8); + x3 = (x3>>8) | (x3<<8); + x4 = (x4>>8) | (x4<<8); +#endif + do { + MUL(x1, *key++); + x2 += *key++; + x3 += *key++; + MUL(x4, *key++ ); + + s3 = x3; + x3 ^= x1; + MUL(x3, *key++); + s2 = x2; + x2 ^=x4; + x2 += x3; + MUL(x2, *key++); + x3 += x2; + + x1 ^= x2; + x4 ^= x3; + + x2 ^= s3; + x3 ^= s2; + } while( --r ); + MUL(x1, *key++); + x3 += *key++; + x2 += *key++; + MUL(x4, *key); + +#ifndef WORDS_BIGENDIAN + x1 = (x1>>8) | (x1<<8); + x2 = (x2>>8) | (x2<<8); + x3 = (x3>>8) | (x3<<8); + x4 = (x4>>8) | (x4<<8); +#endif + memcpy (outbuf+0, &x1, 2); + memcpy (outbuf+2, &x3, 2); + memcpy (outbuf+4, &x2, 2); + memcpy (outbuf+6, &x4, 2); +#undef MUL +#undef x1 +#undef x2 +#undef x3 +#undef x4 +} + + +static int +do_setkey( IDEA_context *c, const byte *key, unsigned int keylen ) +{ + static int initialized = 0; + static const char *selftest_failed = 0; + + if( !initialized ) { + initialized = 1; + selftest_failed = selftest(); + if( selftest_failed ) + log_error( "%s\n", selftest_failed ); + } + if( selftest_failed ) + return GPG_ERR_SELFTEST_FAILED; + + assert(keylen == 16); + c->have_dk = 0; + expand_key( key, c->ek ); + invert_key( c->ek, c->dk ); + return 0; +} + +static gcry_err_code_t +idea_setkey (void *context, const byte *key, unsigned int keylen) +{ + IDEA_context *ctx = context; + int rc = do_setkey (ctx, key, keylen); + _gcry_burn_stack (23+6*sizeof(void*)); + return rc; +} + +static void +encrypt_block( IDEA_context *c, byte *outbuf, const byte *inbuf ) +{ + cipher( outbuf, inbuf, c->ek ); +} + +static unsigned int +idea_encrypt (void *context, byte *out, const byte *in) +{ + IDEA_context *ctx = context; + encrypt_block (ctx, out, in); + return /*burn_stack*/ (24+3*sizeof (void*)); +} + +static void +decrypt_block( IDEA_context *c, byte *outbuf, const byte *inbuf ) +{ + if( !c->have_dk ) { + c->have_dk = 1; + invert_key( c->ek, c->dk ); + } + cipher( outbuf, inbuf, c->dk ); +} + +static unsigned int +idea_decrypt (void *context, byte *out, const byte *in) +{ + IDEA_context *ctx = context; + decrypt_block (ctx, out, in); + return /*burn_stack*/ (24+3*sizeof (void*)); +} + + +static const char * +selftest( void ) +{ +static struct { + byte key[16]; + byte plain[8]; + byte cipher[8]; +} test_vectors[] = { + { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 }, + { 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03 }, + { 0x11, 0xFB, 0xED, 0x2B, 0x01, 0x98, 0x6D, 0xE5 } }, + { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 }, + { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }, + { 0x54, 0x0E, 0x5F, 0xEA, 0x18, 0xC2, 0xF8, 0xB1 } }, + { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 }, + { 0x00, 0x19, 0x32, 0x4B, 0x64, 0x7D, 0x96, 0xAF }, + { 0x9F, 0x0A, 0x0A, 0xB6, 0xE1, 0x0C, 0xED, 0x78 } }, + { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 }, + { 0xF5, 0x20, 0x2D, 0x5B, 0x9C, 0x67, 0x1B, 0x08 }, + { 0xCF, 0x18, 0xFD, 0x73, 0x55, 0xE2, 0xC5, 0xC5 } }, + { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 }, + { 0xFA, 0xE6, 0xD2, 0xBE, 0xAA, 0x96, 0x82, 0x6E }, + { 0x85, 0xDF, 0x52, 0x00, 0x56, 0x08, 0x19, 0x3D } }, + { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 }, + { 0x0A, 0x14, 0x1E, 0x28, 0x32, 0x3C, 0x46, 0x50 }, + { 0x2F, 0x7D, 0xE7, 0x50, 0x21, 0x2F, 0xB7, 0x34 } }, + { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 }, + { 0x05, 0x0A, 0x0F, 0x14, 0x19, 0x1E, 0x23, 0x28 }, + { 0x7B, 0x73, 0x14, 0x92, 0x5D, 0xE5, 0x9C, 0x09 } }, + { { 0x00, 0x05, 0x00, 0x0A, 0x00, 0x0F, 0x00, 0x14, + 0x00, 0x19, 0x00, 0x1E, 0x00, 0x23, 0x00, 0x28 }, + { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }, + { 0x3E, 0xC0, 0x47, 0x80, 0xBE, 0xFF, 0x6E, 0x20 } }, + { { 0x3A, 0x98, 0x4E, 0x20, 0x00, 0x19, 0x5D, 0xB3, + 0x2E, 0xE5, 0x01, 0xC8, 0xC4, 0x7C, 0xEA, 0x60 }, + { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }, + { 0x97, 0xBC, 0xD8, 0x20, 0x07, 0x80, 0xDA, 0x86 } }, + { { 0x00, 0x64, 0x00, 0xC8, 0x01, 0x2C, 0x01, 0x90, + 0x01, 0xF4, 0x02, 0x58, 0x02, 0xBC, 0x03, 0x20 }, + { 0x05, 0x32, 0x0A, 0x64, 0x14, 0xC8, 0x19, 0xFA }, + { 0x65, 0xBE, 0x87, 0xE7, 0xA2, 0x53, 0x8A, 0xED } }, + { { 0x9D, 0x40, 0x75, 0xC1, 0x03, 0xBC, 0x32, 0x2A, + 0xFB, 0x03, 0xE7, 0xBE, 0x6A, 0xB3, 0x00, 0x06 }, + { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, + { 0xF5, 0xDB, 0x1A, 0xC4, 0x5E, 0x5E, 0xF9, 0xF9 } } +}; + IDEA_context c; + byte buffer[8]; + int i; + + for(i=0; i < DIM(test_vectors); i++ ) { + do_setkey( &c, test_vectors[i].key, 16 ); + encrypt_block( &c, buffer, test_vectors[i].plain ); + if( memcmp( buffer, test_vectors[i].cipher, 8 ) ) + return "IDEA test encryption failed."; + decrypt_block( &c, buffer, test_vectors[i].cipher ); + if( memcmp( buffer, test_vectors[i].plain, 8 ) ) + return "IDEA test decryption failed."; + } + + return NULL; +} + + +gcry_cipher_spec_t _gcry_cipher_spec_idea = + { + GCRY_CIPHER_IDEA, {0, 0}, + "IDEA", NULL, NULL, IDEA_BLOCKSIZE, 128, + sizeof (IDEA_context), + idea_setkey, idea_encrypt, idea_decrypt + }; diff --git a/plugins/MirOTR/Libgcrypt/cipher/kdf-internal.h b/plugins/MirOTR/Libgcrypt/cipher/kdf-internal.h new file mode 100644 index 0000000000..7079860e99 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/kdf-internal.h @@ -0,0 +1,40 @@ +/* kdf-internal.h - Internal defs for kdf.c + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef GCRY_KDF_INTERNAL_H +#define GCRY_KDF_INTERNAL_H + +/*-- kdf.c --*/ +gpg_err_code_t +_gcry_kdf_pkdf2 (const void *passphrase, size_t passphraselen, + int hashalgo, + const void *salt, size_t saltlen, + unsigned long iterations, + size_t keysize, void *keybuffer); + +/*-- scrypt.c --*/ +gcry_err_code_t +_gcry_kdf_scrypt (const unsigned char *passwd, size_t passwdlen, + int algo, int subalgo, + const unsigned char *salt, size_t saltlen, + unsigned long iterations, + size_t dklen, unsigned char *dk); + + +#endif /*GCRY_KDF_INTERNAL_H*/ diff --git a/plugins/MirOTR/Libgcrypt/cipher/kdf.c b/plugins/MirOTR/Libgcrypt/cipher/kdf.c new file mode 100644 index 0000000000..af0dc48009 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/kdf.c @@ -0,0 +1,300 @@ +/* kdf.c - Key Derivation Functions + * Copyright (C) 1998, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "g10lib.h" +#include "cipher.h" +#include "ath.h" +#include "kdf-internal.h" + + +/* Transform a passphrase into a suitable key of length KEYSIZE and + store this key in the caller provided buffer KEYBUFFER. The caller + must provide an HASHALGO, a valid ALGO and depending on that algo a + SALT of 8 bytes and the number of ITERATIONS. Code taken from + gnupg/agent/protect.c:hash_passphrase. */ +static gpg_err_code_t +openpgp_s2k (const void *passphrase, size_t passphraselen, + int algo, int hashalgo, + const void *salt, size_t saltlen, + unsigned long iterations, + size_t keysize, void *keybuffer) +{ + gpg_err_code_t ec; + gcry_md_hd_t md; + char *key = keybuffer; + int pass, i; + int used = 0; + int secmode; + + if ((algo == GCRY_KDF_SALTED_S2K || algo == GCRY_KDF_ITERSALTED_S2K) + && (!salt || saltlen != 8)) + return GPG_ERR_INV_VALUE; + + secmode = _gcry_is_secure (passphrase) || _gcry_is_secure (keybuffer); + + ec = _gcry_md_open (&md, hashalgo, secmode? GCRY_MD_FLAG_SECURE : 0); + if (ec) + return ec; + + for (pass=0; used < keysize; pass++) + { + if (pass) + { + _gcry_md_reset (md); + for (i=0; i < pass; i++) /* Preset the hash context. */ + _gcry_md_putc (md, 0); + } + + if (algo == GCRY_KDF_SALTED_S2K || algo == GCRY_KDF_ITERSALTED_S2K) + { + int len2 = passphraselen + 8; + unsigned long count = len2; + + if (algo == GCRY_KDF_ITERSALTED_S2K) + { + count = iterations; + if (count < len2) + count = len2; + } + + while (count > len2) + { + _gcry_md_write (md, salt, saltlen); + _gcry_md_write (md, passphrase, passphraselen); + count -= len2; + } + if (count < saltlen) + _gcry_md_write (md, salt, count); + else + { + _gcry_md_write (md, salt, saltlen); + count -= saltlen; + _gcry_md_write (md, passphrase, count); + } + } + else + _gcry_md_write (md, passphrase, passphraselen); + + _gcry_md_final (md); + i = _gcry_md_get_algo_dlen (hashalgo); + if (i > keysize - used) + i = keysize - used; + memcpy (key+used, _gcry_md_read (md, hashalgo), i); + used += i; + } + _gcry_md_close (md); + return 0; +} + + +/* Transform a passphrase into a suitable key of length KEYSIZE and + store this key in the caller provided buffer KEYBUFFER. The caller + must provide PRFALGO which indicates the pseudorandom function to + use: This shall be the algorithms id of a hash algorithm; it is + used in HMAC mode. SALT is a salt of length SALTLEN and ITERATIONS + gives the number of iterations. */ +gpg_err_code_t +_gcry_kdf_pkdf2 (const void *passphrase, size_t passphraselen, + int hashalgo, + const void *salt, size_t saltlen, + unsigned long iterations, + size_t keysize, void *keybuffer) +{ + gpg_err_code_t ec; + gcry_md_hd_t md; + int secmode; + unsigned int dklen = keysize; + char *dk = keybuffer; + unsigned int hlen; /* Output length of the digest function. */ + unsigned int l; /* Rounded up number of blocks. */ + unsigned int r; /* Number of octets in the last block. */ + char *sbuf; /* Malloced buffer to concatenate salt and iter + as well as space to hold TBUF and UBUF. */ + char *tbuf; /* Buffer for T; ptr into SBUF, size is HLEN. */ + char *ubuf; /* Buffer for U; ptr into SBUF, size is HLEN. */ + unsigned int lidx; /* Current block number. */ + unsigned long iter; /* Current iteration number. */ + unsigned int i; + + /* NWe allow for a saltlen of 0 here to support scrypt. It is not + clear whether rfc2898 allows for this this, thus we do a test on + saltlen > 0 only in gcry_kdf_derive. */ + if (!salt || !iterations || !dklen) + return GPG_ERR_INV_VALUE; + + hlen = _gcry_md_get_algo_dlen (hashalgo); + if (!hlen) + return GPG_ERR_DIGEST_ALGO; + + secmode = _gcry_is_secure (passphrase) || _gcry_is_secure (keybuffer); + + /* We ignore step 1 from pksc5v2.1 which demands a check that dklen + is not larger that 0xffffffff * hlen. */ + + /* Step 2 */ + l = ((dklen - 1)/ hlen) + 1; + r = dklen - (l - 1) * hlen; + + /* Setup buffers and prepare a hash context. */ + sbuf = (secmode + ? xtrymalloc_secure (saltlen + 4 + hlen + hlen) + : xtrymalloc (saltlen + 4 + hlen + hlen)); + if (!sbuf) + return gpg_err_code_from_syserror (); + tbuf = sbuf + saltlen + 4; + ubuf = tbuf + hlen; + + ec = _gcry_md_open (&md, hashalgo, (GCRY_MD_FLAG_HMAC + | (secmode?GCRY_MD_FLAG_SECURE:0))); + if (ec) + { + xfree (sbuf); + return ec; + } + + ec = _gcry_md_setkey (md, passphrase, passphraselen); + if (ec) + { + _gcry_md_close (md); + xfree (sbuf); + return ec; + } + + /* Step 3 and 4. */ + memcpy (sbuf, salt, saltlen); + for (lidx = 1; lidx <= l; lidx++) + { + for (iter = 0; iter < iterations; iter++) + { + _gcry_md_reset (md); + if (!iter) /* Compute U_1: */ + { + sbuf[saltlen] = (lidx >> 24); + sbuf[saltlen + 1] = (lidx >> 16); + sbuf[saltlen + 2] = (lidx >> 8); + sbuf[saltlen + 3] = lidx; + _gcry_md_write (md, sbuf, saltlen + 4); + memcpy (ubuf, _gcry_md_read (md, 0), hlen); + memcpy (tbuf, ubuf, hlen); + } + else /* Compute U_(2..c): */ + { + _gcry_md_write (md, ubuf, hlen); + memcpy (ubuf, _gcry_md_read (md, 0), hlen); + for (i=0; i < hlen; i++) + tbuf[i] ^= ubuf[i]; + } + } + if (lidx == l) /* Last block. */ + memcpy (dk, tbuf, r); + else + { + memcpy (dk, tbuf, hlen); + dk += hlen; + } + } + + _gcry_md_close (md); + xfree (sbuf); + return 0; +} + + +/* Derive a key from a passphrase. KEYSIZE gives the requested size + of the keys in octets. KEYBUFFER is a caller provided buffer + filled on success with the derived key. The input passphrase is + taken from (PASSPHRASE,PASSPHRASELEN) which is an arbitrary memory + buffer. ALGO specifies the KDF algorithm to use; these are the + constants GCRY_KDF_*. SUBALGO specifies an algorithm used + internally by the KDF algorithms; this is usually a hash algorithm + but certain KDF algorithm may use it differently. {SALT,SALTLEN} + is a salt as needed by most KDF algorithms. ITERATIONS is a + positive integer parameter to most KDFs. 0 is returned on success, + or an error code on failure. */ +gpg_err_code_t +_gcry_kdf_derive (const void *passphrase, size_t passphraselen, + int algo, int subalgo, + const void *salt, size_t saltlen, + unsigned long iterations, + size_t keysize, void *keybuffer) +{ + gpg_err_code_t ec; + + if (!passphrase) + { + ec = GPG_ERR_INV_DATA; + goto leave; + } + + if (!keybuffer || !keysize) + { + ec = GPG_ERR_INV_VALUE; + goto leave; + } + + + switch (algo) + { + case GCRY_KDF_SIMPLE_S2K: + case GCRY_KDF_SALTED_S2K: + case GCRY_KDF_ITERSALTED_S2K: + if (!passphraselen) + ec = GPG_ERR_INV_DATA; + else + ec = openpgp_s2k (passphrase, passphraselen, algo, subalgo, + salt, saltlen, iterations, keysize, keybuffer); + break; + + case GCRY_KDF_PBKDF1: + ec = GPG_ERR_UNSUPPORTED_ALGORITHM; + break; + + case GCRY_KDF_PBKDF2: + if (!saltlen) + ec = GPG_ERR_INV_VALUE; + else + ec = _gcry_kdf_pkdf2 (passphrase, passphraselen, subalgo, + salt, saltlen, iterations, keysize, keybuffer); + break; + + case 41: + case GCRY_KDF_SCRYPT: +#if USE_SCRYPT + ec = _gcry_kdf_scrypt (passphrase, passphraselen, algo, subalgo, + salt, saltlen, iterations, keysize, keybuffer); +#else + ec = GPG_ERR_UNSUPPORTED_ALGORITHM; +#endif /*USE_SCRYPT*/ + break; + + default: + ec = GPG_ERR_UNKNOWN_ALGORITHM; + break; + } + + leave: + return ec; +} diff --git a/plugins/MirOTR/Libgcrypt/cipher/mac-cmac.c b/plugins/MirOTR/Libgcrypt/cipher/mac-cmac.c new file mode 100644 index 0000000000..69a2f174db --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/mac-cmac.c @@ -0,0 +1,226 @@ +/* mac-cmac.c - CMAC glue for MAC API + * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "g10lib.h" +#include "cipher.h" +#include "./mac-internal.h" + + +static int +map_mac_algo_to_cipher (int mac_algo) +{ + switch (mac_algo) + { + default: + return GCRY_CIPHER_NONE; + case GCRY_MAC_CMAC_AES: + return GCRY_CIPHER_AES; + case GCRY_MAC_CMAC_3DES: + return GCRY_CIPHER_3DES; + case GCRY_MAC_CMAC_CAMELLIA: + return GCRY_CIPHER_CAMELLIA128; + case GCRY_MAC_CMAC_IDEA: + return GCRY_CIPHER_IDEA; + case GCRY_MAC_CMAC_CAST5: + return GCRY_CIPHER_CAST5; + case GCRY_MAC_CMAC_BLOWFISH: + return GCRY_CIPHER_BLOWFISH; + case GCRY_MAC_CMAC_TWOFISH: + return GCRY_CIPHER_TWOFISH; + case GCRY_MAC_CMAC_SERPENT: + return GCRY_CIPHER_SERPENT128; + case GCRY_MAC_CMAC_SEED: + return GCRY_CIPHER_SEED; + case GCRY_MAC_CMAC_RFC2268: + return GCRY_CIPHER_RFC2268_128; + case GCRY_MAC_CMAC_GOST28147: + return GCRY_CIPHER_GOST28147; + } +} + + +static gcry_err_code_t +cmac_open (gcry_mac_hd_t h) +{ + gcry_err_code_t err; + gcry_cipher_hd_t hd; + int secure = (h->magic == CTX_MAGIC_SECURE); + int cipher_algo; + unsigned int flags; + + cipher_algo = map_mac_algo_to_cipher (h->spec->algo); + flags = (secure ? GCRY_CIPHER_SECURE : 0); + + err = _gcry_cipher_open_internal (&hd, cipher_algo, GCRY_CIPHER_MODE_CMAC, + flags); + if (err) + return err; + + h->u.cmac.cipher_algo = cipher_algo; + h->u.cmac.ctx = hd; + h->u.cmac.blklen = _gcry_cipher_get_algo_blklen (cipher_algo); + return 0; +} + + +static void +cmac_close (gcry_mac_hd_t h) +{ + _gcry_cipher_close (h->u.cmac.ctx); + h->u.cmac.ctx = NULL; +} + + +static gcry_err_code_t +cmac_setkey (gcry_mac_hd_t h, const unsigned char *key, size_t keylen) +{ + return _gcry_cipher_setkey (h->u.cmac.ctx, key, keylen); +} + + +static gcry_err_code_t +cmac_reset (gcry_mac_hd_t h) +{ + return _gcry_cipher_reset (h->u.cmac.ctx); +} + + +static gcry_err_code_t +cmac_write (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) +{ + return _gcry_cipher_cmac_authenticate (h->u.cmac.ctx, buf, buflen); +} + + +static gcry_err_code_t +cmac_read (gcry_mac_hd_t h, unsigned char *outbuf, size_t * outlen) +{ + if (*outlen > h->u.cmac.blklen) + *outlen = h->u.cmac.blklen; + return _gcry_cipher_cmac_get_tag (h->u.cmac.ctx, outbuf, *outlen); +} + + +static gcry_err_code_t +cmac_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) +{ + return _gcry_cipher_cmac_check_tag (h->u.cmac.ctx, buf, buflen); +} + + +static unsigned int +cmac_get_maclen (int algo) +{ + return _gcry_cipher_get_algo_blklen (map_mac_algo_to_cipher (algo)); +} + + +static unsigned int +cmac_get_keylen (int algo) +{ + return _gcry_cipher_get_algo_keylen (map_mac_algo_to_cipher (algo)); +} + + +static gcry_mac_spec_ops_t cmac_ops = { + cmac_open, + cmac_close, + cmac_setkey, + NULL, + cmac_reset, + cmac_write, + cmac_read, + cmac_verify, + cmac_get_maclen, + cmac_get_keylen +}; + + +#if USE_BLOWFISH +gcry_mac_spec_t _gcry_mac_type_spec_cmac_blowfish = { + GCRY_MAC_CMAC_BLOWFISH, {0, 0}, "CMAC_BLOWFISH", + &cmac_ops +}; +#endif +#if USE_DES +gcry_mac_spec_t _gcry_mac_type_spec_cmac_tripledes = { + GCRY_MAC_CMAC_3DES, {0, 1}, "CMAC_3DES", + &cmac_ops +}; +#endif +#if USE_CAST5 +gcry_mac_spec_t _gcry_mac_type_spec_cmac_cast5 = { + GCRY_MAC_CMAC_CAST5, {0, 0}, "CMAC_CAST5", + &cmac_ops +}; +#endif +#if USE_AES +gcry_mac_spec_t _gcry_mac_type_spec_cmac_aes = { + GCRY_MAC_CMAC_AES, {0, 1}, "CMAC_AES", + &cmac_ops +}; +#endif +#if USE_TWOFISH +gcry_mac_spec_t _gcry_mac_type_spec_cmac_twofish = { + GCRY_MAC_CMAC_TWOFISH, {0, 0}, "CMAC_TWOFISH", + &cmac_ops +}; +#endif +#if USE_SERPENT +gcry_mac_spec_t _gcry_mac_type_spec_cmac_serpent = { + GCRY_MAC_CMAC_SERPENT, {0, 0}, "CMAC_SERPENT", + &cmac_ops +}; +#endif +#if USE_RFC2268 +gcry_mac_spec_t _gcry_mac_type_spec_cmac_rfc2268 = { + GCRY_MAC_CMAC_RFC2268, {0, 0}, "CMAC_RFC2268", + &cmac_ops +}; +#endif +#if USE_SEED +gcry_mac_spec_t _gcry_mac_type_spec_cmac_seed = { + GCRY_MAC_CMAC_SEED, {0, 0}, "CMAC_SEED", + &cmac_ops +}; +#endif +#if USE_CAMELLIA +gcry_mac_spec_t _gcry_mac_type_spec_cmac_camellia = { + GCRY_MAC_CMAC_CAMELLIA, {0, 0}, "CMAC_CAMELLIA", + &cmac_ops +}; +#endif +#ifdef USE_IDEA +gcry_mac_spec_t _gcry_mac_type_spec_cmac_idea = { + GCRY_MAC_CMAC_IDEA, {0, 0}, "CMAC_IDEA", + &cmac_ops +}; +#endif +#if USE_GOST28147 +gcry_mac_spec_t _gcry_mac_type_spec_cmac_gost28147 = { + GCRY_MAC_CMAC_GOST28147, {0, 0}, "CMAC_GOST28147", + &cmac_ops +}; +#endif diff --git a/plugins/MirOTR/Libgcrypt/cipher/mac-gmac.c b/plugins/MirOTR/Libgcrypt/cipher/mac-gmac.c new file mode 100644 index 0000000000..18d56b5caa --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/mac-gmac.c @@ -0,0 +1,185 @@ +/* mac-gmac.c - GMAC glue for MAC API + * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "g10lib.h" +#include "cipher.h" +#include "./mac-internal.h" + + +static int +map_mac_algo_to_cipher (int mac_algo) +{ + switch (mac_algo) + { + default: + return GCRY_CIPHER_NONE; + case GCRY_MAC_GMAC_AES: + return GCRY_CIPHER_AES; + case GCRY_MAC_GMAC_CAMELLIA: + return GCRY_CIPHER_CAMELLIA128; + case GCRY_MAC_GMAC_TWOFISH: + return GCRY_CIPHER_TWOFISH; + case GCRY_MAC_GMAC_SERPENT: + return GCRY_CIPHER_SERPENT128; + case GCRY_MAC_GMAC_SEED: + return GCRY_CIPHER_SEED; + } +} + + +static gcry_err_code_t +gmac_open (gcry_mac_hd_t h) +{ + gcry_err_code_t err; + gcry_cipher_hd_t hd; + int secure = (h->magic == CTX_MAGIC_SECURE); + int cipher_algo; + unsigned int flags; + + cipher_algo = map_mac_algo_to_cipher (h->spec->algo); + flags = (secure ? GCRY_CIPHER_SECURE : 0); + + err = _gcry_cipher_open_internal (&hd, cipher_algo, GCRY_CIPHER_MODE_GCM, + flags); + if (err) + return err; + + h->u.gmac.cipher_algo = cipher_algo; + h->u.gmac.ctx = hd; + return 0; +} + + +static void +gmac_close (gcry_mac_hd_t h) +{ + _gcry_cipher_close (h->u.gmac.ctx); + h->u.gmac.ctx = NULL; +} + + +static gcry_err_code_t +gmac_setkey (gcry_mac_hd_t h, const unsigned char *key, size_t keylen) +{ + return _gcry_cipher_setkey (h->u.gmac.ctx, key, keylen); +} + + +static gcry_err_code_t +gmac_setiv (gcry_mac_hd_t h, const unsigned char *iv, size_t ivlen) +{ + return _gcry_cipher_setiv (h->u.gmac.ctx, iv, ivlen); +} + + +static gcry_err_code_t +gmac_reset (gcry_mac_hd_t h) +{ + return _gcry_cipher_reset (h->u.gmac.ctx); +} + + +static gcry_err_code_t +gmac_write (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) +{ + return _gcry_cipher_authenticate (h->u.gmac.ctx, buf, buflen); +} + + +static gcry_err_code_t +gmac_read (gcry_mac_hd_t h, unsigned char *outbuf, size_t * outlen) +{ + if (*outlen > GCRY_GCM_BLOCK_LEN) + *outlen = GCRY_GCM_BLOCK_LEN; + return _gcry_cipher_gettag (h->u.gmac.ctx, outbuf, *outlen); +} + + +static gcry_err_code_t +gmac_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) +{ + return _gcry_cipher_checktag (h->u.gmac.ctx, buf, buflen); +} + + +static unsigned int +gmac_get_maclen (int algo) +{ + (void)algo; + return GCRY_GCM_BLOCK_LEN; +} + + +static unsigned int +gmac_get_keylen (int algo) +{ + return _gcry_cipher_get_algo_keylen (map_mac_algo_to_cipher (algo)); +} + + +static gcry_mac_spec_ops_t gmac_ops = { + gmac_open, + gmac_close, + gmac_setkey, + gmac_setiv, + gmac_reset, + gmac_write, + gmac_read, + gmac_verify, + gmac_get_maclen, + gmac_get_keylen +}; + + +#if USE_AES +gcry_mac_spec_t _gcry_mac_type_spec_gmac_aes = { + GCRY_MAC_GMAC_AES, {0, 1}, "GMAC_AES", + &gmac_ops +}; +#endif +#if USE_TWOFISH +gcry_mac_spec_t _gcry_mac_type_spec_gmac_twofish = { + GCRY_MAC_GMAC_TWOFISH, {0, 0}, "GMAC_TWOFISH", + &gmac_ops +}; +#endif +#if USE_SERPENT +gcry_mac_spec_t _gcry_mac_type_spec_gmac_serpent = { + GCRY_MAC_GMAC_SERPENT, {0, 0}, "GMAC_SERPENT", + &gmac_ops +}; +#endif +#if USE_SEED +gcry_mac_spec_t _gcry_mac_type_spec_gmac_seed = { + GCRY_MAC_GMAC_SEED, {0, 0}, "GMAC_SEED", + &gmac_ops +}; +#endif +#if USE_CAMELLIA +gcry_mac_spec_t _gcry_mac_type_spec_gmac_camellia = { + GCRY_MAC_GMAC_CAMELLIA, {0, 0}, "GMAC_CAMELLIA", + &gmac_ops +}; +#endif diff --git a/plugins/MirOTR/Libgcrypt/cipher/mac-hmac.c b/plugins/MirOTR/Libgcrypt/cipher/mac-hmac.c new file mode 100644 index 0000000000..15c613d53a --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/mac-hmac.c @@ -0,0 +1,272 @@ +/* mac-hmac.c - HMAC glue for MAC API + * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "g10lib.h" +#include "./mac-internal.h" +#include "bufhelp.h" + + +static int +map_mac_algo_to_md (int mac_algo) +{ + switch (mac_algo) + { + default: + return GCRY_MD_NONE; + case GCRY_MAC_HMAC_MD4: + return GCRY_MD_MD4; + case GCRY_MAC_HMAC_MD5: + return GCRY_MD_MD5; + case GCRY_MAC_HMAC_SHA1: + return GCRY_MD_SHA1; + case GCRY_MAC_HMAC_SHA224: + return GCRY_MD_SHA224; + case GCRY_MAC_HMAC_SHA256: + return GCRY_MD_SHA256; + case GCRY_MAC_HMAC_SHA384: + return GCRY_MD_SHA384; + case GCRY_MAC_HMAC_SHA512: + return GCRY_MD_SHA512; + case GCRY_MAC_HMAC_RMD160: + return GCRY_MD_RMD160; + case GCRY_MAC_HMAC_TIGER1: + return GCRY_MD_TIGER1; + case GCRY_MAC_HMAC_WHIRLPOOL: + return GCRY_MD_WHIRLPOOL; + case GCRY_MAC_HMAC_GOSTR3411_94: + return GCRY_MD_GOSTR3411_94; + case GCRY_MAC_HMAC_STRIBOG256: + return GCRY_MD_STRIBOG256; + case GCRY_MAC_HMAC_STRIBOG512: + return GCRY_MD_STRIBOG512; + } +} + + +static gcry_err_code_t +hmac_open (gcry_mac_hd_t h) +{ + gcry_err_code_t err; + gcry_md_hd_t hd; + int secure = (h->magic == CTX_MAGIC_SECURE); + unsigned int flags; + int md_algo; + + md_algo = map_mac_algo_to_md (h->spec->algo); + + flags = GCRY_MD_FLAG_HMAC; + flags |= (secure ? GCRY_MD_FLAG_SECURE : 0); + + err = _gcry_md_open (&hd, md_algo, flags); + if (err) + return err; + + h->u.hmac.md_algo = md_algo; + h->u.hmac.md_ctx = hd; + return 0; +} + + +static void +hmac_close (gcry_mac_hd_t h) +{ + _gcry_md_close (h->u.hmac.md_ctx); + h->u.hmac.md_ctx = NULL; +} + + +static gcry_err_code_t +hmac_setkey (gcry_mac_hd_t h, const unsigned char *key, size_t keylen) +{ + return _gcry_md_setkey (h->u.hmac.md_ctx, key, keylen); +} + + +static gcry_err_code_t +hmac_reset (gcry_mac_hd_t h) +{ + _gcry_md_reset (h->u.hmac.md_ctx); + return 0; +} + + +static gcry_err_code_t +hmac_write (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) +{ + _gcry_md_write (h->u.hmac.md_ctx, buf, buflen); + return 0; +} + + +static gcry_err_code_t +hmac_read (gcry_mac_hd_t h, unsigned char *outbuf, size_t * outlen) +{ + unsigned int dlen; + const unsigned char *digest; + + dlen = _gcry_md_get_algo_dlen (h->u.hmac.md_algo); + digest = _gcry_md_read (h->u.hmac.md_ctx, h->u.hmac.md_algo); + + if (*outlen <= dlen) + buf_cpy (outbuf, digest, *outlen); + else + { + buf_cpy (outbuf, digest, dlen); + *outlen = dlen; + } + + return 0; +} + + +static gcry_err_code_t +hmac_verify (gcry_mac_hd_t h, const unsigned char *buf, size_t buflen) +{ + unsigned int dlen; + const unsigned char *digest; + + dlen = _gcry_md_get_algo_dlen (h->u.hmac.md_algo); + digest = _gcry_md_read (h->u.hmac.md_ctx, h->u.hmac.md_algo); + + if (buflen > dlen) + return GPG_ERR_INV_LENGTH; + + return buf_eq_const (buf, digest, buflen) ? 0 : GPG_ERR_CHECKSUM; +} + + +static unsigned int +hmac_get_maclen (int algo) +{ + return _gcry_md_get_algo_dlen (map_mac_algo_to_md (algo)); +} + + +static unsigned int +hmac_get_keylen (int algo) +{ + /* Return blocksize for default key length. */ + switch (algo) + { + case GCRY_MAC_HMAC_SHA384: + case GCRY_MAC_HMAC_SHA512: + return 128; + case GCRY_MAC_HMAC_GOSTR3411_94: + return 32; + default: + return 64; + } +} + + +static const gcry_mac_spec_ops_t hmac_ops = { + hmac_open, + hmac_close, + hmac_setkey, + NULL, + hmac_reset, + hmac_write, + hmac_read, + hmac_verify, + hmac_get_maclen, + hmac_get_keylen +}; + + +#if USE_SHA1 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha1 = { + GCRY_MAC_HMAC_SHA1, {0, 1}, "HMAC_SHA1", + &hmac_ops +}; +#endif +#if USE_SHA256 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha256 = { + GCRY_MAC_HMAC_SHA256, {0, 1}, "HMAC_SHA256", + &hmac_ops +}; + +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha224 = { + GCRY_MAC_HMAC_SHA224, {0, 1}, "HMAC_SHA224", + &hmac_ops +}; +#endif +#if USE_SHA512 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha512 = { + GCRY_MAC_HMAC_SHA512, {0, 1}, "HMAC_SHA512", + &hmac_ops +}; + +gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha384 = { + GCRY_MAC_HMAC_SHA384, {0, 1}, "HMAC_SHA384", + &hmac_ops +}; +#endif +#ifdef USE_GOST_R_3411_94 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_gost3411_94 = { + GCRY_MAC_HMAC_GOSTR3411_94, {0, 0}, "HMAC_GOSTR3411_94", + &hmac_ops +}; +#endif +#ifdef USE_GOST_R_3411_12 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_stribog256 = { + GCRY_MAC_HMAC_STRIBOG256, {0, 0}, "HMAC_STRIBOG256", + &hmac_ops +}; + +gcry_mac_spec_t _gcry_mac_type_spec_hmac_stribog512 = { + GCRY_MAC_HMAC_STRIBOG512, {0, 0}, "HMAC_STRIBOG512", + &hmac_ops +}; +#endif +#if USE_WHIRLPOOL +gcry_mac_spec_t _gcry_mac_type_spec_hmac_whirlpool = { + GCRY_MAC_HMAC_WHIRLPOOL, {0, 0}, "HMAC_WHIRLPOOL", + &hmac_ops +}; +#endif +#if USE_RMD160 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_rmd160 = { + GCRY_MAC_HMAC_RMD160, {0, 0}, "HMAC_RIPEMD160", + &hmac_ops +}; +#endif +#if USE_TIGER +gcry_mac_spec_t _gcry_mac_type_spec_hmac_tiger1 = { + GCRY_MAC_HMAC_TIGER1, {0, 0}, "HMAC_TIGER", + &hmac_ops +}; +#endif +#if USE_MD5 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_md5 = { + GCRY_MAC_HMAC_MD5, {0, 0}, "HMAC_MD5", + &hmac_ops +}; +#endif +#if USE_MD4 +gcry_mac_spec_t _gcry_mac_type_spec_hmac_md4 = { + GCRY_MAC_HMAC_MD4, {0, 0}, "HMAC_MD4", + &hmac_ops +}; +#endif diff --git a/plugins/MirOTR/Libgcrypt/cipher/mac-internal.h b/plugins/MirOTR/Libgcrypt/cipher/mac-internal.h new file mode 100644 index 0000000000..6fc304baba --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/mac-internal.h @@ -0,0 +1,204 @@ +/* mac-internal.h - Internal defs for mac.c + * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* The data object used to hold a handle to an encryption object. */ +struct gcry_mac_handle; + + +/* + * + * Message authentication code related definitions. + * + */ + + +/* Magic values for the context structure. */ +#define CTX_MAGIC_NORMAL 0x59d9b8af +#define CTX_MAGIC_SECURE 0x12c27cd0 + + +/* MAC module functions. */ +typedef gcry_err_code_t (*gcry_mac_open_func_t)(gcry_mac_hd_t h); +typedef void (*gcry_mac_close_func_t)(gcry_mac_hd_t h); +typedef gcry_err_code_t (*gcry_mac_setkey_func_t)(gcry_mac_hd_t h, + const unsigned char *key, + size_t keylen); +typedef gcry_err_code_t (*gcry_mac_setiv_func_t)(gcry_mac_hd_t h, + const unsigned char *iv, + size_t ivlen); +typedef gcry_err_code_t (*gcry_mac_reset_func_t)(gcry_mac_hd_t h); +typedef gcry_err_code_t (*gcry_mac_write_func_t)(gcry_mac_hd_t h, + const unsigned char *inbuf, + size_t inlen); +typedef gcry_err_code_t (*gcry_mac_read_func_t)(gcry_mac_hd_t h, + unsigned char *outbuf, + size_t *outlen); +typedef gcry_err_code_t (*gcry_mac_verify_func_t)(gcry_mac_hd_t h, + const unsigned char *inbuf, + size_t inlen); +typedef unsigned int (*gcry_mac_get_maclen_func_t)(int algo); +typedef unsigned int (*gcry_mac_get_keylen_func_t)(int algo); + + +typedef struct gcry_mac_spec_ops +{ + gcry_mac_open_func_t open; + gcry_mac_close_func_t close; + gcry_mac_setkey_func_t setkey; + gcry_mac_setiv_func_t setiv; + gcry_mac_reset_func_t reset; + gcry_mac_write_func_t write; + gcry_mac_read_func_t read; + gcry_mac_verify_func_t verify; + gcry_mac_get_maclen_func_t get_maclen; + gcry_mac_get_keylen_func_t get_keylen; +} gcry_mac_spec_ops_t; + + +/* Module specification structure for message authentication codes. */ +typedef struct gcry_mac_spec +{ + int algo; + struct { + unsigned int disabled:1; + unsigned int fips:1; + } flags; + const char *name; + const gcry_mac_spec_ops_t *ops; +} gcry_mac_spec_t; + + + +/* The handle structure. */ +struct gcry_mac_handle +{ + int magic; + int algo; + const gcry_mac_spec_t *spec; + gcry_ctx_t gcry_ctx; + union { + struct { + gcry_md_hd_t md_ctx; + int md_algo; + } hmac; + struct { + gcry_cipher_hd_t ctx; + int cipher_algo; + unsigned int blklen; + } cmac; + struct { + gcry_cipher_hd_t ctx; + int cipher_algo; + } gmac; + } u; +}; + + +/* + * The HMAC algorithm specifications (mac-hmac.c). + */ +#if USE_SHA1 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha1; +#endif +#if USE_SHA256 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha256; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha224; +#endif +#if USE_SHA512 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha512; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_sha384; +#endif +#ifdef USE_GOST_R_3411_94 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_gost3411_94; +#endif +#ifdef USE_GOST_R_3411_12 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_stribog256; +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_stribog512; +#endif +#if USE_WHIRLPOOL +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_whirlpool; +#endif +#if USE_RMD160 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_rmd160; +#endif +#if USE_TIGER +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_tiger1; +#endif +#if USE_MD5 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_md5; +#endif +#if USE_MD4 +extern gcry_mac_spec_t _gcry_mac_type_spec_hmac_md4; +#endif + +/* + * The CMAC algorithm specifications (mac-cmac.c). + */ +#if USE_BLOWFISH +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_blowfish; +#endif +#if USE_DES +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_tripledes; +#endif +#if USE_CAST5 +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_cast5; +#endif +#if USE_AES +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_aes; +#endif +#if USE_TWOFISH +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_twofish; +#endif +#if USE_SERPENT +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_serpent; +#endif +#if USE_RFC2268 +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_rfc2268; +#endif +#if USE_SEED +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_seed; +#endif +#if USE_CAMELLIA +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_camellia; +#endif +#ifdef USE_IDEA +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_idea; +#endif +#if USE_GOST28147 +extern gcry_mac_spec_t _gcry_mac_type_spec_cmac_gost28147; +#endif + +/* + * The GMAC algorithm specifications (mac-gmac.c). + */ +#if USE_AES +extern gcry_mac_spec_t _gcry_mac_type_spec_gmac_aes; +#endif +#if USE_TWOFISH +extern gcry_mac_spec_t _gcry_mac_type_spec_gmac_twofish; +#endif +#if USE_SERPENT +extern gcry_mac_spec_t _gcry_mac_type_spec_gmac_serpent; +#endif +#if USE_SEED +extern gcry_mac_spec_t _gcry_mac_type_spec_gmac_seed; +#endif +#if USE_CAMELLIA +extern gcry_mac_spec_t _gcry_mac_type_spec_gmac_camellia; +#endif diff --git a/plugins/MirOTR/Libgcrypt/cipher/mac.c b/plugins/MirOTR/Libgcrypt/cipher/mac.c new file mode 100644 index 0000000000..d87ac13761 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/mac.c @@ -0,0 +1,466 @@ +/* mac.c - message authentication code dispatcher + * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "g10lib.h" +#include "mac-internal.h" + + +/* This is the list of the digest implementations included in + libgcrypt. */ +static gcry_mac_spec_t *mac_list[] = { +#if USE_SHA1 + &_gcry_mac_type_spec_hmac_sha1, +#endif +#if USE_SHA256 + &_gcry_mac_type_spec_hmac_sha256, + &_gcry_mac_type_spec_hmac_sha224, +#endif +#if USE_SHA512 + &_gcry_mac_type_spec_hmac_sha512, + &_gcry_mac_type_spec_hmac_sha384, +#endif +#ifdef USE_GOST_R_3411_94 + &_gcry_mac_type_spec_hmac_gost3411_94, +#endif +#ifdef USE_GOST_R_3411_12 + &_gcry_mac_type_spec_hmac_stribog256, + &_gcry_mac_type_spec_hmac_stribog512, +#endif +#if USE_WHIRLPOOL + &_gcry_mac_type_spec_hmac_whirlpool, +#endif +#if USE_RMD160 + &_gcry_mac_type_spec_hmac_rmd160, +#endif +#if USE_TIGER + &_gcry_mac_type_spec_hmac_tiger1, +#endif +#if USE_MD5 + &_gcry_mac_type_spec_hmac_md5, +#endif +#if USE_MD4 + &_gcry_mac_type_spec_hmac_md4, +#endif +#if USE_BLOWFISH + &_gcry_mac_type_spec_cmac_blowfish, +#endif +#if USE_DES + &_gcry_mac_type_spec_cmac_tripledes, +#endif +#if USE_CAST5 + &_gcry_mac_type_spec_cmac_cast5, +#endif +#if USE_AES + &_gcry_mac_type_spec_cmac_aes, + &_gcry_mac_type_spec_gmac_aes, +#endif +#if USE_TWOFISH + &_gcry_mac_type_spec_cmac_twofish, + &_gcry_mac_type_spec_gmac_twofish, +#endif +#if USE_SERPENT + &_gcry_mac_type_spec_cmac_serpent, + &_gcry_mac_type_spec_gmac_serpent, +#endif +#if USE_RFC2268 + &_gcry_mac_type_spec_cmac_rfc2268, +#endif +#if USE_SEED + &_gcry_mac_type_spec_cmac_seed, + &_gcry_mac_type_spec_gmac_seed, +#endif +#if USE_CAMELLIA + &_gcry_mac_type_spec_cmac_camellia, + &_gcry_mac_type_spec_gmac_camellia, +#endif +#ifdef USE_IDEA + &_gcry_mac_type_spec_cmac_idea, +#endif +#if USE_GOST28147 + &_gcry_mac_type_spec_cmac_gost28147, +#endif + NULL, +}; + + + +/* Return the spec structure for the MAC algorithm ALGO. For an + unknown algorithm NULL is returned. */ +static gcry_mac_spec_t * +spec_from_algo (int algo) +{ + gcry_mac_spec_t *spec; + int idx; + + for (idx = 0; (spec = mac_list[idx]); idx++) + if (algo == spec->algo) + return spec; + return NULL; +} + + +/* Lookup a mac's spec by its name. */ +static gcry_mac_spec_t * +spec_from_name (const char *name) +{ + gcry_mac_spec_t *spec; + int idx; + + for (idx = 0; (spec = mac_list[idx]); idx++) + if (!stricmp (name, spec->name)) + return spec; + + return NULL; +} + + +/**************** + * Map a string to the mac algo + */ +int +_gcry_mac_map_name (const char *string) +{ + gcry_mac_spec_t *spec; + + if (!string) + return 0; + + /* Not found, search a matching mac name. */ + spec = spec_from_name (string); + if (spec) + return spec->algo; + + return 0; +} + + +/**************** + * This function simply returns the name of the algorithm or some constant + * string when there is no algo. It will never return NULL. + * Use the macro gcry_mac_test_algo() to check whether the algorithm + * is valid. + */ +const char * +_gcry_mac_algo_name (int algorithm) +{ + gcry_mac_spec_t *spec; + + spec = spec_from_algo (algorithm); + return spec ? spec->name : "?"; +} + + +static gcry_err_code_t +check_mac_algo (int algorithm) +{ + gcry_mac_spec_t *spec; + + spec = spec_from_algo (algorithm); + if (spec && !spec->flags.disabled) + return 0; + + return GPG_ERR_MAC_ALGO; +} + + +/**************** + * Open a message digest handle for use with algorithm ALGO. + */ +static gcry_err_code_t +mac_open (gcry_mac_hd_t * hd, int algo, int secure, gcry_ctx_t ctx) +{ + gcry_mac_spec_t *spec; + gcry_err_code_t err; + gcry_mac_hd_t h; + + spec = spec_from_algo (algo); + if (!spec) + return GPG_ERR_MAC_ALGO; + else if (spec->flags.disabled) + return GPG_ERR_MAC_ALGO; + else if (!spec->ops) + return GPG_ERR_MAC_ALGO; + else if (!spec->ops->open || !spec->ops->write || !spec->ops->setkey || + !spec->ops->read || !spec->ops->verify || !spec->ops->reset) + return GPG_ERR_MAC_ALGO; + + if (secure) + h = xtrycalloc_secure (1, sizeof (*h)); + else + h = xtrycalloc (1, sizeof (*h)); + + if (!h) + return gpg_err_code_from_syserror (); + + h->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL; + h->spec = spec; + h->algo = algo; + h->gcry_ctx = ctx; + + err = h->spec->ops->open (h); + if (err) + xfree (h); + else + *hd = h; + + return err; +} + + +static gcry_error_t +mac_reset (gcry_mac_hd_t hd) +{ + if (hd->spec->ops->reset) + return hd->spec->ops->reset (hd); + + return 0; +} + + +static void +mac_close (gcry_mac_hd_t hd) +{ + if (hd->spec->ops->close) + hd->spec->ops->close (hd); + + wipememory (hd, sizeof (*hd)); + + xfree (hd); +} + + +static gcry_error_t +mac_setkey (gcry_mac_hd_t hd, const void *key, size_t keylen) +{ + if (!hd->spec->ops->setkey) + return GPG_ERR_INV_ARG; + if (keylen > 0 && !key) + return GPG_ERR_INV_ARG; + + return hd->spec->ops->setkey (hd, key, keylen); +} + + +static gcry_error_t +mac_setiv (gcry_mac_hd_t hd, const void *iv, size_t ivlen) +{ + if (!hd->spec->ops->setiv) + return GPG_ERR_INV_ARG; + if (ivlen > 0 && !iv) + return GPG_ERR_INV_ARG; + + return hd->spec->ops->setiv (hd, iv, ivlen); +} + + +static gcry_error_t +mac_write (gcry_mac_hd_t hd, const void *inbuf, size_t inlen) +{ + if (!hd->spec->ops->write) + return GPG_ERR_INV_ARG; + if (inlen > 0 && !inbuf) + return GPG_ERR_INV_ARG; + + return hd->spec->ops->write (hd, inbuf, inlen); +} + + +static gcry_error_t +mac_read (gcry_mac_hd_t hd, void *outbuf, size_t * outlen) +{ + if (!outbuf || !outlen || *outlen == 0 || !hd->spec->ops->read) + return GPG_ERR_INV_ARG; + + return hd->spec->ops->read (hd, outbuf, outlen); +} + + +static gcry_error_t +mac_verify (gcry_mac_hd_t hd, const void *buf, size_t buflen) +{ + if (!buf || buflen == 0 || !hd->spec->ops->verify) + return GPG_ERR_INV_ARG; + + return hd->spec->ops->verify (hd, buf, buflen); +} + + +/* Create a MAC object for algorithm ALGO. FLAGS may be + given as an bitwise OR of the gcry_mac_flags values. + H is guaranteed to be a valid handle or NULL on error. */ +gpg_err_code_t +_gcry_mac_open (gcry_mac_hd_t * h, int algo, unsigned int flags, + gcry_ctx_t ctx) +{ + gcry_err_code_t rc; + gcry_mac_hd_t hd = NULL; + + if ((flags & ~GCRY_MAC_FLAG_SECURE)) + rc = GPG_ERR_INV_ARG; + else + rc = mac_open (&hd, algo, !!(flags & GCRY_MAC_FLAG_SECURE), ctx); + + *h = rc ? NULL : hd; + return rc; +} + + +void +_gcry_mac_close (gcry_mac_hd_t hd) +{ + if (hd) + mac_close (hd); +} + + +gcry_err_code_t +_gcry_mac_setkey (gcry_mac_hd_t hd, const void *key, size_t keylen) +{ + return mac_setkey (hd, key, keylen); +} + + +gcry_err_code_t +_gcry_mac_setiv (gcry_mac_hd_t hd, const void *iv, size_t ivlen) +{ + return mac_setiv (hd, iv, ivlen); +} + + +gcry_err_code_t +_gcry_mac_write (gcry_mac_hd_t hd, const void *inbuf, size_t inlen) +{ + return mac_write (hd, inbuf, inlen); +} + + +gcry_err_code_t +_gcry_mac_read (gcry_mac_hd_t hd, void *outbuf, size_t * outlen) +{ + return mac_read (hd, outbuf, outlen); +} + + +gcry_err_code_t +_gcry_mac_verify (gcry_mac_hd_t hd, const void *buf, size_t buflen) +{ + return mac_verify (hd, buf, buflen); +} + + +unsigned int +_gcry_mac_get_algo_maclen (int algo) +{ + gcry_mac_spec_t *spec; + + spec = spec_from_algo (algo); + if (!spec || !spec->ops || !spec->ops->get_maclen) + return 0; + + return spec->ops->get_maclen (algo); +} + + +unsigned int +_gcry_mac_get_algo_keylen (int algo) +{ + gcry_mac_spec_t *spec; + + spec = spec_from_algo (algo); + if (!spec || !spec->ops || !spec->ops->get_keylen) + return 0; + + return spec->ops->get_keylen (algo); +} + + +gcry_err_code_t +_gcry_mac_ctl (gcry_mac_hd_t hd, int cmd, void *buffer, size_t buflen) +{ + gcry_err_code_t rc; + + /* Currently not used. */ + (void) hd; + (void) buffer; + (void) buflen; + + switch (cmd) + { + case GCRYCTL_RESET: + rc = mac_reset (hd); + break; + default: + rc = GPG_ERR_INV_OP; + } + return rc; +} + + +/* Return information about the given MAC algorithm ALGO. + + GCRYCTL_TEST_ALGO: + Returns 0 if the specified algorithm ALGO is available for use. + BUFFER and NBYTES must be zero. + + Note: Because this function is in most cases used to return an + integer value, we can make it easier for the caller to just look at + the return value. The caller will in all cases consult the value + and thereby detecting whether a error occurred or not (i.e. while + checking the block size) + */ +gcry_err_code_t +_gcry_mac_algo_info (int algo, int what, void *buffer, size_t * nbytes) +{ + gcry_err_code_t rc = 0; + unsigned int ui; + + switch (what) + { + case GCRYCTL_GET_KEYLEN: + if (buffer || (!nbytes)) + rc = GPG_ERR_INV_ARG; + else + { + ui = _gcry_mac_get_algo_keylen (algo); + if (ui > 0) + *nbytes = (size_t) ui; + else + /* The only reason for an error is an invalid algo. */ + rc = GPG_ERR_MAC_ALGO; + } + break; + case GCRYCTL_TEST_ALGO: + if (buffer || nbytes) + rc = GPG_ERR_INV_ARG; + else + rc = check_mac_algo (algo); + break; + + default: + rc = GPG_ERR_INV_OP; + } + + return rc; +} diff --git a/plugins/MirOTR/Libgcrypt/cipher/md.c b/plugins/MirOTR/Libgcrypt/cipher/md.c index da07783d92..008ef5b230 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/md.c +++ b/plugins/MirOTR/Libgcrypt/cipher/md.c @@ -1,6 +1,7 @@ /* md.c - message digest dispatcher * Copyright (C) 1998, 1999, 2002, 2003, 2006, * 2008 Free Software Foundation, Inc. + * Copyright (C) 2013, 2014 g10 Code GmbH * * This file is part of Libgcrypt. * @@ -30,103 +31,75 @@ #include "rmd.h" -/* A dummy extraspec so that we do not need to tests the extraspec - field from the module specification against NULL and instead - directly test the respective fields of extraspecs. */ -static md_extra_spec_t dummy_extra_spec; - /* This is the list of the digest implementations included in libgcrypt. */ -static struct digest_table_entry -{ - gcry_md_spec_t *digest; - md_extra_spec_t *extraspec; - unsigned int algorithm; - int fips_allowed; -} digest_table[] = +static gcry_md_spec_t *digest_list[] = { -#if USE_CRC - /* We allow the CRC algorithms even in FIPS mode because they are - actually no cryptographic primitives. */ - { &_gcry_digest_spec_crc32, - &dummy_extra_spec, GCRY_MD_CRC32, 1 }, - { &_gcry_digest_spec_crc32_rfc1510, - &dummy_extra_spec, GCRY_MD_CRC32_RFC1510, 1 }, - { &_gcry_digest_spec_crc24_rfc2440, - &dummy_extra_spec, GCRY_MD_CRC24_RFC2440, 1 }, -#endif -#if USE_MD4 - { &_gcry_digest_spec_md4, - &dummy_extra_spec, GCRY_MD_MD4 }, -#endif -#if USE_MD5 - { &_gcry_digest_spec_md5, - &dummy_extra_spec, GCRY_MD_MD5, 1 }, -#endif -#if USE_RMD160 - { &_gcry_digest_spec_rmd160, - &dummy_extra_spec, GCRY_MD_RMD160 }, +#if USE_CRC + &_gcry_digest_spec_crc32, + &_gcry_digest_spec_crc32_rfc1510, + &_gcry_digest_spec_crc24_rfc2440, #endif #if USE_SHA1 - { &_gcry_digest_spec_sha1, - &_gcry_digest_extraspec_sha1, GCRY_MD_SHA1, 1 }, + &_gcry_digest_spec_sha1, #endif #if USE_SHA256 - { &_gcry_digest_spec_sha256, - &_gcry_digest_extraspec_sha256, GCRY_MD_SHA256, 1 }, - { &_gcry_digest_spec_sha224, - &_gcry_digest_extraspec_sha224, GCRY_MD_SHA224, 1 }, + &_gcry_digest_spec_sha256, + &_gcry_digest_spec_sha224, #endif #if USE_SHA512 - { &_gcry_digest_spec_sha512, - &_gcry_digest_extraspec_sha512, GCRY_MD_SHA512, 1 }, - { &_gcry_digest_spec_sha384, - &_gcry_digest_extraspec_sha384, GCRY_MD_SHA384, 1 }, + &_gcry_digest_spec_sha512, + &_gcry_digest_spec_sha384, #endif -#if USE_TIGER - { &_gcry_digest_spec_tiger, - &dummy_extra_spec, GCRY_MD_TIGER }, - { &_gcry_digest_spec_tiger1, - &dummy_extra_spec, GCRY_MD_TIGER1 }, - { &_gcry_digest_spec_tiger2, - &dummy_extra_spec, GCRY_MD_TIGER2 }, +#ifdef USE_GOST_R_3411_94 + &_gcry_digest_spec_gost3411_94, +#endif +#ifdef USE_GOST_R_3411_12 + &_gcry_digest_spec_stribog_256, + &_gcry_digest_spec_stribog_512, #endif #if USE_WHIRLPOOL - { &_gcry_digest_spec_whirlpool, - &dummy_extra_spec, GCRY_MD_WHIRLPOOL }, + &_gcry_digest_spec_whirlpool, +#endif +#if USE_RMD160 + &_gcry_digest_spec_rmd160, +#endif +#if USE_TIGER + &_gcry_digest_spec_tiger, + &_gcry_digest_spec_tiger1, + &_gcry_digest_spec_tiger2, +#endif +#if USE_MD5 + &_gcry_digest_spec_md5, #endif - { NULL }, +#if USE_MD4 + &_gcry_digest_spec_md4, +#endif + NULL }; -/* List of registered digests. */ -static gcry_module_t digests_registered; - -/* This is the lock protecting DIGESTS_REGISTERED. */ -static ath_mutex_t digests_registered_lock = ATH_MUTEX_INITIALIZER; - -/* Flag to check wether the default ciphers have already been - registered. */ -static int default_digests_registered; typedef struct gcry_md_list { - gcry_md_spec_t *digest; - gcry_module_t module; + gcry_md_spec_t *spec; struct gcry_md_list *next; size_t actual_struct_size; /* Allocated size of this structure. */ PROPERLY_ALIGNED_TYPE context; } GcryDigestEntry; -/* this structure is put right after the gcry_md_hd_t buffer, so that +/* This structure is put right after the gcry_md_hd_t buffer, so that * only one memory block is needed. */ struct gcry_md_context { int magic; size_t actual_handle_size; /* Allocated size of this handle. */ - int secure; FILE *debug; - int finalized; + struct { + unsigned int secure: 1; + unsigned int finalized:1; + unsigned int bugemu1:1; + } flags; GcryDigestEntry *list; byte *macpads; int macpads_Bsize; /* Blocksize as used for the HMAC pads. */ @@ -136,301 +109,175 @@ struct gcry_md_context #define CTX_MAGIC_NORMAL 0x11071961 #define CTX_MAGIC_SECURE 0x16917011 -/* Convenient macro for registering the default digests. */ -#define REGISTER_DEFAULT_DIGESTS \ - do \ - { \ - ath_mutex_lock (&digests_registered_lock); \ - if (! default_digests_registered) \ - { \ - md_register_default (); \ - default_digests_registered = 1; \ - } \ - ath_mutex_unlock (&digests_registered_lock); \ - } \ - while (0) - - -static const char * digest_algo_to_string( int algo ); -static gcry_err_code_t check_digest_algo (int algo); -static gcry_err_code_t md_open (gcry_md_hd_t *h, int algo, - int secure, int hmac); static gcry_err_code_t md_enable (gcry_md_hd_t hd, int algo); -static gcry_err_code_t md_copy (gcry_md_hd_t a, gcry_md_hd_t *b); static void md_close (gcry_md_hd_t a); static void md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen); -static void md_final(gcry_md_hd_t a); static byte *md_read( gcry_md_hd_t a, int algo ); static int md_get_algo( gcry_md_hd_t a ); static int md_digest_length( int algo ); -static const byte *md_asn_oid( int algo, size_t *asnlen, size_t *mdlen ); static void md_start_debug ( gcry_md_hd_t a, const char *suffix ); static void md_stop_debug ( gcry_md_hd_t a ); + +static int +map_algo (int algo) +{ + return algo; +} -/* Internal function. Register all the ciphers included in - CIPHER_TABLE. Returns zero on success or an error code. */ -static void -md_register_default (void) +/* Return the spec structure for the hash algorithm ALGO. For an + unknown algorithm NULL is returned. */ +static gcry_md_spec_t * +spec_from_algo (int algo) { - gcry_err_code_t err = 0; - int i; - - for (i = 0; !err && digest_table[i].digest; i++) - { - if ( fips_mode ()) - { - if (!digest_table[i].fips_allowed) - continue; - if (digest_table[i].algorithm == GCRY_MD_MD5 - && _gcry_enforced_fips_mode () ) - continue; /* Do not register in enforced fips mode. */ - } + int idx; + gcry_md_spec_t *spec; - err = _gcry_module_add (&digests_registered, - digest_table[i].algorithm, - (void *) digest_table[i].digest, - (void *) digest_table[i].extraspec, - NULL); - } + algo = map_algo (algo); - if (err) - BUG (); + for (idx = 0; (spec = digest_list[idx]); idx++) + if (algo == spec->algo) + return spec; + return NULL; } -/* Internal callback function. */ -static int -gcry_md_lookup_func_name (void *spec, void *data) -{ - gcry_md_spec_t *digest = (gcry_md_spec_t *) spec; - char *name = (char *) data; - return (!_stricmp (digest->name, name)); -} - -/* Internal callback function. Used via _gcry_module_lookup. */ -static int -gcry_md_lookup_func_oid (void *spec, void *data) +/* Lookup a hash's spec by its name. */ +static gcry_md_spec_t * +spec_from_name (const char *name) { - gcry_md_spec_t *digest = (gcry_md_spec_t *) spec; - char *oid = (char *) data; - gcry_md_oid_spec_t *oid_specs = digest->oids; - int ret = 0, i; + gcry_md_spec_t *spec; + int idx; - if (oid_specs) + for (idx=0; (spec = digest_list[idx]); idx++) { - for (i = 0; oid_specs[i].oidstring && (! ret); i++) - if (!_stricmp (oid, oid_specs[i].oidstring)) - ret = 1; + if (!stricmp (name, spec->name)) + return spec; } - return ret; -} - -/* Internal function. Lookup a digest entry by it's name. */ -static gcry_module_t -gcry_md_lookup_name (const char *name) -{ - gcry_module_t digest; - - digest = _gcry_module_lookup (digests_registered, (void *) name, - gcry_md_lookup_func_name); - - return digest; + return NULL; } -/* Internal function. Lookup a cipher entry by it's oid. */ -static gcry_module_t -gcry_md_lookup_oid (const char *oid) -{ - gcry_module_t digest; - - digest = _gcry_module_lookup (digests_registered, (void *) oid, - gcry_md_lookup_func_oid); - - return digest; -} -/* Register a new digest module whose specification can be found in - DIGEST. On success, a new algorithm ID is stored in ALGORITHM_ID - and a pointer representhing this module is stored in MODULE. */ -gcry_error_t -_gcry_md_register (gcry_md_spec_t *digest, - md_extra_spec_t *extraspec, - unsigned int *algorithm_id, - gcry_module_t *module) +/* Lookup a hash's spec by its OID. */ +static gcry_md_spec_t * +spec_from_oid (const char *oid) { - gcry_err_code_t err = 0; - gcry_module_t mod; + gcry_md_spec_t *spec; + gcry_md_oid_spec_t *oid_specs; + int idx, j; - /* We do not support module loading in fips mode. */ - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - ath_mutex_lock (&digests_registered_lock); - err = _gcry_module_add (&digests_registered, 0, - (void *) digest, - (void *)(extraspec? extraspec : &dummy_extra_spec), - &mod); - ath_mutex_unlock (&digests_registered_lock); - - if (! err) + for (idx=0; (spec = digest_list[idx]); idx++) { - *module = mod; - *algorithm_id = mod->mod_id; + oid_specs = spec->oids; + if (oid_specs) + { + for (j = 0; oid_specs[j].oidstring; j++) + if (!stricmp (oid, oid_specs[j].oidstring)) + return spec; + } } - return gcry_error (err); -} - -/* Unregister the digest identified by ID, which must have been - registered with gcry_digest_register. */ -void -gcry_md_unregister (gcry_module_t module) -{ - ath_mutex_lock (&digests_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&digests_registered_lock); + return NULL; } -static int -search_oid (const char *oid, int *algorithm, gcry_md_oid_spec_t *oid_spec) +static gcry_md_spec_t * +search_oid (const char *oid, gcry_md_oid_spec_t *oid_spec) { - gcry_module_t module; - int ret = 0; + gcry_md_spec_t *spec; + int i; if (oid && ((! strncmp (oid, "oid.", 4)) || (! strncmp (oid, "OID.", 4)))) oid += 4; - module = gcry_md_lookup_oid (oid); - if (module) + spec = spec_from_oid (oid); + if (spec && spec->oids) { - gcry_md_spec_t *digest = module->spec; - int i; - - for (i = 0; digest->oids[i].oidstring && !ret; i++) - if (!_stricmp (oid, digest->oids[i].oidstring)) + for (i = 0; spec->oids[i].oidstring; i++) + if (!stricmp (oid, spec->oids[i].oidstring)) { - if (algorithm) - *algorithm = module->mod_id; if (oid_spec) - *oid_spec = digest->oids[i]; - ret = 1; + *oid_spec = spec->oids[i]; + return spec; } - _gcry_module_release (module); } - return ret; + return NULL; } + /**************** * Map a string to the digest algo */ int -gcry_md_map_name (const char *string) +_gcry_md_map_name (const char *string) { - gcry_module_t digest; - int ret, algorithm = 0; + gcry_md_spec_t *spec; - if (! string) + if (!string) return 0; - REGISTER_DEFAULT_DIGESTS; - /* If the string starts with a digit (optionally prefixed with either "OID." or "oid."), we first look into our table of ASN.1 object identifiers to figure out the algorithm */ + spec = search_oid (string, NULL); + if (spec) + return spec->algo; - ath_mutex_lock (&digests_registered_lock); + /* Not found, search a matching digest name. */ + spec = spec_from_name (string); + if (spec) + return spec->algo; - ret = search_oid (string, &algorithm, NULL); - if (! ret) - { - /* Not found, search a matching digest name. */ - digest = gcry_md_lookup_name (string); - if (digest) - { - algorithm = digest->mod_id; - _gcry_module_release (digest); - } - } - ath_mutex_unlock (&digests_registered_lock); - - return algorithm; + return 0; } /**************** - * Map a digest algo to a string - */ -static const char * -digest_algo_to_string (int algorithm) -{ - const char *name = NULL; - gcry_module_t digest; - - REGISTER_DEFAULT_DIGESTS; - - ath_mutex_lock (&digests_registered_lock); - digest = _gcry_module_lookup_id (digests_registered, algorithm); - if (digest) - { - name = ((gcry_md_spec_t *) digest->spec)->name; - _gcry_module_release (digest); - } - ath_mutex_unlock (&digests_registered_lock); - - return name; -} - -/**************** * This function simply returns the name of the algorithm or some constant * string when there is no algo. It will never return NULL. * Use the macro gcry_md_test_algo() to check whether the algorithm * is valid. */ const char * -gcry_md_algo_name (int algorithm) +_gcry_md_algo_name (int algorithm) { - const char *s = digest_algo_to_string (algorithm); - return s ? s : "?"; + gcry_md_spec_t *spec; + + spec = spec_from_algo (algorithm); + return spec ? spec->name : "?"; } static gcry_err_code_t check_digest_algo (int algorithm) { - gcry_err_code_t rc = 0; - gcry_module_t digest; + gcry_md_spec_t *spec; - REGISTER_DEFAULT_DIGESTS; + spec = spec_from_algo (algorithm); + if (spec && !spec->flags.disabled) + return 0; - ath_mutex_lock (&digests_registered_lock); - digest = _gcry_module_lookup_id (digests_registered, algorithm); - if (digest) - _gcry_module_release (digest); - else - rc = GPG_ERR_DIGEST_ALGO; - ath_mutex_unlock (&digests_registered_lock); + return GPG_ERR_DIGEST_ALGO; - return rc; } - /**************** * Open a message digest handle for use with algorithm ALGO. * More algorithms may be added by md_enable(). The initial algorithm * may be 0. */ static gcry_err_code_t -md_open (gcry_md_hd_t *h, int algo, int secure, int hmac) +md_open (gcry_md_hd_t *h, int algo, unsigned int flags) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_err_code_t err = 0; + int secure = !!(flags & GCRY_MD_FLAG_SECURE); + int hmac = !!(flags & GCRY_MD_FLAG_HMAC); int bufsize = secure ? 512 : 1024; struct gcry_md_context *ctx; gcry_md_hd_t hd; @@ -456,9 +303,9 @@ md_open (gcry_md_hd_t *h, int algo, int secure, int hmac) /* Allocate and set the Context pointer to the private data */ if (secure) - hd = gcry_malloc_secure (n + sizeof (struct gcry_md_context)); + hd = xtrymalloc_secure (n + sizeof (struct gcry_md_context)); else - hd = gcry_malloc (n + sizeof (struct gcry_md_context)); + hd = xtrymalloc (n + sizeof (struct gcry_md_context)); if (! hd) err = gpg_err_code_from_errno (errno); @@ -474,7 +321,8 @@ md_open (gcry_md_hd_t *h, int algo, int secure, int hmac) memset (hd->ctx, 0, sizeof *hd->ctx); ctx->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL; ctx->actual_handle_size = n + sizeof (struct gcry_md_context); - ctx->secure = secure; + ctx->flags.secure = secure; + ctx->flags.bugemu1 = !!(flags & GCRY_MD_FLAG_BUGEMU1); if (hmac) { @@ -484,11 +332,14 @@ md_open (gcry_md_hd_t *h, int algo, int secure, int hmac) case GCRY_MD_SHA512: ctx->macpads_Bsize = 128; break; + case GCRY_MD_GOSTR3411_94: + ctx->macpads_Bsize = 32; + break; default: ctx->macpads_Bsize = 64; break; } - ctx->macpads = gcry_malloc_secure (2*(ctx->macpads_Bsize)); + ctx->macpads = xtrymalloc_secure (2*(ctx->macpads_Bsize)); if (!ctx->macpads) { err = gpg_err_code_from_errno (errno); @@ -521,22 +372,21 @@ md_open (gcry_md_hd_t *h, int algo, int secure, int hmac) given as 0 if the algorithms to be used are later set using gcry_md_enable. H is guaranteed to be a valid handle or NULL on error. */ -gcry_error_t -gcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags) +gcry_err_code_t +_gcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_err_code_t rc; gcry_md_hd_t hd; - if ((flags & ~(GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC))) - err = GPG_ERR_INV_ARG; + if ((flags & ~(GCRY_MD_FLAG_SECURE + | GCRY_MD_FLAG_HMAC + | GCRY_MD_FLAG_BUGEMU1))) + rc = GPG_ERR_INV_ARG; else - { - err = md_open (&hd, algo, (flags & GCRY_MD_FLAG_SECURE), - (flags & GCRY_MD_FLAG_HMAC)); - } + rc = md_open (&hd, algo, flags); - *h = err? NULL : hd; - return gcry_error (err); + *h = rc? NULL : hd; + return rc; } @@ -545,29 +395,22 @@ static gcry_err_code_t md_enable (gcry_md_hd_t hd, int algorithm) { struct gcry_md_context *h = hd->ctx; - gcry_md_spec_t *digest = NULL; + gcry_md_spec_t *spec; GcryDigestEntry *entry; - gcry_module_t module; gcry_err_code_t err = 0; for (entry = h->list; entry; entry = entry->next) - if (entry->module->mod_id == algorithm) - return err; /* already enabled */ - - REGISTER_DEFAULT_DIGESTS; + if (entry->spec->algo == algorithm) + return 0; /* Already enabled */ - ath_mutex_lock (&digests_registered_lock); - module = _gcry_module_lookup_id (digests_registered, algorithm); - ath_mutex_unlock (&digests_registered_lock); - if (! module) + spec = spec_from_algo (algorithm); + if (!spec) { log_debug ("md_enable: algorithm %d not available\n", algorithm); err = GPG_ERR_DIGEST_ALGO; } - else - digest = (gcry_md_spec_t *) module->spec; - + if (!err && algorithm == GCRY_MD_MD5 && fips_mode ()) { _gcry_inactivate_fips_mode ("MD5 used"); @@ -578,41 +421,31 @@ md_enable (gcry_md_hd_t hd, int algorithm) err = GPG_ERR_DIGEST_ALGO; } } - + if (!err) { size_t size = (sizeof (*entry) - + digest->contextsize + + spec->contextsize - sizeof (entry->context)); /* And allocate a new list entry. */ - if (h->secure) - entry = gcry_malloc_secure (size); + if (h->flags.secure) + entry = xtrymalloc_secure (size); else - entry = gcry_malloc (size); + entry = xtrymalloc (size); if (! entry) err = gpg_err_code_from_errno (errno); else { - entry->digest = digest; - entry->module = module; + entry->spec = spec; entry->next = h->list; entry->actual_struct_size = size; h->list = entry; /* And init this instance. */ - entry->digest->init (&entry->context.c); - } - } - - if (err) - { - if (module) - { - ath_mutex_lock (&digests_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&digests_registered_lock); + entry->spec->init (&entry->context.c, + h->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0); } } @@ -620,30 +453,31 @@ md_enable (gcry_md_hd_t hd, int algorithm) } -gcry_error_t -gcry_md_enable (gcry_md_hd_t hd, int algorithm) +gcry_err_code_t +_gcry_md_enable (gcry_md_hd_t hd, int algorithm) { - return gcry_error (md_enable (hd, algorithm)); + return md_enable (hd, algorithm); } + static gcry_err_code_t md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_err_code_t err = 0; struct gcry_md_context *a = ahd->ctx; struct gcry_md_context *b; GcryDigestEntry *ar, *br; gcry_md_hd_t bhd; size_t n; - + if (ahd->bufpos) md_write (ahd, NULL, 0); n = (char *) ahd->ctx - (char *) ahd; - if (a->secure) - bhd = gcry_malloc_secure (n + sizeof (struct gcry_md_context)); + if (a->flags.secure) + bhd = xtrymalloc_secure (n + sizeof (struct gcry_md_context)); else - bhd = gcry_malloc (n + sizeof (struct gcry_md_context)); + bhd = xtrymalloc (n + sizeof (struct gcry_md_context)); if (! bhd) err = gpg_err_code_from_errno (errno); @@ -661,7 +495,7 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd) b->debug = NULL; if (a->macpads) { - b->macpads = gcry_malloc_secure (2*(a->macpads_Bsize)); + b->macpads = xtrymalloc_secure (2*(a->macpads_Bsize)); if (! b->macpads) { err = gpg_err_code_from_errno (errno); @@ -678,14 +512,14 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd) { for (ar = a->list; ar; ar = ar->next) { - if (a->secure) - br = gcry_malloc_secure (sizeof *br - + ar->digest->contextsize - - sizeof(ar->context)); + if (a->flags.secure) + br = xtrymalloc_secure (sizeof *br + + ar->spec->contextsize + - sizeof(ar->context)); else - br = gcry_malloc (sizeof *br - + ar->digest->contextsize - - sizeof (ar->context)); + br = xtrymalloc (sizeof *br + + ar->spec->contextsize + - sizeof (ar->context)); if (!br) { err = gpg_err_code_from_errno (errno); @@ -693,15 +527,10 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd) break; } - memcpy (br, ar, (sizeof (*br) + ar->digest->contextsize + memcpy (br, ar, (sizeof (*br) + ar->spec->contextsize - sizeof (ar->context))); br->next = b->list; b->list = br; - - /* Add a reference to the module. */ - ath_mutex_lock (&digests_registered_lock); - _gcry_module_use (br->module); - ath_mutex_unlock (&digests_registered_lock); } } @@ -714,39 +543,43 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd) return err; } -gcry_error_t -gcry_md_copy (gcry_md_hd_t *handle, gcry_md_hd_t hd) + +gcry_err_code_t +_gcry_md_copy (gcry_md_hd_t *handle, gcry_md_hd_t hd) { - gcry_err_code_t err; + gcry_err_code_t rc; - err = md_copy (hd, handle); - if (err) + rc = md_copy (hd, handle); + if (rc) *handle = NULL; - return gcry_error (err); + return rc; } + /* * Reset all contexts and discard any buffered stuff. This may be used * instead of a md_close(); md_open(). */ void -gcry_md_reset (gcry_md_hd_t a) +_gcry_md_reset (gcry_md_hd_t a) { GcryDigestEntry *r; /* Note: We allow this even in fips non operational mode. */ - a->bufpos = a->ctx->finalized = 0; + a->bufpos = a->ctx->flags.finalized = 0; for (r = a->ctx->list; r; r = r->next) { - memset (r->context.c, 0, r->digest->contextsize); - (*r->digest->init) (&r->context.c); + memset (r->context.c, 0, r->spec->contextsize); + (*r->spec->init) (&r->context.c, + a->ctx->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0); } if (a->ctx->macpads) md_write (a, a->ctx->macpads, a->ctx->macpads_Bsize); /* inner pad */ } + static void md_close (gcry_md_hd_t a) { @@ -759,35 +592,34 @@ md_close (gcry_md_hd_t a) for (r = a->ctx->list; r; r = r2) { r2 = r->next; - ath_mutex_lock (&digests_registered_lock); - _gcry_module_release (r->module); - ath_mutex_unlock (&digests_registered_lock); wipememory (r, r->actual_struct_size); - gcry_free (r); + xfree (r); } if (a->ctx->macpads) { wipememory (a->ctx->macpads, 2*(a->ctx->macpads_Bsize)); - gcry_free(a->ctx->macpads); + xfree(a->ctx->macpads); } wipememory (a, a->ctx->actual_handle_size); - gcry_free(a); + xfree(a); } + void -gcry_md_close (gcry_md_hd_t hd) +_gcry_md_close (gcry_md_hd_t hd) { /* Note: We allow this even in fips non operational mode. */ md_close (hd); } + static void md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen) { GcryDigestEntry *r; - + if (a->ctx->debug) { if (a->bufpos && fwrite (a->buf, a->bufpos, 1, a->ctx->debug) != 1) @@ -799,33 +631,35 @@ md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen) for (r = a->ctx->list; r; r = r->next) { if (a->bufpos) - (*r->digest->write) (&r->context.c, a->buf, a->bufpos); - (*r->digest->write) (&r->context.c, inbuf, inlen); + (*r->spec->write) (&r->context.c, a->buf, a->bufpos); + (*r->spec->write) (&r->context.c, inbuf, inlen); } a->bufpos = 0; } + void -gcry_md_write (gcry_md_hd_t hd, const void *inbuf, size_t inlen) +_gcry_md_write (gcry_md_hd_t hd, const void *inbuf, size_t inlen) { md_write (hd, inbuf, inlen); } + static void md_final (gcry_md_hd_t a) { GcryDigestEntry *r; - if (a->ctx->finalized) + if (a->ctx->flags.finalized) return; if (a->bufpos) md_write (a, NULL, 0); for (r = a->ctx->list; r; r = r->next) - (*r->digest->final) (&r->context.c); + (*r->spec->final) (&r->context.c); - a->ctx->finalized = 1; + a->ctx->flags.finalized = 1; if (a->ctx->macpads) { @@ -834,12 +668,15 @@ md_final (gcry_md_hd_t a) byte *p = md_read (a, algo); size_t dlen = md_digest_length (algo); gcry_md_hd_t om; - gcry_err_code_t err = md_open (&om, algo, a->ctx->secure, 0); + gcry_err_code_t err; + err = md_open (&om, algo, + ((a->ctx->flags.secure? GCRY_MD_FLAG_SECURE:0) + | (a->ctx->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0))); if (err) _gcry_fatal_error (err, NULL); - md_write (om, - (a->ctx->macpads)+(a->ctx->macpads_Bsize), + md_write (om, + (a->ctx->macpads)+(a->ctx->macpads_Bsize), a->ctx->macpads_Bsize); md_write (om, p, dlen); md_final (om); @@ -849,6 +686,7 @@ md_final (gcry_md_hd_t a) } } + static gcry_err_code_t prepare_macpads (gcry_md_hd_t hd, const unsigned char *key, size_t keylen) { @@ -860,12 +698,12 @@ prepare_macpads (gcry_md_hd_t hd, const unsigned char *key, size_t keylen) if (!algo) return GPG_ERR_DIGEST_ALGO; /* Might happen if no algo is enabled. */ - if ( keylen > hd->ctx->macpads_Bsize ) + if ( keylen > hd->ctx->macpads_Bsize ) { - helpkey = gcry_malloc_secure (md_digest_length (algo)); + helpkey = xtrymalloc_secure (md_digest_length (algo)); if (!helpkey) return gpg_err_code_from_errno (errno); - gcry_md_hash_buffer (algo, helpkey, key, keylen); + _gcry_md_hash_buffer (algo, helpkey, key, keylen); key = helpkey; keylen = md_digest_length (algo); gcry_assert ( keylen <= hd->ctx->macpads_Bsize ); @@ -876,29 +714,29 @@ prepare_macpads (gcry_md_hd_t hd, const unsigned char *key, size_t keylen) opad = (hd->ctx->macpads)+(hd->ctx->macpads_Bsize); memcpy ( ipad, key, keylen ); memcpy ( opad, key, keylen ); - for (i=0; i < hd->ctx->macpads_Bsize; i++ ) + for (i=0; i < hd->ctx->macpads_Bsize; i++ ) { ipad[i] ^= 0x36; opad[i] ^= 0x5c; } - gcry_free (helpkey); + xfree (helpkey); - return GPG_ERR_NO_ERROR; + return 0; } -gcry_error_t -gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen) + +gcry_err_code_t +_gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen) { gcry_err_code_t rc = 0; - + + (void)buflen; /* Currently not used. */ + switch (cmd) { case GCRYCTL_FINALIZE: md_final (hd); break; - case GCRYCTL_SET_KEY: - rc = gcry_err_code (gcry_md_setkey (hd, buffer, buflen)); - break; case GCRYCTL_START_DUMP: md_start_debug (hd, buffer); break; @@ -908,31 +746,33 @@ gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen) default: rc = GPG_ERR_INV_OP; } - return gcry_error (rc); + return rc; } -gcry_error_t -gcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen) + +gcry_err_code_t +_gcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen) { - gcry_err_code_t rc = GPG_ERR_NO_ERROR; + gcry_err_code_t rc; if (!hd->ctx->macpads) rc = GPG_ERR_CONFLICT; else { rc = prepare_macpads (hd, key, keylen); - if (! rc) - gcry_md_reset (hd); + if (!rc) + _gcry_md_reset (hd); } - return gcry_error (rc); + return rc; } + /* The new debug interface. If SUFFIX is a string it creates an debug file for the context HD. IF suffix is NULL, the file is closed and debugging is stopped. */ void -gcry_md_debug (gcry_md_hd_t hd, const char *suffix) +_gcry_md_debug (gcry_md_hd_t hd, const char *suffix) { if (suffix) md_start_debug (hd, suffix); @@ -941,9 +781,9 @@ gcry_md_debug (gcry_md_hd_t hd, const char *suffix) } - /**************** - * if ALGO is null get the digest for the used algo (which should be only one) + * If ALGO is null get the digest for the used algo (which should be + * only one) */ static byte * md_read( gcry_md_hd_t a, int algo ) @@ -952,35 +792,36 @@ md_read( gcry_md_hd_t a, int algo ) if (! algo) { - /* Return the first algorithm. */ + /* Return the first algorithm */ if (r) { if (r->next) log_debug ("more than one algorithm in md_read(0)\n"); - return r->digest->read( &r->context.c ); + return r->spec->read (&r->context.c); } } else { for (r = a->ctx->list; r; r = r->next) - if (r->module->mod_id == algo) - return r->digest->read (&r->context.c); + if (r->spec->algo == algo) + return r->spec->read (&r->context.c); } BUG(); return NULL; } + /* * Read out the complete digest, this function implictly finalizes * the hash. */ byte * -gcry_md_read (gcry_md_hd_t hd, int algo) +_gcry_md_read (gcry_md_hd_t hd, int algo) { /* This function is expected to always return a digest, thus we can't return an error which we actually should do in non-operational state. */ - gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); + _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); return md_read (hd, algo); } @@ -989,7 +830,7 @@ gcry_md_read (gcry_md_hd_t hd, int algo) * Read out an intermediate digest. Not yet functional. */ gcry_err_code_t -gcry_md_get (gcry_md_hd_t hd, int algo, byte *buffer, int buflen) +_gcry_md_get (gcry_md_hd_t hd, int algo, byte *buffer, int buflen) { (void)hd; (void)algo; @@ -1009,8 +850,8 @@ gcry_md_get (gcry_md_hd_t hd, int algo, byte *buffer, int buflen) * hash. No error is returned, the function will abort on an invalid * algo. DISABLED_ALGOS are ignored here. */ void -gcry_md_hash_buffer (int algo, void *digest, - const void *buffer, size_t length) +_gcry_md_hash_buffer (int algo, void *digest, + const void *buffer, size_t length) { if (algo == GCRY_MD_SHA1) _gcry_sha1_hash_buffer (digest, buffer, length); @@ -1034,7 +875,7 @@ gcry_md_hash_buffer (int algo, void *digest, } } - err = md_open (&h, algo, 0, 0); + err = md_open (&h, algo, 0); if (err) log_bug ("gcry_md_open failed for algo %d: %s", algo, gpg_strerror (gcry_error(err))); @@ -1045,6 +886,83 @@ gcry_md_hash_buffer (int algo, void *digest, } } + +/* Shortcut function to hash multiple buffers with a given algo. In + contrast to gcry_md_hash_buffer, this function returns an error on + invalid arguments or on other problems; disabled algorithms are + _not_ ignored but flagged as an error. + + The data to sign is taken from the array IOV which has IOVCNT items. + + The only supported flag in FLAGS is GCRY_MD_FLAG_HMAC which turns + this function into a HMAC function; the first item in IOV is then + used as the key. + + On success 0 is returned and resulting hash or HMAC is stored at + DIGEST which must have been provided by the caller with an + appropriate length. */ +gpg_err_code_t +_gcry_md_hash_buffers (int algo, unsigned int flags, void *digest, + const gcry_buffer_t *iov, int iovcnt) +{ + int hmac; + + if (!iov || iovcnt < 0) + return GPG_ERR_INV_ARG; + if (flags & ~(GCRY_MD_FLAG_HMAC)) + return GPG_ERR_INV_ARG; + + hmac = !!(flags & GCRY_MD_FLAG_HMAC); + if (hmac && iovcnt < 1) + return GPG_ERR_INV_ARG; + + if (algo == GCRY_MD_SHA1 && !hmac) + _gcry_sha1_hash_buffers (digest, iov, iovcnt); + else + { + /* For the others we do not have a fast function, so we use the + normal functions. */ + gcry_md_hd_t h; + gpg_err_code_t rc; + + if (algo == GCRY_MD_MD5 && fips_mode ()) + { + _gcry_inactivate_fips_mode ("MD5 used"); + if (_gcry_enforced_fips_mode () ) + { + /* We should never get to here because we do not register + MD5 in enforced fips mode. */ + _gcry_fips_noreturn (); + } + } + + rc = md_open (&h, algo, (hmac? GCRY_MD_FLAG_HMAC:0)); + if (rc) + return rc; + + if (hmac) + { + rc = _gcry_md_setkey (h, + (const char*)iov[0].data + iov[0].off, + iov[0].len); + if (rc) + { + md_close (h); + return rc; + } + iov++; iovcnt--; + } + for (;iovcnt; iov++, iovcnt--) + md_write (h, (const char*)iov[0].data + iov[0].off, iov[0].len); + md_final (h); + memcpy (digest, md_read (h, algo), md_digest_length (algo)); + md_close (h); + } + + return 0; +} + + static int md_get_algo (gcry_md_hd_t a) { @@ -1055,11 +973,12 @@ md_get_algo (gcry_md_hd_t a) fips_signal_error ("possible usage error"); log_error ("WARNING: more than one algorithm in md_get_algo()\n"); } - return r ? r->module->mod_id : 0; + return r ? r->spec->algo : 0; } + int -gcry_md_get_algo (gcry_md_hd_t hd) +_gcry_md_get_algo (gcry_md_hd_t hd) { return md_get_algo (hd); } @@ -1071,29 +990,19 @@ gcry_md_get_algo (gcry_md_hd_t hd) static int md_digest_length (int algorithm) { - gcry_module_t digest; - int mdlen = 0; - - REGISTER_DEFAULT_DIGESTS; + gcry_md_spec_t *spec; - ath_mutex_lock (&digests_registered_lock); - digest = _gcry_module_lookup_id (digests_registered, algorithm); - if (digest) - { - mdlen = ((gcry_md_spec_t *) digest->spec)->mdlen; - _gcry_module_release (digest); - } - ath_mutex_unlock (&digests_registered_lock); - - return mdlen; + spec = spec_from_algo (algorithm); + return spec? spec->mdlen : 0; } + /**************** * Return the length of the digest in bytes. * This function will return 0 in case of errors. */ unsigned int -gcry_md_get_algo_dlen (int algorithm) +_gcry_md_get_algo_dlen (int algorithm) { return md_digest_length (algorithm); } @@ -1104,31 +1013,25 @@ gcry_md_get_algo_dlen (int algorithm) static const byte * md_asn_oid (int algorithm, size_t *asnlen, size_t *mdlen) { + gcry_md_spec_t *spec; const byte *asnoid = NULL; - gcry_module_t digest; - - REGISTER_DEFAULT_DIGESTS; - ath_mutex_lock (&digests_registered_lock); - digest = _gcry_module_lookup_id (digests_registered, algorithm); - if (digest) + spec = spec_from_algo (algorithm); + if (spec) { if (asnlen) - *asnlen = ((gcry_md_spec_t *) digest->spec)->asnlen; + *asnlen = spec->asnlen; if (mdlen) - *mdlen = ((gcry_md_spec_t *) digest->spec)->mdlen; - asnoid = ((gcry_md_spec_t *) digest->spec)->asnoid; - _gcry_module_release (digest); + *mdlen = spec->mdlen; + asnoid = spec->asnoid; } else log_bug ("no ASN.1 OID for md algo %d\n", algorithm); - ath_mutex_unlock (&digests_registered_lock); return asnoid; } - /**************** * Return information about the given cipher algorithm * WHAT select the kind of information returned: @@ -1138,59 +1041,68 @@ md_asn_oid (int algorithm, size_t *asnlen, size_t *mdlen) * GCRYCTL_GET_ASNOID: * Return the ASNOID of the algorithm in buffer. if buffer is NULL, only * the required length is returned. + * GCRYCTL_SELFTEST + * Helper for the regression tests - shall not be used by applications. * * Note: Because this function is in most cases used to return an * integer value, we can make it easier for the caller to just look at * the return value. The caller will in all cases consult the value - * and thereby detecting whether a error occured or not (i.e. while checking + * and thereby detecting whether a error occurred or not (i.e. while checking * the block size) */ -gcry_error_t -gcry_md_algo_info (int algo, int what, void *buffer, size_t *nbytes) +gcry_err_code_t +_gcry_md_algo_info (int algo, int what, void *buffer, size_t *nbytes) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_err_code_t rc; switch (what) { case GCRYCTL_TEST_ALGO: if (buffer || nbytes) - err = GPG_ERR_INV_ARG; + rc = GPG_ERR_INV_ARG; else - err = check_digest_algo (algo); + rc = check_digest_algo (algo); break; case GCRYCTL_GET_ASNOID: /* We need to check that the algo is available because md_asn_oid would otherwise raise an assertion. */ - err = check_digest_algo (algo); - if (!err) + rc = check_digest_algo (algo); + if (!rc) { const char unsigned *asn; size_t asnlen; - + asn = md_asn_oid (algo, &asnlen, NULL); if (buffer && (*nbytes >= asnlen)) - { - memcpy (buffer, asn, asnlen); - *nbytes = asnlen; - } + { + memcpy (buffer, asn, asnlen); + *nbytes = asnlen; + } else if (!buffer && nbytes) *nbytes = asnlen; else { if (buffer) - err = GPG_ERR_TOO_SHORT; + rc = GPG_ERR_TOO_SHORT; else - err = GPG_ERR_INV_ARG; + rc = GPG_ERR_INV_ARG; } } break; - default: - err = GPG_ERR_INV_OP; + case GCRYCTL_SELFTEST: + /* Helper function for the regression tests. */ + rc = gpg_err_code (_gcry_md_selftest (algo, nbytes? (int)*nbytes : 0, + NULL)); + break; + + default: + rc = GPG_ERR_INV_OP; + break; } - return gcry_error (err); + return rc; } @@ -1202,7 +1114,7 @@ md_start_debug ( gcry_md_hd_t md, const char *suffix ) if (fips_mode ()) return; - + if ( md->ctx->debug ) { log_debug("Oops: md debug already started\n"); @@ -1215,6 +1127,7 @@ md_start_debug ( gcry_md_hd_t md, const char *suffix ) log_debug("md debug: can't open %s\n", buf ); } + static void md_stop_debug( gcry_md_hd_t md ) { @@ -1232,6 +1145,7 @@ md_stop_debug( gcry_md_hd_t md ) volatile u64 b = 42; volatile u64 c; c = a * b; + (void)c; } #endif } @@ -1247,15 +1161,15 @@ md_stop_debug( gcry_md_hd_t md ) * Returns 1 if the algo is enabled for that handle. * The algo must be passed as the address of an int. */ -gcry_error_t -gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes) +gcry_err_code_t +_gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_err_code_t rc = 0; switch (cmd) { case GCRYCTL_IS_SECURE: - *nbytes = h->ctx->secure; + *nbytes = h->ctx->flags.secure; break; case GCRYCTL_IS_ALGO_ENABLED: @@ -1263,15 +1177,15 @@ gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes) GcryDigestEntry *r; int algo; - if ( !buffer || (nbytes && (*nbytes != sizeof (int)))) - err = GPG_ERR_INV_ARG; + if ( !buffer || !nbytes || *nbytes != sizeof (int)) + rc = GPG_ERR_INV_ARG; else { algo = *(int*)buffer; - + *nbytes = 0; for(r=h->ctx->list; r; r = r->next ) { - if (r->module->mod_id == algo) + if (r->spec->algo == algo) { *nbytes = 1; break; @@ -1282,10 +1196,10 @@ gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes) } default: - err = GPG_ERR_INV_OP; + rc = GPG_ERR_INV_OP; } - return gcry_error (err); + return rc; } @@ -1293,20 +1207,16 @@ gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes) gcry_err_code_t _gcry_md_init (void) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - REGISTER_DEFAULT_DIGESTS; - - return err; + return 0; } int -gcry_md_is_secure (gcry_md_hd_t a) +_gcry_md_is_secure (gcry_md_hd_t a) { size_t value; - if (gcry_md_info (a, GCRYCTL_IS_SECURE, NULL, &value)) + if (_gcry_md_info (a, GCRYCTL_IS_SECURE, NULL, &value)) value = 1; /* It seems to be better to assume secure memory on error. */ return value; @@ -1314,69 +1224,38 @@ gcry_md_is_secure (gcry_md_hd_t a) int -gcry_md_is_enabled (gcry_md_hd_t a, int algo) +_gcry_md_is_enabled (gcry_md_hd_t a, int algo) { size_t value; value = sizeof algo; - if (gcry_md_info (a, GCRYCTL_IS_ALGO_ENABLED, &algo, &value)) + if (_gcry_md_info (a, GCRYCTL_IS_ALGO_ENABLED, &algo, &value)) value = 0; return value; } -/* Get a list consisting of the IDs of the loaded message digest - modules. If LIST is zero, write the number of loaded message - digest modules to LIST_LENGTH and return. If LIST is non-zero, the - first *LIST_LENGTH algorithm IDs are stored in LIST, which must be - of according size. In case there are less message digest modules - than *LIST_LENGTH, *LIST_LENGTH is updated to the correct - number. */ -gcry_error_t -gcry_md_list (int *list, int *list_length) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - ath_mutex_lock (&digests_registered_lock); - err = _gcry_module_list (digests_registered, list, list_length); - ath_mutex_unlock (&digests_registered_lock); - - return err; -} - /* Run the selftests for digest algorithm ALGO with optional reporting function REPORT. */ gpg_error_t _gcry_md_selftest (int algo, int extended, selftest_report_func_t report) { - gcry_module_t module = NULL; - cipher_extra_spec_t *extraspec = NULL; gcry_err_code_t ec = 0; + gcry_md_spec_t *spec; - REGISTER_DEFAULT_DIGESTS; - - ath_mutex_lock (&digests_registered_lock); - module = _gcry_module_lookup_id (digests_registered, algo); - if (module && !(module->flags & FLAG_MODULE_DISABLED)) - extraspec = module->extraspec; - ath_mutex_unlock (&digests_registered_lock); - if (extraspec && extraspec->selftest) - ec = extraspec->selftest (algo, extended, report); + spec = spec_from_algo (algo); + if (spec && !spec->flags.disabled && spec->selftest) + ec = spec->selftest (algo, extended, report); else { - ec = GPG_ERR_DIGEST_ALGO; + ec = (spec && spec->selftest) ? GPG_ERR_DIGEST_ALGO + /* */ : GPG_ERR_NOT_IMPLEMENTED; if (report) - report ("digest", algo, "module", - module && !(module->flags & FLAG_MODULE_DISABLED)? + report ("digest", algo, "module", + (spec && !spec->flags.disabled)? "no selftest available" : - module? "algorithm disabled" : "algorithm not found"); + spec? "algorithm disabled" : "algorithm not found"); } - if (module) - { - ath_mutex_lock (&digests_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&digests_registered_lock); - } return gpg_error (ec); } diff --git a/plugins/MirOTR/Libgcrypt/cipher/md4.c b/plugins/MirOTR/Libgcrypt/cipher/md4.c index 680cf87f5d..624ae997e0 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/md4.c +++ b/plugins/MirOTR/Libgcrypt/cipher/md4.c @@ -53,32 +53,38 @@ #include <string.h> #include "g10lib.h" -#include "memory.h" #include "cipher.h" #include "bithelp.h" +#include "bufhelp.h" +#include "hash-common.h" typedef struct { + gcry_md_block_ctx_t bctx; u32 A,B,C,D; /* chaining variables */ - u32 nblocks; - byte buf[64]; - int count; } MD4_CONTEXT; +static unsigned int +transform ( void *c, const unsigned char *data ); static void -md4_init( void *context ) +md4_init (void *context, unsigned int flags) { MD4_CONTEXT *ctx = context; + (void)flags; + ctx->A = 0x67452301; ctx->B = 0xefcdab89; ctx->C = 0x98badcfe; ctx->D = 0x10325476; - ctx->nblocks = 0; - ctx->count = 0; + ctx->bctx.nblocks = 0; + ctx->bctx.nblocks_high = 0; + ctx->bctx.count = 0; + ctx->bctx.blocksize = 64; + ctx->bctx.bwrite = transform; } #define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) @@ -89,30 +95,19 @@ md4_init( void *context ) /**************** * transform 64 bytes */ -static void -transform ( MD4_CONTEXT *ctx, const unsigned char *data ) +static unsigned int +transform ( void *c, const unsigned char *data ) { + MD4_CONTEXT *ctx = c; u32 in[16]; register u32 A = ctx->A; register u32 B = ctx->B; register u32 C = ctx->C; register u32 D = ctx->D; + int i; -#ifdef WORDS_BIGENDIAN - { - int i; - byte *p2, *p1; - for(i=0, p1=data, p2=(byte*)in; i < 16; i++, p2 += 4 ) - { - p2[3] = *p1++; - p2[2] = *p1++; - p2[1] = *p1++; - p2[0] = *p1++; - } - } -#else - memcpy (in, data, 64); -#endif + for ( i = 0; i < 16; i++ ) + in[i] = buf_get_le32(data + i * 4); /* Round 1. */ #define function(a,b,c,d,k,s) a=rol(a+F(b,c,d)+in[k],s); @@ -183,50 +178,8 @@ transform ( MD4_CONTEXT *ctx, const unsigned char *data ) ctx->B += B; ctx->C += C; ctx->D += D; -} - - -/* The routine updates the message-digest context to - * account for the presence of each of the characters inBuf[0..inLen-1] - * in the message whose digest is being computed. - */ -static void -md4_write ( void *context, const void *inbuf_arg, size_t inlen) -{ - const unsigned char *inbuf = inbuf_arg; - MD4_CONTEXT *hd = context; - - if( hd->count == 64 ) /* flush the buffer */ - { - transform( hd, hd->buf ); - _gcry_burn_stack (80+6*sizeof(void*)); - hd->count = 0; - hd->nblocks++; - } - if( !inbuf ) - return; - - if( hd->count ) - { - for( ; inlen && hd->count < 64; inlen-- ) - hd->buf[hd->count++] = *inbuf++; - md4_write( hd, NULL, 0 ); - if( !inlen ) - return; - } - _gcry_burn_stack (80+6*sizeof(void*)); - - while( inlen >= 64 ) - { - transform( hd, inbuf ); - hd->count = 0; - hd->nblocks++; - inlen -= 64; - inbuf += 64; - } - for( ; inlen && hd->count < 64; inlen-- ) - hd->buf[hd->count++] = *inbuf++; + return /*burn_stack*/ 80+6*sizeof(void*); } @@ -241,58 +194,53 @@ static void md4_final( void *context ) { MD4_CONTEXT *hd = context; - u32 t, msb, lsb; + u32 t, th, msb, lsb; byte *p; + unsigned int burn; - md4_write(hd, NULL, 0); /* flush */; + _gcry_md_block_write(hd, NULL, 0); /* flush */; + + t = hd->bctx.nblocks; + if (sizeof t == sizeof hd->bctx.nblocks) + th = hd->bctx.nblocks_high; + else + th = hd->bctx.nblocks >> 32; - t = hd->nblocks; /* multiply by 64 to make a byte count */ lsb = t << 6; - msb = t >> 26; + msb = (th << 6) | (t >> 26); /* add the count */ t = lsb; - if( (lsb += hd->count) < t ) + if( (lsb += hd->bctx.count) < t ) msb++; /* multiply by 8 to make a bit count */ t = lsb; lsb <<= 3; msb <<= 3; msb |= t >> 29; - - if( hd->count < 56 ) /* enough room */ + + if( hd->bctx.count < 56 ) /* enough room */ { - hd->buf[hd->count++] = 0x80; /* pad */ - while( hd->count < 56 ) - hd->buf[hd->count++] = 0; /* pad */ + hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad */ + while( hd->bctx.count < 56 ) + hd->bctx.buf[hd->bctx.count++] = 0; /* pad */ } - else /* need one extra block */ - { - hd->buf[hd->count++] = 0x80; /* pad character */ - while( hd->count < 64 ) - hd->buf[hd->count++] = 0; - md4_write(hd, NULL, 0); /* flush */; - memset(hd->buf, 0, 56 ); /* fill next block with zeroes */ + else /* need one extra block */ + { + hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad character */ + while( hd->bctx.count < 64 ) + hd->bctx.buf[hd->bctx.count++] = 0; + _gcry_md_block_write(hd, NULL, 0); /* flush */; + memset(hd->bctx.buf, 0, 56 ); /* fill next block with zeroes */ } /* append the 64 bit count */ - hd->buf[56] = lsb ; - hd->buf[57] = lsb >> 8; - hd->buf[58] = lsb >> 16; - hd->buf[59] = lsb >> 24; - hd->buf[60] = msb ; - hd->buf[61] = msb >> 8; - hd->buf[62] = msb >> 16; - hd->buf[63] = msb >> 24; - transform( hd, hd->buf ); - _gcry_burn_stack (80+6*sizeof(void*)); - - p = hd->buf; -#ifdef WORDS_BIGENDIAN -#define X(a) do { *p++ = hd->a ; *p++ = hd->a >> 8; \ - *p++ = hd->a >> 16; *p++ = hd->a >> 24; } while(0) -#else /* little endian */ -#define X(a) do { *(u32*)p = (*hd).a ; p += 4; } while(0) -#endif + buf_put_le32(hd->bctx.buf + 56, lsb); + buf_put_le32(hd->bctx.buf + 60, msb); + burn = transform( hd, hd->bctx.buf ); + _gcry_burn_stack (burn); + + p = hd->bctx.buf; +#define X(a) do { *(u32*)p = le_bswap32((*hd).a) ; p += 4; } while(0) X(A); X(B); X(C); @@ -305,7 +253,7 @@ static byte * md4_read (void *context) { MD4_CONTEXT *hd = context; - return hd->buf; + return hd->bctx.buf; } static byte asn[18] = /* Object ID is 1.2.840.113549.2.4 */ @@ -321,8 +269,8 @@ static gcry_md_oid_spec_t oid_spec_md4[] = gcry_md_spec_t _gcry_digest_spec_md4 = { + GCRY_MD_MD4, {0, 0}, "MD4", asn, DIM (asn), oid_spec_md4,16, - md4_init, md4_write, md4_final, md4_read, + md4_init, _gcry_md_block_write, md4_final, md4_read, sizeof (MD4_CONTEXT) }; - diff --git a/plugins/MirOTR/Libgcrypt/cipher/md5.c b/plugins/MirOTR/Libgcrypt/cipher/md5.c index aaf02a8f14..b0187c98eb 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/md5.c +++ b/plugins/MirOTR/Libgcrypt/cipher/md5.c @@ -20,8 +20,8 @@ * * According to the definition of MD5 in RFC 1321 from April 1992. * NOTE: This is *not* the same file as the one from glibc. - * Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. - * heavily modified for GnuPG by Werner Koch <wk@gnupg.org> + * Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. + * heavily modified for GnuPG by Werner Koch <wk@gnupg.org> */ /* Test values: @@ -37,32 +37,38 @@ #include <string.h> #include "g10lib.h" -#include "memory.h" #include "cipher.h" #include "bithelp.h" +#include "bufhelp.h" +#include "hash-common.h" typedef struct { + gcry_md_block_ctx_t bctx; u32 A,B,C,D; /* chaining variables */ - u32 nblocks; - byte buf[64]; - int count; } MD5_CONTEXT; +static unsigned int +transform ( void *ctx, const unsigned char *data ); static void -mir_md5_init( void *context ) +md5_init( void *context, unsigned int flags) { MD5_CONTEXT *ctx = context; + (void)flags; + ctx->A = 0x67452301; ctx->B = 0xefcdab89; ctx->C = 0x98badcfe; ctx->D = 0x10325476; - ctx->nblocks = 0; - ctx->count = 0; + ctx->bctx.nblocks = 0; + ctx->bctx.nblocks_high = 0; + ctx->bctx.count = 0; + ctx->bctx.blocksize = 64; + ctx->bctx.bwrite = transform; } @@ -79,32 +85,20 @@ mir_md5_init( void *context ) /**************** * transform n*64 bytes */ -static void -transform ( MD5_CONTEXT *ctx, const unsigned char *data ) +static unsigned int +transform ( void *c, const unsigned char *data ) { + MD5_CONTEXT *ctx = c; u32 correct_words[16]; register u32 A = ctx->A; register u32 B = ctx->B; register u32 C = ctx->C; register u32 D = ctx->D; u32 *cwp = correct_words; - -#ifdef WORDS_BIGENDIAN - { - int i; - byte *p2, *p1; - for(i=0, p1=data, p2=(byte*)correct_words; i < 16; i++, p2 += 4 ) - { - p2[3] = *p1++; - p2[2] = *p1++; - p2[1] = *p1++; - p2[0] = *p1++; - } - } -#else - memcpy( correct_words, data, 64 ); -#endif + int i; + for ( i = 0; i < 16; i++ ) + correct_words[i] = buf_get_le32(data + i * 4); #define OP(a, b, c, d, s, T) \ do \ @@ -208,51 +202,8 @@ transform ( MD5_CONTEXT *ctx, const unsigned char *data ) ctx->B += B; ctx->C += C; ctx->D += D; -} - - - -/* The routine updates the message-digest context to - * account for the presence of each of the characters inBuf[0..inLen-1] - * in the message whose digest is being computed. - */ -static void -md5_write( void *context, const void *inbuf_arg , size_t inlen) -{ - const unsigned char *inbuf = inbuf_arg; - MD5_CONTEXT *hd = context; - - if( hd->count == 64 ) /* flush the buffer */ - { - transform( hd, hd->buf ); - _gcry_burn_stack (80+6*sizeof(void*)); - hd->count = 0; - hd->nblocks++; - } - if( !inbuf ) - return; - - if( hd->count ) - { - for( ; inlen && hd->count < 64; inlen-- ) - hd->buf[hd->count++] = *inbuf++; - md5_write( hd, NULL, 0 ); - if( !inlen ) - return; - } - _gcry_burn_stack (80+6*sizeof(void*)); - - while( inlen >= 64 ) - { - transform( hd, inbuf ); - hd->count = 0; - hd->nblocks++; - inlen -= 64; - inbuf += 64; - } - for( ; inlen && hd->count < 64; inlen-- ) - hd->buf[hd->count++] = *inbuf++; + return /*burn_stack*/ 80+6*sizeof(void*); } @@ -267,18 +218,24 @@ static void md5_final( void *context) { MD5_CONTEXT *hd = context; - u32 t, msb, lsb; + u32 t, th, msb, lsb; byte *p; - - md5_write(hd, NULL, 0); /* flush */; + unsigned int burn; + + _gcry_md_block_write(hd, NULL, 0); /* flush */; + + t = hd->bctx.nblocks; + if (sizeof t == sizeof hd->bctx.nblocks) + th = hd->bctx.nblocks_high; + else + th = hd->bctx.nblocks >> 32; - t = hd->nblocks; /* multiply by 64 to make a byte count */ lsb = t << 6; - msb = t >> 26; + msb = (th << 6) | (t >> 26); /* add the count */ t = lsb; - if( (lsb += hd->count) < t ) + if( (lsb += hd->bctx.count) < t ) msb++; /* multiply by 8 to make a bit count */ t = lsb; @@ -286,39 +243,28 @@ md5_final( void *context) msb <<= 3; msb |= t >> 29; - if( hd->count < 56 ) /* enough room */ + if( hd->bctx.count < 56 ) /* enough room */ { - hd->buf[hd->count++] = 0x80; /* pad */ - while( hd->count < 56 ) - hd->buf[hd->count++] = 0; /* pad */ + hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad */ + while( hd->bctx.count < 56 ) + hd->bctx.buf[hd->bctx.count++] = 0; /* pad */ } else /* need one extra block */ { - hd->buf[hd->count++] = 0x80; /* pad character */ - while( hd->count < 64 ) - hd->buf[hd->count++] = 0; - md5_write(hd, NULL, 0); /* flush */; - memset(hd->buf, 0, 56 ); /* fill next block with zeroes */ + hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad character */ + while( hd->bctx.count < 64 ) + hd->bctx.buf[hd->bctx.count++] = 0; + _gcry_md_block_write(hd, NULL, 0); /* flush */; + memset(hd->bctx.buf, 0, 56 ); /* fill next block with zeroes */ } /* append the 64 bit count */ - hd->buf[56] = lsb ; - hd->buf[57] = lsb >> 8; - hd->buf[58] = lsb >> 16; - hd->buf[59] = lsb >> 24; - hd->buf[60] = msb ; - hd->buf[61] = msb >> 8; - hd->buf[62] = msb >> 16; - hd->buf[63] = msb >> 24; - transform( hd, hd->buf ); - _gcry_burn_stack (80+6*sizeof(void*)); - - p = hd->buf; -#ifdef WORDS_BIGENDIAN -#define X(a) do { *p++ = hd->a ; *p++ = hd->a >> 8; \ - *p++ = hd->a >> 16; *p++ = hd->a >> 24; } while(0) -#else /* little endian */ -#define X(a) do { *(u32*)p = (*hd).a ; p += 4; } while(0) -#endif + buf_put_le32(hd->bctx.buf + 56, lsb); + buf_put_le32(hd->bctx.buf + 60, msb); + burn = transform( hd, hd->bctx.buf ); + _gcry_burn_stack (burn); + + p = hd->bctx.buf; +#define X(a) do { *(u32*)p = le_bswap32((*hd).a) ; p += 4; } while(0) X(A); X(B); X(C); @@ -331,7 +277,7 @@ static byte * md5_read( void *context ) { MD5_CONTEXT *hd = (MD5_CONTEXT *) context; - return hd->buf; + return hd->bctx.buf; } static byte asn[18] = /* Object ID is 1.2.840.113549.2.5 */ @@ -349,7 +295,8 @@ static gcry_md_oid_spec_t oid_spec_md5[] = gcry_md_spec_t _gcry_digest_spec_md5 = { + GCRY_MD_MD5, {0, 1}, "MD5", asn, DIM (asn), oid_spec_md5, 16, - mir_md5_init, md5_write, md5_final, md5_read, + md5_init, _gcry_md_block_write, md5_final, md5_read, sizeof (MD5_CONTEXT) }; diff --git a/plugins/MirOTR/Libgcrypt/cipher/primegen.c b/plugins/MirOTR/Libgcrypt/cipher/primegen.c index b869bee839..e46bf184e0 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/primegen.c +++ b/plugins/MirOTR/Libgcrypt/cipher/primegen.c @@ -31,7 +31,7 @@ #include "cipher.h" #include "ath.h" -static gcry_mpi_t gen_prime (unsigned int nbits, int secret, int randomlevel, +static gcry_mpi_t gen_prime (unsigned int nbits, int secret, int randomlevel, int (*extra_check)(void *, gcry_mpi_t), void *extra_check_arg); static int check_prime( gcry_mpi_t prime, gcry_mpi_t val_2, int rm_rounds, @@ -132,7 +132,7 @@ static int no_of_small_prime_numbers = DIM (small_prime_numbers) - 1; /* An object and a list to build up a global pool of primes. See save_pool_prime and get_pool_prime. */ -struct primepool_s +struct primepool_s { struct primepool_s *next; gcry_mpi_t prime; /* If this is NULL the entry is not used. */ @@ -141,9 +141,20 @@ struct primepool_s }; struct primepool_s *primepool; /* Mutex used to protect access to the primepool. */ -static ath_mutex_t primepool_lock = ATH_MUTEX_INITIALIZER; +static ath_mutex_t primepool_lock; +gcry_err_code_t +_gcry_primegen_init (void) +{ + gcry_err_code_t ec; + + ec = ath_mutex_init (&primepool_lock); + if (ec) + return gpg_err_code_from_errno (ec); + return ec; +} + /* Save PRIME which has been generated at RANDOMLEVEL for later use. Needs to be called while primepool_lock is being hold. Note @@ -163,12 +174,12 @@ save_pool_prime (gcry_mpi_t prime, gcry_random_level_t randomlevel) /* Remove some of the entries. Our strategy is removing the last third from the list. */ int i; - + for (i=0, item2 = primepool; item2; item2 = item2->next) { if (i >= n/3*2) { - gcry_mpi_release (item2->prime); + _gcry_mpi_release (item2->prime); item2->prime = NULL; if (!item) item = item2; @@ -177,12 +188,12 @@ save_pool_prime (gcry_mpi_t prime, gcry_random_level_t randomlevel) } if (!item) { - item = gcry_calloc (1, sizeof *item); + item = xtrycalloc (1, sizeof *item); if (!item) { /* Out of memory. Silently giving up. */ - gcry_mpi_release (prime); - return; + _gcry_mpi_release (prime); + return; } item->next = primepool; primepool = item; @@ -195,7 +206,7 @@ save_pool_prime (gcry_mpi_t prime, gcry_random_level_t randomlevel) /* Return a prime for the prime pool or NULL if none has been found. The prime needs to match NBITS and randomlevel. This function needs - to be called why the primepool_look is being hold. */ + to be called with the primepool_look is being hold. */ static gcry_mpi_t get_pool_prime (unsigned int nbits, gcry_random_level_t randomlevel) { @@ -359,13 +370,13 @@ prime_generate_internal (int need_q_factor, fbits = (pbits - req_qbits -1) / n; qbits = pbits - n * fbits; } - + if (DBG_CIPHER) log_debug ("gen prime: pbits=%u qbits=%u fbits=%u/%u n=%d\n", pbits, req_qbits, qbits, fbits, n); /* Allocate an integer to old the new prime. */ - prime = gcry_mpi_new (pbits); + prime = mpi_new (pbits); /* Generate first prime factor. */ q = gen_prime (qbits, is_secret, randomlevel, NULL, NULL); @@ -373,9 +384,9 @@ prime_generate_internal (int need_q_factor, /* Generate a specific Q-Factor if requested. */ if (need_q_factor) q_factor = gen_prime (req_qbits, is_secret, randomlevel, NULL, NULL); - + /* Allocate an array to hold all factors + 2 for later usage. */ - factors = gcry_calloc (n + 2, sizeof (*factors)); + factors = xtrycalloc (n + 2, sizeof (*factors)); if (!factors) { err = gpg_err_code_from_errno (errno); @@ -383,7 +394,7 @@ prime_generate_internal (int need_q_factor, } /* Allocate an array to track pool usage. */ - pool_in_use = gcry_malloc (n * sizeof *pool_in_use); + pool_in_use = xtrymalloc (n * sizeof *pool_in_use); if (!pool_in_use) { err = gpg_err_code_from_errno (errno); @@ -391,10 +402,10 @@ prime_generate_internal (int need_q_factor, } for (i=0; i < n; i++) pool_in_use[i] = -1; - + /* Make a pool of 3n+5 primes (this is an arbitrary value). We - require at least 30 primes for are useful selection process. - + require at least 30 primes for are useful selection process. + Fixme: We need to research the best formula for sizing the pool. */ m = n * 3 + 5; @@ -402,7 +413,7 @@ prime_generate_internal (int need_q_factor, m += 5; if (m < 30) m = 30; - pool = gcry_calloc (m , sizeof (*pool)); + pool = xtrycalloc (m , sizeof (*pool)); if (! pool) { err = gpg_err_code_from_errno (errno); @@ -428,7 +439,7 @@ prime_generate_internal (int need_q_factor, } /* Init m_out_of_n(). */ - perms = gcry_calloc (1, m); + perms = xtrycalloc (1, m); if (!perms) { err = gpg_err_code_from_errno (errno); @@ -443,7 +454,7 @@ prime_generate_internal (int need_q_factor, is_locked = 1; for (i = 0; i < n; i++) { - perms[i] = 1; + perms[i] = 1; /* At a maximum we use strong random for the factors. This saves us a lot of entropy. Given that Q and possible Q-factor are also used in the final prime @@ -520,15 +531,15 @@ prime_generate_internal (int need_q_factor, if (i == n) { /* Ran out of permutations: Allocate new primes. */ - gcry_free (perms); + xfree (perms); perms = NULL; progress ('!'); - goto next_try; + goto next_try; } } /* Generate next prime candidate: - p = 2 * q [ * q_factor] * factor_0 * factor_1 * ... * factor_n + 1. + p = 2 * q [ * q_factor] * factor_0 * factor_1 * ... * factor_n + 1. */ mpi_set (prime, q); mpi_mul_ui (prime, prime, 2); @@ -553,7 +564,7 @@ prime_generate_internal (int need_q_factor, } else count1 = 0; - + if (nprime > pbits) { if (++count2 > 20) @@ -575,25 +586,25 @@ prime_generate_internal (int need_q_factor, if (DBG_CIPHER) { progress ('\n'); - log_mpidump ("prime : ", prime); - log_mpidump ("factor q: ", q); + log_mpidump ("prime ", prime); + log_mpidump ("factor q", q); if (need_q_factor) - log_mpidump ("factor q0: ", q_factor); + log_mpidump ("factor q0", q_factor); for (i = 0; i < n; i++) - log_mpidump ("factor pi: ", factors[i]); + log_mpidump ("factor pi", factors[i]); log_debug ("bit sizes: prime=%u, q=%u", mpi_get_nbits (prime), mpi_get_nbits (q)); if (need_q_factor) - log_debug (", q0=%u", mpi_get_nbits (q_factor)); + log_printf (", q0=%u", mpi_get_nbits (q_factor)); for (i = 0; i < n; i++) - log_debug (", p%d=%u", i, mpi_get_nbits (factors[i])); - progress('\n'); + log_printf (", p%d=%u", i, mpi_get_nbits (factors[i])); + log_printf ("\n"); } if (ret_factors) { /* Caller wants the factors. */ - factors_new = gcry_calloc (n + 4, sizeof (*factors_new)); + factors_new = xtrycalloc (n + 4, sizeof (*factors_new)); if (! factors_new) { err = gpg_err_code_from_errno (errno); @@ -603,7 +614,7 @@ prime_generate_internal (int need_q_factor, if (all_factors) { i = 0; - factors_new[i++] = gcry_mpi_set_ui (NULL, 2); + factors_new[i++] = mpi_set_ui (NULL, 2); factors_new[i++] = mpi_copy (q); if (need_q_factor) factors_new[i++] = mpi_copy (q_factor); @@ -624,14 +635,14 @@ prime_generate_internal (int need_q_factor, factors_new[i] = mpi_copy (factors[i]); } } - + if (g) { /* Create a generator (start with 3). */ gcry_mpi_t tmp = mpi_alloc (mpi_get_nlimbs (prime)); gcry_mpi_t b = mpi_alloc (mpi_get_nlimbs (prime)); gcry_mpi_t pmin1 = mpi_alloc (mpi_get_nlimbs (prime)); - + if (need_q_factor) err = GPG_ERR_NOT_IMPLEMENTED; else @@ -644,11 +655,7 @@ prime_generate_internal (int need_q_factor, { mpi_add_ui (g, g, 1); if (DBG_CIPHER) - { - log_debug ("checking g:"); - gcry_mpi_dump (g); - log_printf ("\n"); - } + log_printmpi ("checking g", g); else progress('^'); for (i = 0; i < n + 2; i++) @@ -656,13 +663,13 @@ prime_generate_internal (int need_q_factor, mpi_fdiv_q (tmp, pmin1, factors[i]); /* No mpi_pow(), but it is okay to use this with mod prime. */ - gcry_mpi_powm (b, g, tmp, prime); + mpi_powm (b, g, tmp, prime); if (! mpi_cmp_ui (b, 1)) break; } if (DBG_CIPHER) progress('\n'); - } + } while (i < n + 2); mpi_free (factors[n+1]); @@ -671,7 +678,7 @@ prime_generate_internal (int need_q_factor, mpi_free (pmin1); } } - + if (! DBG_CIPHER) progress ('\n'); @@ -699,13 +706,13 @@ prime_generate_internal (int need_q_factor, if (is_locked && ath_mutex_unlock (&primepool_lock)) err = GPG_ERR_INTERNAL; is_locked = 0; - gcry_free (pool); + xfree (pool); } - gcry_free (pool_in_use); + xfree (pool_in_use); if (factors) - gcry_free (factors); /* Factors are shallow copies. */ + xfree (factors); /* Factors are shallow copies. */ if (perms) - gcry_free (perms); + xfree (perms); mpi_free (val_2); mpi_free (q); @@ -723,7 +730,7 @@ prime_generate_internal (int need_q_factor, { for (i = 0; factors_new[i]; i++) mpi_free (factors_new[i]); - gcry_free (factors_new); + xfree (factors_new); } mpi_free (prime); } @@ -733,24 +740,27 @@ prime_generate_internal (int need_q_factor, /* Generate a prime used for discrete logarithm algorithms; i.e. this - prime will be public and no strong random is required. */ -gcry_mpi_t + prime will be public and no strong random is required. On success + R_PRIME receives a new MPI with the prime. On error R_PRIME is set + to NULL and an error code is returned. If RET_FACTORS is not NULL + it is set to an allocated array of factors on success or to NULL on + error. */ +gcry_err_code_t _gcry_generate_elg_prime (int mode, unsigned pbits, unsigned qbits, - gcry_mpi_t g, gcry_mpi_t **ret_factors) + gcry_mpi_t g, + gcry_mpi_t *r_prime, gcry_mpi_t **ret_factors) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_mpi_t prime = NULL; - - err = prime_generate_internal ((mode == 1), &prime, pbits, qbits, g, - ret_factors, GCRY_WEAK_RANDOM, 0, 0, - NULL, NULL); - - return prime; + *r_prime = NULL; + if (ret_factors) + *ret_factors = NULL; + return prime_generate_internal ((mode == 1), r_prime, pbits, qbits, g, + ret_factors, GCRY_WEAK_RANDOM, 0, 0, + NULL, NULL); } static gcry_mpi_t -gen_prime (unsigned int nbits, int secret, int randomlevel, +gen_prime (unsigned int nbits, int secret, int randomlevel, int (*extra_check)(void *, gcry_mpi_t), void *extra_check_arg) { gcry_mpi_t prime, ptest, pminus1, val_2, val_3, result; @@ -758,18 +768,18 @@ gen_prime (unsigned int nbits, int secret, int randomlevel, unsigned int x, step; unsigned int count1, count2; int *mods; - + /* if ( DBG_CIPHER ) */ /* log_debug ("generate a prime of %u bits ", nbits ); */ if (nbits < 16) log_fatal ("can't generate a prime with less than %d bits\n", 16); - mods = gcry_xmalloc( no_of_small_prime_numbers * sizeof *mods ); + mods = xmalloc (no_of_small_prime_numbers * sizeof *mods); /* Make nbits fit into gcry_mpi_t implementation. */ val_2 = mpi_alloc_set_ui( 2 ); val_3 = mpi_alloc_set_ui( 3); - prime = secret? gcry_mpi_snew ( nbits ): gcry_mpi_new ( nbits ); + prime = secret? mpi_snew (nbits): mpi_new (nbits); result = mpi_alloc_like( prime ); pminus1= mpi_alloc_like( prime ); ptest = mpi_alloc_like( prime ); @@ -777,10 +787,10 @@ gen_prime (unsigned int nbits, int secret, int randomlevel, for (;;) { /* try forvever */ int dotcount=0; - + /* generate a random number */ - gcry_mpi_randomize( prime, nbits, randomlevel ); - + _gcry_mpi_randomize( prime, nbits, randomlevel ); + /* Set high order bit to 1, set low order bit to 1. If we are generating a secret prime we are most probably doing that for RSA, to make sure that the modulus does have the @@ -789,17 +799,17 @@ gen_prime (unsigned int nbits, int secret, int randomlevel, if (secret) mpi_set_bit (prime, nbits-2); mpi_set_bit(prime, 0); - + /* Calculate all remainders. */ for (i=0; (x = small_prime_numbers[i]); i++ ) mods[i] = mpi_fdiv_r_ui(NULL, prime, x); - + /* Now try some primes starting with prime. */ - for(step=0; step < 20000; step += 2 ) + for(step=0; step < 20000; step += 2 ) { /* Check against all the small primes we have in mods. */ count1++; - for (i=0; (x = small_prime_numbers[i]); i++ ) + for (i=0; (x = small_prime_numbers[i]); i++ ) { while ( mods[i] + step >= x ) mods[i] -= x; @@ -808,15 +818,15 @@ gen_prime (unsigned int nbits, int secret, int randomlevel, } if ( x ) continue; /* Found a multiple of an already known prime. */ - + mpi_add_ui( ptest, prime, step ); /* Do a fast Fermat test now. */ count2++; mpi_sub_ui( pminus1, ptest, 1); - gcry_mpi_powm( result, val_2, pminus1, ptest ); + mpi_powm( result, val_2, pminus1, ptest ); if ( !mpi_cmp_ui( result, 1 ) ) - { + { /* Not composite, perform stronger tests */ if (is_prime(ptest, 5, &count2 )) { @@ -828,21 +838,21 @@ gen_prime (unsigned int nbits, int secret, int randomlevel, } if (extra_check && extra_check (extra_check_arg, ptest)) - { + { /* The extra check told us that this prime is not of the caller's taste. */ progress ('/'); } else - { + { /* Got it. */ mpi_free(val_2); mpi_free(val_3); mpi_free(result); mpi_free(pminus1); mpi_free(prime); - gcry_free(mods); - return ptest; + xfree(mods); + return ptest; } } } @@ -872,7 +882,7 @@ check_prime( gcry_mpi_t prime, gcry_mpi_t val_2, int rm_rounds, for (i=0; (x = small_prime_numbers[i]); i++ ) { if ( mpi_divisible_ui( prime, x ) ) - return 0; + return !mpi_cmp_ui (prime, x); } /* A quick Fermat test. */ @@ -880,10 +890,10 @@ check_prime( gcry_mpi_t prime, gcry_mpi_t val_2, int rm_rounds, gcry_mpi_t result = mpi_alloc_like( prime ); gcry_mpi_t pminus1 = mpi_alloc_like( prime ); mpi_sub_ui( pminus1, prime, 1); - gcry_mpi_powm( result, val_2, pminus1, prime ); + mpi_powm( result, val_2, pminus1, prime ); mpi_free( pminus1 ); if ( mpi_cmp_ui( result, 1 ) ) - { + { /* Is composite. */ mpi_free( result ); progress('.'); @@ -924,7 +934,7 @@ is_prime (gcry_mpi_t n, int steps, unsigned int *count) unsigned nbits = mpi_get_nbits( n ); if (steps < 5) /* Make sure that we do at least 5 rounds. */ - steps = 5; + steps = 5; mpi_sub_ui( nminus1, n, 1 ); @@ -942,7 +952,7 @@ is_prime (gcry_mpi_t n, int steps, unsigned int *count) } else { - gcry_mpi_randomize( x, nbits, GCRY_WEAK_RANDOM ); + _gcry_mpi_randomize( x, nbits, GCRY_WEAK_RANDOM ); /* Make sure that the number is smaller than the prime and keep the randomness of the high bit. */ @@ -957,12 +967,12 @@ is_prime (gcry_mpi_t n, int steps, unsigned int *count) } gcry_assert (mpi_cmp (x, nminus1) < 0 && mpi_cmp_ui (x, 1) > 0); } - gcry_mpi_powm ( y, x, q, n); + mpi_powm ( y, x, q, n); if ( mpi_cmp_ui(y, 1) && mpi_cmp( y, nminus1 ) ) { for ( j=1; j < k && mpi_cmp( y, nminus1 ); j++ ) { - gcry_mpi_powm(y, y, a2, n); + mpi_powm(y, y, a2, n); if( !mpi_cmp_ui( y, 1 ) ) goto leave; /* Not a prime. */ } @@ -988,7 +998,7 @@ is_prime (gcry_mpi_t n, int steps, unsigned int *count) /* Given ARRAY of size N with M elements set to true produce a modified array with the next permutation of M elements. Note, that ARRAY is used in a one-bit-per-byte approach. To detected the last - permutation it is useful to intialize the array with the first M + permutation it is useful to initialize the array with the first M element set to true and use this test: m_out_of_n (array, m, n); for (i = j = 0; i < n && j < m; i++) @@ -996,7 +1006,7 @@ is_prime (gcry_mpi_t n, int steps, unsigned int *count) j++; if (j == m) goto ready; - + This code is based on the algorithm 452 from the "Collected Algorithms From ACM, Volume II" by C. N. Liu and D. T. Tang. */ @@ -1010,7 +1020,7 @@ m_out_of_n ( char *array, int m, int n ) /* Need to handle this simple case separately. */ if( m == 1 ) - { + { for (i=0; i < n; i++ ) { if ( array[i] ) @@ -1060,7 +1070,7 @@ m_out_of_n ( char *array, int m, int n ) else k1 = k2 + 1; } - else + else { /* M is even. */ if( !array[n-1] ) @@ -1069,7 +1079,7 @@ m_out_of_n ( char *array, int m, int n ) k2 = k1 + 1; goto leave; } - + if( !(j1 & 1) ) { k1 = n - j1; @@ -1080,7 +1090,7 @@ m_out_of_n ( char *array, int m, int n ) } scan: jp = n - j1 - 1; - for (i=1; i <= jp; i++ ) + for (i=1; i <= jp; i++ ) { i1 = jp + 2 - i; if( array[i1-1] ) @@ -1114,135 +1124,131 @@ m_out_of_n ( char *array, int m, int n ) non-zero, allocate a new, NULL-terminated array holding the prime factors and store it in FACTORS. FLAGS might be used to influence the prime number generation process. */ -gcry_error_t -gcry_prime_generate (gcry_mpi_t *prime, unsigned int prime_bits, - unsigned int factor_bits, gcry_mpi_t **factors, - gcry_prime_check_func_t cb_func, void *cb_arg, - gcry_random_level_t random_level, - unsigned int flags) +gcry_err_code_t +_gcry_prime_generate (gcry_mpi_t *prime, unsigned int prime_bits, + unsigned int factor_bits, gcry_mpi_t **factors, + gcry_prime_check_func_t cb_func, void *cb_arg, + gcry_random_level_t random_level, + unsigned int flags) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_err_code_t rc = 0; gcry_mpi_t *factors_generated = NULL; gcry_mpi_t prime_generated = NULL; unsigned int mode = 0; if (!prime) - return gpg_error (GPG_ERR_INV_ARG); - *prime = NULL; + return GPG_ERR_INV_ARG; + *prime = NULL; if (flags & GCRY_PRIME_FLAG_SPECIAL_FACTOR) mode = 1; /* Generate. */ - err = prime_generate_internal ((mode==1), &prime_generated, prime_bits, - factor_bits, NULL, - factors? &factors_generated : NULL, - random_level, flags, 1, - cb_func, cb_arg); + rc = prime_generate_internal ((mode==1), &prime_generated, prime_bits, + factor_bits, NULL, + factors? &factors_generated : NULL, + random_level, flags, 1, + cb_func, cb_arg); - if (! err) - if (cb_func) - { - /* Additional check. */ - if ( !cb_func (cb_arg, GCRY_PRIME_CHECK_AT_FINISH, prime_generated)) - { - /* Failed, deallocate resources. */ - unsigned int i; + if (!rc && cb_func) + { + /* Additional check. */ + if ( !cb_func (cb_arg, GCRY_PRIME_CHECK_AT_FINISH, prime_generated)) + { + /* Failed, deallocate resources. */ + unsigned int i; - mpi_free (prime_generated); - if (factors) - { - for (i = 0; factors_generated[i]; i++) - mpi_free (factors_generated[i]); - gcry_free (factors_generated); - } - err = GPG_ERR_GENERAL; - } - } + mpi_free (prime_generated); + if (factors) + { + for (i = 0; factors_generated[i]; i++) + mpi_free (factors_generated[i]); + xfree (factors_generated); + } + rc = GPG_ERR_GENERAL; + } + } - if (! err) + if (!rc) { if (factors) *factors = factors_generated; *prime = prime_generated; } - return gcry_error (err); + return rc; } -/* Check wether the number X is prime. */ -gcry_error_t -gcry_prime_check (gcry_mpi_t x, unsigned int flags) +/* Check whether the number X is prime. */ +gcry_err_code_t +_gcry_prime_check (gcry_mpi_t x, unsigned int flags) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_mpi_t val_2 = mpi_alloc_set_ui (2); /* Used by the Fermat test. */ - (void)flags; + switch (mpi_cmp_ui (x, 2)) + { + case 0: return 0; /* 2 is a prime */ + case -1: return GPG_ERR_NO_PRIME; /* Only numbers > 1 are primes. */ + } + /* We use 64 rounds because the prime we are going to test is not guaranteed to be a random one. */ - if (! check_prime (x, val_2, 64, NULL, NULL)) - err = GPG_ERR_NO_PRIME; - - mpi_free (val_2); + if (check_prime (x, mpi_const (MPI_C_TWO), 64, NULL, NULL)) + return 0; - return gcry_error (err); + return GPG_ERR_NO_PRIME; } /* Find a generator for PRIME where the factorization of (prime-1) is in the NULL terminated array FACTORS. Return the generator as a newly allocated MPI in R_G. If START_G is not NULL, use this as s atart for the search. Returns 0 on success.*/ -gcry_error_t -gcry_prime_group_generator (gcry_mpi_t *r_g, - gcry_mpi_t prime, gcry_mpi_t *factors, - gcry_mpi_t start_g) +gcry_err_code_t +_gcry_prime_group_generator (gcry_mpi_t *r_g, + gcry_mpi_t prime, gcry_mpi_t *factors, + gcry_mpi_t start_g) { - gcry_mpi_t tmp = gcry_mpi_new (0); - gcry_mpi_t b = gcry_mpi_new (0); - gcry_mpi_t pmin1 = gcry_mpi_new (0); - gcry_mpi_t g = start_g? gcry_mpi_copy (start_g) : gcry_mpi_set_ui (NULL, 3); + gcry_mpi_t tmp = mpi_new (0); + gcry_mpi_t b = mpi_new (0); + gcry_mpi_t pmin1 = mpi_new (0); + gcry_mpi_t g = start_g? mpi_copy (start_g) : mpi_set_ui (NULL, 3); int first = 1; int i, n; if (!factors || !r_g || !prime) - return gpg_error (GPG_ERR_INV_ARG); - *r_g = NULL; + return GPG_ERR_INV_ARG; + *r_g = NULL; for (n=0; factors[n]; n++) ; if (n < 2) - return gpg_error (GPG_ERR_INV_ARG); + return GPG_ERR_INV_ARG; - /* Extra sanity check - usually disabled. */ + /* Extra sanity check - usually disabled. */ /* mpi_set (tmp, factors[0]); */ /* for(i = 1; i < n; i++) */ /* mpi_mul (tmp, tmp, factors[i]); */ /* mpi_add_ui (tmp, tmp, 1); */ /* if (mpi_cmp (prime, tmp)) */ /* return gpg_error (GPG_ERR_INV_ARG); */ - - gcry_mpi_sub_ui (pmin1, prime, 1); - do + + mpi_sub_ui (pmin1, prime, 1); + do { if (first) first = 0; else - gcry_mpi_add_ui (g, g, 1); - + mpi_add_ui (g, g, 1); + if (DBG_CIPHER) - { - log_debug ("checking g:"); - gcry_mpi_dump (g); - log_debug ("\n"); - } + log_printmpi ("checking g", g); else progress('^'); - + for (i = 0; i < n; i++) { mpi_fdiv_q (tmp, pmin1, factors[i]); - gcry_mpi_powm (b, g, tmp, prime); + mpi_powm (b, g, tmp, prime); if (! mpi_cmp_ui (b, 1)) break; } @@ -1250,26 +1256,26 @@ gcry_prime_group_generator (gcry_mpi_t *r_g, progress('\n'); } while (i < n); - - gcry_mpi_release (tmp); - gcry_mpi_release (b); - gcry_mpi_release (pmin1); - *r_g = g; - return 0; + _gcry_mpi_release (tmp); + _gcry_mpi_release (b); + _gcry_mpi_release (pmin1); + *r_g = g; + + return 0; } /* Convenience function to release the factors array. */ void -gcry_prime_release_factors (gcry_mpi_t *factors) +_gcry_prime_release_factors (gcry_mpi_t *factors) { if (factors) { int i; - + for (i=0; factors[i]; i++) mpi_free (factors[i]); - gcry_free (factors); + xfree (factors); } } @@ -1279,11 +1285,11 @@ gcry_prime_release_factors (gcry_mpi_t *factors) static gcry_mpi_t find_x931_prime (const gcry_mpi_t pfirst) { - gcry_mpi_t val_2 = mpi_alloc_set_ui (2); + gcry_mpi_t val_2 = mpi_alloc_set_ui (2); gcry_mpi_t prime; - - prime = gcry_mpi_copy (pfirst); - /* If P is even add 1. */ + + prime = mpi_copy (pfirst); + /* If P is even add 1. */ mpi_set_bit (prime, 0); /* We use 64 Rabin-Miller rounds which is better and thus @@ -1299,7 +1305,7 @@ find_x931_prime (const gcry_mpi_t pfirst) } -/* Generate a prime using the algorithm from X9.31 appendix B.4. +/* Generate a prime using the algorithm from X9.31 appendix B.4. This function requires that the provided public exponent E is odd. XP, XP1 and XP2 are the seed values. All values are mandatory. @@ -1308,7 +1314,7 @@ find_x931_prime (const gcry_mpi_t pfirst) internal values P1 and P2 are saved at these addresses. On error NULL is returned. */ gcry_mpi_t -_gcry_derive_x931_prime (const gcry_mpi_t xp, +_gcry_derive_x931_prime (const gcry_mpi_t xp, const gcry_mpi_t xp1, const gcry_mpi_t xp2, const gcry_mpi_t e, gcry_mpi_t *r_p1, gcry_mpi_t *r_p2) @@ -1327,20 +1333,20 @@ _gcry_derive_x931_prime (const gcry_mpi_t xp, { gcry_mpi_t r1, tmp; - + /* r1 = (p2^{-1} mod p1)p2 - (p1^{-1} mod p2) */ tmp = mpi_alloc_like (p1); mpi_invm (tmp, p2, p1); mpi_mul (tmp, tmp, p2); r1 = tmp; - + tmp = mpi_alloc_like (p2); mpi_invm (tmp, p1, p2); mpi_mul (tmp, tmp, p1); mpi_sub (r1, r1, tmp); /* Fixup a negative value. */ - if (mpi_is_neg (r1)) + if (mpi_has_sign (r1)) mpi_add (r1, r1, p1p2); /* yp0 = xp + (r1 - xp mod p1*p2) */ @@ -1350,7 +1356,7 @@ _gcry_derive_x931_prime (const gcry_mpi_t xp, mpi_free (r1); /* Fixup a negative value. */ - if (mpi_cmp (yp0, xp) < 0 ) + if (mpi_cmp (yp0, xp) < 0 ) mpi_add (yp0, yp0, p1p2); } @@ -1378,15 +1384,15 @@ _gcry_derive_x931_prime (const gcry_mpi_t xp, */ { - gcry_mpi_t val_2 = mpi_alloc_set_ui (2); + gcry_mpi_t val_2 = mpi_alloc_set_ui (2); gcry_mpi_t gcdtmp = mpi_alloc_like (yp0); int gcdres; - + mpi_sub_ui (p1p2, p1p2, 1); /* Adjust for loop body. */ mpi_sub_ui (yp0, yp0, 1); /* Ditto. */ for (;;) { - gcdres = gcry_mpi_gcd (gcdtmp, e, yp0); + gcdres = mpi_gcd (gcdtmp, e, yp0); mpi_add_ui (yp0, yp0, 1); if (!gcdres) progress ('/'); /* gcd (e, yp0-1) != 1 */ @@ -1453,9 +1459,9 @@ _gcry_generate_fips186_2_prime (unsigned int pbits, unsigned int qbits, ; /* No seed value given: We are asked to generate it. */ else if (!seed || seedlen < qbits/8) return GPG_ERR_INV_ARG; - + /* Allocate a buffer to later compute SEED+some_increment. */ - seed_plus = gcry_malloc (seedlen < 20? 20:seedlen); + seed_plus = xtrymalloc (seedlen < 20? 20:seedlen); if (!seed_plus) { ec = gpg_err_code_from_syserror (); @@ -1465,10 +1471,10 @@ _gcry_generate_fips186_2_prime (unsigned int pbits, unsigned int qbits, val_2 = mpi_alloc_set_ui (2); value_n = (pbits - 1) / qbits; value_b = (pbits - 1) - value_n * qbits; - value_w = gcry_mpi_new (pbits); - value_x = gcry_mpi_new (pbits); + value_w = mpi_new (pbits); + value_x = mpi_new (pbits); - restart: + restart: /* Generate Q. */ for (;;) { @@ -1476,10 +1482,10 @@ _gcry_generate_fips186_2_prime (unsigned int pbits, unsigned int qbits, if (!seed) { seedlen = sizeof seed_help_buffer; - gcry_create_nonce (seed_help_buffer, seedlen); + _gcry_create_nonce (seed_help_buffer, seedlen); seed = seed_help_buffer; } - + /* Step 2: U = sha1(seed) ^ sha1((seed+1) mod 2^{qbits}) */ memcpy (seed_plus, seed, seedlen); for (i=seedlen-1; i >= 0; i--) @@ -1488,20 +1494,20 @@ _gcry_generate_fips186_2_prime (unsigned int pbits, unsigned int qbits, if (seed_plus[i]) break; } - gcry_md_hash_buffer (GCRY_MD_SHA1, value_u, seed, seedlen); - gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen); + _gcry_md_hash_buffer (GCRY_MD_SHA1, value_u, seed, seedlen); + _gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen); for (i=0; i < sizeof value_u; i++) value_u[i] ^= digest[i]; - + /* Step 3: Form q from U */ - gcry_mpi_release (prime_q); prime_q = NULL; - ec = gpg_err_code (gcry_mpi_scan (&prime_q, GCRYMPI_FMT_USG, - value_u, sizeof value_u, NULL)); + _gcry_mpi_release (prime_q); prime_q = NULL; + ec = _gcry_mpi_scan (&prime_q, GCRYMPI_FMT_USG, + value_u, sizeof value_u, NULL); if (ec) goto leave; mpi_set_highbit (prime_q, qbits-1 ); mpi_set_bit (prime_q, 0); - + /* Step 4: Test whether Q is prime using 64 round of Rabin-Miller. */ if (check_prime (prime_q, val_2, 64, NULL, NULL)) break; /* Yes, Q is prime. */ @@ -1509,21 +1515,21 @@ _gcry_generate_fips186_2_prime (unsigned int pbits, unsigned int qbits, /* Step 5. */ seed = NULL; /* Force a new seed at Step 1. */ } - + /* Step 6. Note that we do no use an explicit offset but increment SEED_PLUS accordingly. SEED_PLUS is currently SEED+1. */ counter = 0; /* Generate P. */ - prime_p = gcry_mpi_new (pbits); + prime_p = mpi_new (pbits); for (;;) { - /* Step 7: For k = 0,...n let - V_k = sha1(seed+offset+k) mod 2^{qbits} - Step 8: W = V_0 + V_1*2^160 + - ... + /* Step 7: For k = 0,...n let + V_k = sha1(seed+offset+k) mod 2^{qbits} + Step 8: W = V_0 + V_1*2^160 + + ... + V_{n-1}*2^{(n-1)*160} - + (V_{n} mod 2^b)*2^{n*160} + + (V_{n} mod 2^b)*2^{n*160} */ mpi_set_ui (value_w, 0); for (value_k=0; value_k <= value_n; value_k++) @@ -1541,11 +1547,11 @@ _gcry_generate_fips186_2_prime (unsigned int pbits, unsigned int qbits, if (seed_plus[i]) break; } - gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen); - - gcry_mpi_release (tmpval); tmpval = NULL; - ec = gpg_err_code (gcry_mpi_scan (&tmpval, GCRYMPI_FMT_USG, - digest, sizeof digest, NULL)); + _gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen); + + _gcry_mpi_release (tmpval); tmpval = NULL; + ec = _gcry_mpi_scan (&tmpval, GCRYMPI_FMT_USG, + digest, sizeof digest, NULL); if (ec) goto leave; if (value_k == value_n) @@ -1607,13 +1613,13 @@ _gcry_generate_fips186_2_prime (unsigned int pbits, unsigned int qbits, leave: - gcry_mpi_release (tmpval); - gcry_mpi_release (value_x); - gcry_mpi_release (value_w); - gcry_mpi_release (prime_p); - gcry_mpi_release (prime_q); - gcry_free (seed_plus); - gcry_mpi_release (val_2); + _gcry_mpi_release (tmpval); + _gcry_mpi_release (value_x); + _gcry_mpi_release (value_w); + _gcry_mpi_release (prime_p); + _gcry_mpi_release (prime_q); + xfree (seed_plus); + _gcry_mpi_release (val_2); return ec; } @@ -1631,7 +1637,7 @@ _gcry_generate_fips186_2_prime (unsigned int pbits, unsigned int qbits, value is stored at R_COUNTER and the seed actually used for generation is stored at R_SEED and R_SEEDVALUE. The hash algorithm used is stored at R_HASHALGO. - + Note that this function is very similar to the fips186_2 code. Due to the minor differences, other buffer sizes and for documentarion, we use a separate function. @@ -1652,7 +1658,7 @@ _gcry_generate_fips186_3_prime (unsigned int pbits, unsigned int qbits, gcry_mpi_t tmpval = NULL; /* Helper variable. */ int hashalgo; /* The id of the Approved Hash Function. */ int i; - + unsigned char value_u[256/8]; int value_n, value_b, value_j; int counter; @@ -1678,11 +1684,11 @@ _gcry_generate_fips186_3_prime (unsigned int pbits, unsigned int qbits, return GPG_ERR_INV_KEYLEN; /* Also check that the hash algorithm is available. */ - ec = gpg_err_code (gcry_md_test_algo (hashalgo)); + ec = _gcry_md_test_algo (hashalgo); if (ec) return ec; gcry_assert (qbits/8 <= sizeof digest); - gcry_assert (gcry_md_get_algo_dlen (hashalgo) == qbits/8); + gcry_assert (_gcry_md_get_algo_dlen (hashalgo) == qbits/8); /* Step 2: Check seedlen. */ @@ -1690,26 +1696,26 @@ _gcry_generate_fips186_3_prime (unsigned int pbits, unsigned int qbits, ; /* No seed value given: We are asked to generate it. */ else if (!seed || seedlen < qbits/8) return GPG_ERR_INV_ARG; - + /* Allocate a buffer to later compute SEED+some_increment and a few helper variables. */ - seed_plus = gcry_malloc (seedlen < sizeof seed_help_buffer? - sizeof seed_help_buffer : seedlen); + seed_plus = xtrymalloc (seedlen < sizeof seed_help_buffer? + sizeof seed_help_buffer : seedlen); if (!seed_plus) { ec = gpg_err_code_from_syserror (); goto leave; } val_2 = mpi_alloc_set_ui (2); - value_w = gcry_mpi_new (pbits); - value_x = gcry_mpi_new (pbits); + value_w = mpi_new (pbits); + value_x = mpi_new (pbits); /* Step 3: n = \lceil L / outlen \rceil - 1 */ value_n = (pbits + qbits - 1) / qbits - 1; /* Step 4: b = L - 1 - (n * outlen) */ value_b = pbits - 1 - (value_n * qbits); - restart: + restart: /* Generate Q. */ for (;;) { @@ -1718,12 +1724,12 @@ _gcry_generate_fips186_3_prime (unsigned int pbits, unsigned int qbits, { seedlen = qbits/8; gcry_assert (seedlen <= sizeof seed_help_buffer); - gcry_create_nonce (seed_help_buffer, seedlen); + _gcry_create_nonce (seed_help_buffer, seedlen); seed = seed_help_buffer; } - + /* Step 6: U = hash(seed) */ - gcry_md_hash_buffer (hashalgo, value_u, seed, seedlen); + _gcry_md_hash_buffer (hashalgo, value_u, seed, seedlen); /* Step 7: q = 2^{N-1} + U + 1 - (U mod 2) */ if ( !(value_u[qbits/8-1] & 0x01) ) @@ -1735,13 +1741,13 @@ _gcry_generate_fips186_3_prime (unsigned int pbits, unsigned int qbits, break; } } - gcry_mpi_release (prime_q); prime_q = NULL; - ec = gpg_err_code (gcry_mpi_scan (&prime_q, GCRYMPI_FMT_USG, - value_u, sizeof value_u, NULL)); + _gcry_mpi_release (prime_q); prime_q = NULL; + ec = _gcry_mpi_scan (&prime_q, GCRYMPI_FMT_USG, + value_u, sizeof value_u, NULL); if (ec) goto leave; mpi_set_highbit (prime_q, qbits-1 ); - + /* Step 8: Test whether Q is prime using 64 round of Rabin-Miller. According to table C.1 this is sufficient for all supported prime sizes (i.e. up 3072/256). */ @@ -1751,22 +1757,22 @@ _gcry_generate_fips186_3_prime (unsigned int pbits, unsigned int qbits, /* Step 8. */ seed = NULL; /* Force a new seed at Step 5. */ } - + /* Step 11. Note that we do no use an explicit offset but increment SEED_PLUS accordingly. */ memcpy (seed_plus, seed, seedlen); counter = 0; /* Generate P. */ - prime_p = gcry_mpi_new (pbits); + prime_p = mpi_new (pbits); for (;;) { - /* Step 11.1: For j = 0,...n let - V_j = hash(seed+offset+j) - Step 11.2: W = V_0 + V_1*2^outlen + - ... + /* Step 11.1: For j = 0,...n let + V_j = hash(seed+offset+j) + Step 11.2: W = V_0 + V_1*2^outlen + + ... + V_{n-1}*2^{(n-1)*outlen} - + (V_{n} mod 2^b)*2^{n*outlen} + + (V_{n} mod 2^b)*2^{n*outlen} */ mpi_set_ui (value_w, 0); for (value_j=0; value_j <= value_n; value_j++) @@ -1782,11 +1788,11 @@ _gcry_generate_fips186_3_prime (unsigned int pbits, unsigned int qbits, if (seed_plus[i]) break; } - gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen); - - gcry_mpi_release (tmpval); tmpval = NULL; - ec = gpg_err_code (gcry_mpi_scan (&tmpval, GCRYMPI_FMT_USG, - digest, sizeof digest, NULL)); + _gcry_md_hash_buffer (GCRY_MD_SHA1, digest, seed_plus, seedlen); + + _gcry_mpi_release (tmpval); tmpval = NULL; + ec = _gcry_mpi_scan (&tmpval, GCRYMPI_FMT_USG, + digest, sizeof digest, NULL); if (ec) goto leave; if (value_j == value_n) @@ -1813,7 +1819,7 @@ _gcry_generate_fips186_3_prime (unsigned int pbits, unsigned int qbits, if (mpi_get_nbits (prime_p) >= pbits-1 && check_prime (prime_p, val_2, 64, NULL, NULL) ) break; /* Yes, P is prime, continue with Step 15. */ - + /* Step 11.9: counter = counter + 1, offset = offset + n + 1. If counter >= 4L goto Step 5. */ counter++; @@ -1824,9 +1830,9 @@ _gcry_generate_fips186_3_prime (unsigned int pbits, unsigned int qbits, /* Step 12: Save p, q, counter and seed. */ log_debug ("fips186-3 pbits p=%u q=%u counter=%d\n", mpi_get_nbits (prime_p), mpi_get_nbits (prime_q), counter); - log_printhex("fips186-3 seed:", seed, seedlen); - log_mpidump ("fips186-3 prime p", prime_p); - log_mpidump ("fips186-3 prime q", prime_q); + log_printhex ("fips186-3 seed", seed, seedlen); + log_printmpi ("fips186-3 p", prime_p); + log_printmpi ("fips186-3 q", prime_q); if (r_q) { *r_q = prime_q; @@ -1850,13 +1856,12 @@ _gcry_generate_fips186_3_prime (unsigned int pbits, unsigned int qbits, *r_hashalgo = hashalgo; leave: - gcry_mpi_release (tmpval); - gcry_mpi_release (value_x); - gcry_mpi_release (value_w); - gcry_mpi_release (prime_p); - gcry_mpi_release (prime_q); - gcry_free (seed_plus); - gcry_mpi_release (val_2); + _gcry_mpi_release (tmpval); + _gcry_mpi_release (value_x); + _gcry_mpi_release (value_w); + _gcry_mpi_release (prime_p); + _gcry_mpi_release (prime_q); + xfree (seed_plus); + _gcry_mpi_release (val_2); return ec; } - diff --git a/plugins/MirOTR/Libgcrypt/cipher/pubkey-internal.h b/plugins/MirOTR/Libgcrypt/cipher/pubkey-internal.h new file mode 100644 index 0000000000..193248c327 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/pubkey-internal.h @@ -0,0 +1,100 @@ +/* pubkey-internal.h - Internal defs for pubkey.c + * Copyright (C) 2013 g10 code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef GCRY_PUBKEY_INTERNAL_H +#define GCRY_PUBKEY_INTERNAL_H + +/*-- pubkey-util.c --*/ +gpg_err_code_t _gcry_pk_util_parse_flaglist (gcry_sexp_t list, + int *r_flags, + enum pk_encoding *r_encoding); +gpg_err_code_t _gcry_pk_util_get_nbits (gcry_sexp_t list, + unsigned int *r_nbits); +gpg_err_code_t _gcry_pk_util_get_rsa_use_e (gcry_sexp_t list, + unsigned long *r_e); +gpg_err_code_t _gcry_pk_util_preparse_sigval (gcry_sexp_t s_sig, + const char **algo_names, + gcry_sexp_t *r_parms, + int *r_eccflags); +gpg_err_code_t _gcry_pk_util_preparse_encval (gcry_sexp_t sexp, + const char **algo_names, + gcry_sexp_t *r_parms, + struct pk_encoding_ctx *ctx); +void _gcry_pk_util_init_encoding_ctx (struct pk_encoding_ctx *ctx, + enum pk_operation op, + unsigned int nbits); +void _gcry_pk_util_free_encoding_ctx (struct pk_encoding_ctx *ctx); +gcry_err_code_t _gcry_pk_util_data_to_mpi (gcry_sexp_t input, + gcry_mpi_t *ret_mpi, + struct pk_encoding_ctx *ctx); + + + +/*-- rsa-common.c --*/ +gpg_err_code_t +_gcry_rsa_pkcs1_encode_for_enc (gcry_mpi_t *r_result, unsigned int nbits, + const unsigned char *value, size_t valuelen, + const unsigned char *random_override, + size_t random_override_len); +gpg_err_code_t +_gcry_rsa_pkcs1_decode_for_enc (unsigned char **r_result, size_t *r_resultlen, + unsigned int nbits, gcry_mpi_t value); +gpg_err_code_t +_gcry_rsa_pkcs1_encode_for_sig (gcry_mpi_t *r_result, unsigned int nbits, + const unsigned char *value, size_t valuelen, + int algo); +gpg_err_code_t +_gcry_rsa_oaep_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo, + const unsigned char *value, size_t valuelen, + const unsigned char *label, size_t labellen, + const void *random_override, size_t random_override_len); +gpg_err_code_t +_gcry_rsa_oaep_decode (unsigned char **r_result, size_t *r_resultlen, + unsigned int nbits, int algo, + gcry_mpi_t value, + const unsigned char *label, size_t labellen); +gpg_err_code_t +_gcry_rsa_pss_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo, + const unsigned char *value, size_t valuelen, int saltlen, + const void *random_override, size_t random_override_len); +gpg_err_code_t +_gcry_rsa_pss_verify (gcry_mpi_t value, gcry_mpi_t encoded, + unsigned int nbits, int algo, size_t saltlen); + + + +/*-- dsa-common.c --*/ +gcry_mpi_t _gcry_dsa_gen_k (gcry_mpi_t q, int security_level); +gpg_err_code_t _gcry_dsa_gen_rfc6979_k (gcry_mpi_t *r_k, + gcry_mpi_t dsa_q, gcry_mpi_t dsa_x, + const unsigned char *h1, + unsigned int h1len, + int halgo, + unsigned int extraloops); + +gpg_err_code_t _gcry_dsa_normalize_hash (gcry_mpi_t input, + gcry_mpi_t *out, + unsigned int qbits); + +/*-- ecc.c --*/ +gpg_err_code_t _gcry_pk_ecc_get_sexp (gcry_sexp_t *r_sexp, int mode, + mpi_ec_t ec); + + +#endif /*GCRY_PUBKEY_INTERNAL_H*/ diff --git a/plugins/MirOTR/Libgcrypt/cipher/pubkey-util.c b/plugins/MirOTR/Libgcrypt/cipher/pubkey-util.c new file mode 100644 index 0000000000..616b4990fe --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/pubkey-util.c @@ -0,0 +1,1050 @@ +/* pubkey-util.c - Supporting functions for all pubkey modules. + * Copyright (C) 1998, 1999, 2000, 2002, 2003, 2005, + * 2007, 2008, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "pubkey-internal.h" + + +/* Callback for the pubkey algorithm code to verify PSS signatures. + OPAQUE is the data provided by the actual caller. The meaning of + TMP depends on the actual algorithm (but there is only RSA); now + for RSA it is the output of running the public key function on the + input. */ +static int +pss_verify_cmp (void *opaque, gcry_mpi_t tmp) +{ + struct pk_encoding_ctx *ctx = opaque; + gcry_mpi_t hash = ctx->verify_arg; + + return _gcry_rsa_pss_verify (hash, tmp, ctx->nbits - 1, + ctx->hash_algo, ctx->saltlen); +} + + +/* Parser for a flag list. On return the encoding is stored at + R_ENCODING and the flags are stored at R_FLAGS. If any of them is + not needed, NULL may be passed. The function returns 0 on success + or an error code. */ +gpg_err_code_t +_gcry_pk_util_parse_flaglist (gcry_sexp_t list, + int *r_flags, enum pk_encoding *r_encoding) +{ + gpg_err_code_t rc = 0; + const char *s; + size_t n; + int i; + int encoding = PUBKEY_ENC_UNKNOWN; + int flags = 0; + int igninvflag = 0; + + for (i = list ? sexp_length (list)-1 : 0; i > 0; i--) + { + s = sexp_nth_data (list, i, &n); + if (!s) + continue; /* Not a data element. */ + + switch (n) + { + case 3: + if (!memcmp (s, "pss", 3) && encoding == PUBKEY_ENC_UNKNOWN) + { + encoding = PUBKEY_ENC_PSS; + flags |= PUBKEY_FLAG_FIXEDLEN; + } + else if (!memcmp (s, "raw", 3) && encoding == PUBKEY_ENC_UNKNOWN) + { + encoding = PUBKEY_ENC_RAW; + flags |= PUBKEY_FLAG_RAW_FLAG; /* Explicitly given. */ + } + else if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + + case 4: + if (!memcmp (s, "comp", 4)) + flags |= PUBKEY_FLAG_COMP; + else if (!memcmp (s, "oaep", 4) && encoding == PUBKEY_ENC_UNKNOWN) + { + encoding = PUBKEY_ENC_OAEP; + flags |= PUBKEY_FLAG_FIXEDLEN; + } + else if (!memcmp (s, "gost", 4)) + { + encoding = PUBKEY_ENC_RAW; + flags |= PUBKEY_FLAG_GOST; + } + else if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + + case 5: + if (!memcmp (s, "eddsa", 5)) + { + encoding = PUBKEY_ENC_RAW; + flags |= PUBKEY_FLAG_EDDSA; + } + else if (!memcmp (s, "pkcs1", 5) && encoding == PUBKEY_ENC_UNKNOWN) + { + encoding = PUBKEY_ENC_PKCS1; + flags |= PUBKEY_FLAG_FIXEDLEN; + } + else if (!memcmp (s, "param", 5)) + flags |= PUBKEY_FLAG_PARAM; + else if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + + case 6: + if (!memcmp (s, "nocomp", 6)) + flags |= PUBKEY_FLAG_NOCOMP; + else if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + + case 7: + if (!memcmp (s, "rfc6979", 7)) + flags |= PUBKEY_FLAG_RFC6979; + else if (!memcmp (s, "noparam", 7)) + ; /* Ignore - it is the default. */ + else if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + + case 8: + if (!memcmp (s, "use-x931", 8)) + flags |= PUBKEY_FLAG_USE_X931; + else if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + + case 10: + if (!memcmp (s, "igninvflag", 10)) + igninvflag = 1; + break; + + case 11: + if (!memcmp (s, "no-blinding", 11)) + flags |= PUBKEY_FLAG_NO_BLINDING; + else if (!memcmp (s, "use-fips186", 11)) + flags |= PUBKEY_FLAG_USE_FIPS186; + else if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + + case 13: + if (!memcmp (s, "use-fips186-2", 13)) + flags |= PUBKEY_FLAG_USE_FIPS186_2; + else if (!memcmp (s, "transient-key", 13)) + flags |= PUBKEY_FLAG_TRANSIENT_KEY; + else if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + + default: + if (!igninvflag) + rc = GPG_ERR_INV_FLAG; + break; + } + } + + if (r_flags) + *r_flags = flags; + if (r_encoding) + *r_encoding = encoding; + + return rc; +} + + +static int +get_hash_algo (const char *s, size_t n) +{ + static const struct { const char *name; int algo; } hashnames[] = { + { "sha1", GCRY_MD_SHA1 }, + { "md5", GCRY_MD_MD5 }, + { "sha256", GCRY_MD_SHA256 }, + { "ripemd160", GCRY_MD_RMD160 }, + { "rmd160", GCRY_MD_RMD160 }, + { "sha384", GCRY_MD_SHA384 }, + { "sha512", GCRY_MD_SHA512 }, + { "sha224", GCRY_MD_SHA224 }, + { "md2", GCRY_MD_MD2 }, + { "md4", GCRY_MD_MD4 }, + { "tiger", GCRY_MD_TIGER }, + { "haval", GCRY_MD_HAVAL }, + { NULL, 0 } + }; + int algo; + int i; + + for (i=0; hashnames[i].name; i++) + { + if ( strlen (hashnames[i].name) == n + && !memcmp (hashnames[i].name, s, n)) + break; + } + if (hashnames[i].name) + algo = hashnames[i].algo; + else + { + /* In case of not listed or dynamically allocated hash + algorithm we fall back to this somewhat slower + method. Further, it also allows to use OIDs as + algorithm names. */ + char *tmpname; + + tmpname = xtrymalloc (n+1); + if (!tmpname) + algo = 0; /* Out of core - silently give up. */ + else + { + memcpy (tmpname, s, n); + tmpname[n] = 0; + algo = _gcry_md_map_name (tmpname); + xfree (tmpname); + } + } + return algo; +} + + +/* Get the "nbits" parameter from an s-expression of the format: + * + * (algo + * (parameter_name_1 ....) + * .... + * (parameter_name_n ....)) + * + * Example: + * + * (rsa + * (nbits 4:2048)) + * + * On success the value for nbits is stored at R_NBITS. If no nbits + * parameter is found, the function returns success and stores 0 at + * R_NBITS. For parsing errors the function returns an error code and + * stores 0 at R_NBITS. + */ +gpg_err_code_t +_gcry_pk_util_get_nbits (gcry_sexp_t list, unsigned int *r_nbits) +{ + char buf[50]; + const char *s; + size_t n; + + *r_nbits = 0; + + list = sexp_find_token (list, "nbits", 0); + if (!list) + return 0; /* No NBITS found. */ + + s = sexp_nth_data (list, 1, &n); + if (!s || n >= DIM (buf) - 1 ) + { + /* NBITS given without a cdr. */ + sexp_release (list); + return GPG_ERR_INV_OBJ; + } + memcpy (buf, s, n); + buf[n] = 0; + *r_nbits = (unsigned int)strtoul (buf, NULL, 0); + sexp_release (list); + return 0; +} + + +/* Get the optional "rsa-use-e" parameter from an s-expression of the + * format: + * + * (algo + * (parameter_name_1 ....) + * .... + * (parameter_name_n ....)) + * + * Example: + * + * (rsa + * (nbits 4:2048) + * (rsa-use-e 2:41)) + * + * On success the value for nbits is stored at R_E. If no rsa-use-e + * parameter is found, the function returns success and stores 65537 at + * R_E. For parsing errors the function returns an error code and + * stores 0 at R_E. + */ +gpg_err_code_t +_gcry_pk_util_get_rsa_use_e (gcry_sexp_t list, unsigned long *r_e) +{ + char buf[50]; + const char *s; + size_t n; + + *r_e = 0; + + list = sexp_find_token (list, "rsa-use-e", 0); + if (!list) + { + *r_e = 65537; /* Not given, use the value generated by old versions. */ + return 0; + } + + s = sexp_nth_data (list, 1, &n); + if (!s || n >= DIM (buf) - 1 ) + { + /* No value or value too large. */ + sexp_release (list); + return GPG_ERR_INV_OBJ; + } + memcpy (buf, s, n); + buf[n] = 0; + *r_e = strtoul (buf, NULL, 0); + sexp_release (list); + return 0; +} + + +/* Parse a "sig-val" s-expression and store the inner parameter list at + R_PARMS. ALGO_NAMES is used to verify that the algorithm in + "sig-val" is valid. Returns 0 on success and stores a new list at + R_PARMS which must be freed by the caller. On error R_PARMS is set + to NULL and an error code returned. If R_ECCFLAGS is not NULL flag + values are set into it; as of now they are only used with ecc + algorithms. */ +gpg_err_code_t +_gcry_pk_util_preparse_sigval (gcry_sexp_t s_sig, const char **algo_names, + gcry_sexp_t *r_parms, int *r_eccflags) +{ + gpg_err_code_t rc; + gcry_sexp_t l1 = NULL; + gcry_sexp_t l2 = NULL; + char *name = NULL; + int i; + + *r_parms = NULL; + if (r_eccflags) + *r_eccflags = 0; + + /* Extract the signature value. */ + l1 = sexp_find_token (s_sig, "sig-val", 0); + if (!l1) + { + rc = GPG_ERR_INV_OBJ; /* Does not contain a signature value object. */ + goto leave; + } + + l2 = sexp_nth (l1, 1); + if (!l2) + { + rc = GPG_ERR_NO_OBJ; /* No cadr for the sig object. */ + goto leave; + } + name = sexp_nth_string (l2, 0); + if (!name) + { + rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ + goto leave; + } + else if (!strcmp (name, "flags")) + { + /* Skip a "flags" parameter and look again for the algorithm + name. This is not used but here just for the sake of + consistent S-expressions we need to handle it. */ + sexp_release (l2); + l2 = sexp_nth (l1, 2); + if (!l2) + { + rc = GPG_ERR_INV_OBJ; + goto leave; + } + xfree (name); + name = sexp_nth_string (l2, 0); + if (!name) + { + rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ + goto leave; + } + } + + for (i=0; algo_names[i]; i++) + if (!stricmp (name, algo_names[i])) + break; + if (!algo_names[i]) + { + rc = GPG_ERR_CONFLICT; /* "sig-val" uses an unexpected algo. */ + goto leave; + } + if (r_eccflags) + { + if (!strcmp (name, "eddsa")) + *r_eccflags = PUBKEY_FLAG_EDDSA; + if (!strcmp (name, "gost")) + *r_eccflags = PUBKEY_FLAG_GOST; + } + + *r_parms = l2; + l2 = NULL; + rc = 0; + + leave: + xfree (name); + sexp_release (l2); + sexp_release (l1); + return rc; +} + + +/* Parse a "enc-val" s-expression and store the inner parameter list + at R_PARMS. ALGO_NAMES is used to verify that the algorithm in + "enc-val" is valid. Returns 0 on success and stores a new list at + R_PARMS which must be freed by the caller. On error R_PARMS is set + to NULL and an error code returned. If R_ECCFLAGS is not NULL flag + values are set into it; as of now they are only used with ecc + algorithms. + + (enc-val + [(flags [raw, pkcs1, oaep, no-blinding])] + [(hash-algo <algo>)] + [(label <label>)] + (<algo> + (<param_name1> <mpi>) + ... + (<param_namen> <mpi>))) + + HASH-ALGO and LABEL are specific to OAEP. CTX will be updated with + encoding information. */ +gpg_err_code_t +_gcry_pk_util_preparse_encval (gcry_sexp_t sexp, const char **algo_names, + gcry_sexp_t *r_parms, + struct pk_encoding_ctx *ctx) +{ + gcry_err_code_t rc = 0; + gcry_sexp_t l1 = NULL; + gcry_sexp_t l2 = NULL; + char *name = NULL; + size_t n; + int parsed_flags = 0; + int i; + + *r_parms = NULL; + + /* Check that the first element is valid. */ + l1 = sexp_find_token (sexp, "enc-val" , 0); + if (!l1) + { + rc = GPG_ERR_INV_OBJ; /* Does not contain an encrypted value object. */ + goto leave; + } + + l2 = sexp_nth (l1, 1); + if (!l2) + { + rc = GPG_ERR_NO_OBJ; /* No cadr for the data object. */ + goto leave; + } + + /* Extract identifier of sublist. */ + name = sexp_nth_string (l2, 0); + if (!name) + { + rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ + goto leave; + } + + if (!strcmp (name, "flags")) + { + const char *s; + + /* There is a flags element - process it. */ + rc = _gcry_pk_util_parse_flaglist (l2, &parsed_flags, &ctx->encoding); + if (rc) + goto leave; + if (ctx->encoding == PUBKEY_ENC_PSS) + { + rc = GPG_ERR_CONFLICT; + goto leave; + } + + /* Get the OAEP parameters HASH-ALGO and LABEL, if any. */ + if (ctx->encoding == PUBKEY_ENC_OAEP) + { + /* Get HASH-ALGO. */ + sexp_release (l2); + l2 = sexp_find_token (l1, "hash-algo", 0); + if (l2) + { + s = sexp_nth_data (l2, 1, &n); + if (!s) + rc = GPG_ERR_NO_OBJ; + else + { + ctx->hash_algo = get_hash_algo (s, n); + if (!ctx->hash_algo) + rc = GPG_ERR_DIGEST_ALGO; + } + if (rc) + goto leave; + } + + /* Get LABEL. */ + sexp_release (l2); + l2 = sexp_find_token (l1, "label", 0); + if (l2) + { + s = sexp_nth_data (l2, 1, &n); + if (!s) + rc = GPG_ERR_NO_OBJ; + else if (n > 0) + { + ctx->label = xtrymalloc (n); + if (!ctx->label) + rc = gpg_err_code_from_syserror (); + else + { + memcpy (ctx->label, s, n); + ctx->labellen = n; + } + } + if (rc) + goto leave; + } + } + + /* Get the next which has the actual data - skip HASH-ALGO and LABEL. */ + for (i = 2; (sexp_release (l2), l2 = sexp_nth (l1, i)); i++) + { + s = sexp_nth_data (l2, 0, &n); + if (!(n == 9 && !memcmp (s, "hash-algo", 9)) + && !(n == 5 && !memcmp (s, "label", 5)) + && !(n == 15 && !memcmp (s, "random-override", 15))) + break; + } + if (!l2) + { + rc = GPG_ERR_NO_OBJ; /* No cadr for the data object. */ + goto leave; + } + + /* Extract sublist identifier. */ + xfree (name); + name = sexp_nth_string (l2, 0); + if (!name) + { + rc = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ + goto leave; + } + } + else /* No flags - flag as legacy structure. */ + parsed_flags |= PUBKEY_FLAG_LEGACYRESULT; + + for (i=0; algo_names[i]; i++) + if (!stricmp (name, algo_names[i])) + break; + if (!algo_names[i]) + { + rc = GPG_ERR_CONFLICT; /* "enc-val" uses an unexpected algo. */ + goto leave; + } + + *r_parms = l2; + l2 = NULL; + ctx->flags |= parsed_flags; + rc = 0; + + leave: + xfree (name); + sexp_release (l2); + sexp_release (l1); + return rc; +} + + +/* Initialize an encoding context. */ +void +_gcry_pk_util_init_encoding_ctx (struct pk_encoding_ctx *ctx, + enum pk_operation op, + unsigned int nbits) +{ + ctx->op = op; + ctx->nbits = nbits; + ctx->encoding = PUBKEY_ENC_UNKNOWN; + ctx->flags = 0; + ctx->hash_algo = GCRY_MD_SHA1; + ctx->label = NULL; + ctx->labellen = 0; + ctx->saltlen = 20; + ctx->verify_cmp = NULL; + ctx->verify_arg = NULL; +} + +/* Free a context initialzied by _gcry_pk_util_init_encoding_ctx. */ +void +_gcry_pk_util_free_encoding_ctx (struct pk_encoding_ctx *ctx) +{ + xfree (ctx->label); +} + + +/* Take the hash value and convert into an MPI, suitable for + passing to the low level functions. We currently support the + old style way of passing just a MPI and the modern interface which + allows to pass flags so that we can choose between raw and pkcs1 + padding - may be more padding options later. + + (<mpi>) + or + (data + [(flags [raw, direct, pkcs1, oaep, pss, no-blinding, rfc6979, eddsa])] + [(hash <algo> <value>)] + [(value <text>)] + [(hash-algo <algo>)] + [(label <label>)] + [(salt-length <length>)] + [(random-override <data>)] + ) + + Either the VALUE or the HASH element must be present for use + with signatures. VALUE is used for encryption. + + HASH-ALGO is specific to OAEP and EDDSA. + + LABEL is specific to OAEP. + + SALT-LENGTH is for PSS. + + RANDOM-OVERRIDE is used to replace random nonces for regression + testing. */ +gcry_err_code_t +_gcry_pk_util_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi, + struct pk_encoding_ctx *ctx) +{ + gcry_err_code_t rc = 0; + gcry_sexp_t ldata, lhash, lvalue; + size_t n; + const char *s; + int unknown_flag = 0; + int parsed_flags = 0; + + *ret_mpi = NULL; + ldata = sexp_find_token (input, "data", 0); + if (!ldata) + { /* assume old style */ + *ret_mpi = sexp_nth_mpi (input, 0, 0); + return *ret_mpi ? GPG_ERR_NO_ERROR : GPG_ERR_INV_OBJ; + } + + /* See whether there is a flags list. */ + { + gcry_sexp_t lflags = sexp_find_token (ldata, "flags", 0); + if (lflags) + { + if (_gcry_pk_util_parse_flaglist (lflags, + &parsed_flags, &ctx->encoding)) + unknown_flag = 1; + sexp_release (lflags); + } + } + + if (ctx->encoding == PUBKEY_ENC_UNKNOWN) + ctx->encoding = PUBKEY_ENC_RAW; /* default to raw */ + + /* Get HASH or MPI */ + lhash = sexp_find_token (ldata, "hash", 0); + lvalue = lhash? NULL : sexp_find_token (ldata, "value", 0); + + if (!(!lhash ^ !lvalue)) + rc = GPG_ERR_INV_OBJ; /* none or both given */ + else if (unknown_flag) + rc = GPG_ERR_INV_FLAG; + else if (ctx->encoding == PUBKEY_ENC_RAW + && (parsed_flags & PUBKEY_FLAG_EDDSA)) + { + /* Prepare for EdDSA. */ + gcry_sexp_t list; + void *value; + size_t valuelen; + + if (!lvalue) + { + rc = GPG_ERR_INV_OBJ; + goto leave; + } + /* Get HASH-ALGO. */ + list = sexp_find_token (ldata, "hash-algo", 0); + if (list) + { + s = sexp_nth_data (list, 1, &n); + if (!s) + rc = GPG_ERR_NO_OBJ; + else + { + ctx->hash_algo = get_hash_algo (s, n); + if (!ctx->hash_algo) + rc = GPG_ERR_DIGEST_ALGO; + } + sexp_release (list); + } + else + rc = GPG_ERR_INV_OBJ; + if (rc) + goto leave; + + /* Get VALUE. */ + value = sexp_nth_buffer (lvalue, 1, &valuelen); + if (!value) + { + /* We assume that a zero length message is meant by + "(value)". This is commonly used by test vectors. Note + that S-expression do not allow zero length items. */ + valuelen = 0; + value = xtrymalloc (1); + if (!value) + rc = gpg_err_code_from_syserror (); + } + else if ((valuelen * 8) < valuelen) + { + xfree (value); + rc = GPG_ERR_TOO_LARGE; + } + if (rc) + goto leave; + + /* Note that mpi_set_opaque takes ownership of VALUE. */ + *ret_mpi = mpi_set_opaque (NULL, value, valuelen*8); + } + else if (ctx->encoding == PUBKEY_ENC_RAW && lhash + && ((parsed_flags & PUBKEY_FLAG_RAW_FLAG) + || (parsed_flags & PUBKEY_FLAG_RFC6979))) + { + /* Raw encoding along with a hash element. This is commonly + used for DSA. For better backward error compatibility we + allow this only if either the rfc6979 flag has been given or + the raw flags was explicitly given. */ + if (sexp_length (lhash) != 3) + rc = GPG_ERR_INV_OBJ; + else if ( !(s=sexp_nth_data (lhash, 1, &n)) || !n ) + rc = GPG_ERR_INV_OBJ; + else + { + void *value; + size_t valuelen; + + ctx->hash_algo = get_hash_algo (s, n); + if (!ctx->hash_algo) + rc = GPG_ERR_DIGEST_ALGO; + else if (!(value=sexp_nth_buffer (lhash, 2, &valuelen))) + rc = GPG_ERR_INV_OBJ; + else if ((valuelen * 8) < valuelen) + { + xfree (value); + rc = GPG_ERR_TOO_LARGE; + } + else + *ret_mpi = mpi_set_opaque (NULL, value, valuelen*8); + } + } + else if (ctx->encoding == PUBKEY_ENC_RAW && lvalue) + { + /* RFC6969 may only be used with the a hash value and not the + MPI based value. */ + if (parsed_flags & PUBKEY_FLAG_RFC6979) + { + rc = GPG_ERR_CONFLICT; + goto leave; + } + + /* Get the value */ + *ret_mpi = sexp_nth_mpi (lvalue, 1, GCRYMPI_FMT_USG); + if (!*ret_mpi) + rc = GPG_ERR_INV_OBJ; + } + else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lvalue + && ctx->op == PUBKEY_OP_ENCRYPT) + { + const void * value; + size_t valuelen; + gcry_sexp_t list; + void *random_override = NULL; + size_t random_override_len = 0; + + if ( !(value=sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen ) + rc = GPG_ERR_INV_OBJ; + else + { + /* Get optional RANDOM-OVERRIDE. */ + list = sexp_find_token (ldata, "random-override", 0); + if (list) + { + s = sexp_nth_data (list, 1, &n); + if (!s) + rc = GPG_ERR_NO_OBJ; + else if (n > 0) + { + random_override = xtrymalloc (n); + if (!random_override) + rc = gpg_err_code_from_syserror (); + else + { + memcpy (random_override, s, n); + random_override_len = n; + } + } + sexp_release (list); + if (rc) + goto leave; + } + + rc = _gcry_rsa_pkcs1_encode_for_enc (ret_mpi, ctx->nbits, + value, valuelen, + random_override, + random_override_len); + xfree (random_override); + } + } + else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lhash + && (ctx->op == PUBKEY_OP_SIGN || ctx->op == PUBKEY_OP_VERIFY)) + { + if (sexp_length (lhash) != 3) + rc = GPG_ERR_INV_OBJ; + else if ( !(s=sexp_nth_data (lhash, 1, &n)) || !n ) + rc = GPG_ERR_INV_OBJ; + else + { + const void * value; + size_t valuelen; + + ctx->hash_algo = get_hash_algo (s, n); + + if (!ctx->hash_algo) + rc = GPG_ERR_DIGEST_ALGO; + else if ( !(value=sexp_nth_data (lhash, 2, &valuelen)) + || !valuelen ) + rc = GPG_ERR_INV_OBJ; + else + rc = _gcry_rsa_pkcs1_encode_for_sig (ret_mpi, ctx->nbits, + value, valuelen, + ctx->hash_algo); + } + } + else if (ctx->encoding == PUBKEY_ENC_OAEP && lvalue + && ctx->op == PUBKEY_OP_ENCRYPT) + { + const void * value; + size_t valuelen; + + if ( !(value=sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen ) + rc = GPG_ERR_INV_OBJ; + else + { + gcry_sexp_t list; + void *random_override = NULL; + size_t random_override_len = 0; + + /* Get HASH-ALGO. */ + list = sexp_find_token (ldata, "hash-algo", 0); + if (list) + { + s = sexp_nth_data (list, 1, &n); + if (!s) + rc = GPG_ERR_NO_OBJ; + else + { + ctx->hash_algo = get_hash_algo (s, n); + if (!ctx->hash_algo) + rc = GPG_ERR_DIGEST_ALGO; + } + sexp_release (list); + if (rc) + goto leave; + } + + /* Get LABEL. */ + list = sexp_find_token (ldata, "label", 0); + if (list) + { + s = sexp_nth_data (list, 1, &n); + if (!s) + rc = GPG_ERR_NO_OBJ; + else if (n > 0) + { + ctx->label = xtrymalloc (n); + if (!ctx->label) + rc = gpg_err_code_from_syserror (); + else + { + memcpy (ctx->label, s, n); + ctx->labellen = n; + } + } + sexp_release (list); + if (rc) + goto leave; + } + /* Get optional RANDOM-OVERRIDE. */ + list = sexp_find_token (ldata, "random-override", 0); + if (list) + { + s = sexp_nth_data (list, 1, &n); + if (!s) + rc = GPG_ERR_NO_OBJ; + else if (n > 0) + { + random_override = xtrymalloc (n); + if (!random_override) + rc = gpg_err_code_from_syserror (); + else + { + memcpy (random_override, s, n); + random_override_len = n; + } + } + sexp_release (list); + if (rc) + goto leave; + } + + rc = _gcry_rsa_oaep_encode (ret_mpi, ctx->nbits, ctx->hash_algo, + value, valuelen, + ctx->label, ctx->labellen, + random_override, random_override_len); + + xfree (random_override); + } + } + else if (ctx->encoding == PUBKEY_ENC_PSS && lhash + && ctx->op == PUBKEY_OP_SIGN) + { + if (sexp_length (lhash) != 3) + rc = GPG_ERR_INV_OBJ; + else if ( !(s=sexp_nth_data (lhash, 1, &n)) || !n ) + rc = GPG_ERR_INV_OBJ; + else + { + const void * value; + size_t valuelen; + void *random_override = NULL; + size_t random_override_len = 0; + + ctx->hash_algo = get_hash_algo (s, n); + + if (!ctx->hash_algo) + rc = GPG_ERR_DIGEST_ALGO; + else if ( !(value=sexp_nth_data (lhash, 2, &valuelen)) + || !valuelen ) + rc = GPG_ERR_INV_OBJ; + else + { + gcry_sexp_t list; + + /* Get SALT-LENGTH. */ + list = sexp_find_token (ldata, "salt-length", 0); + if (list) + { + s = sexp_nth_data (list, 1, &n); + if (!s) + { + rc = GPG_ERR_NO_OBJ; + goto leave; + } + ctx->saltlen = (unsigned int)strtoul (s, NULL, 10); + sexp_release (list); + } + + /* Get optional RANDOM-OVERRIDE. */ + list = sexp_find_token (ldata, "random-override", 0); + if (list) + { + s = sexp_nth_data (list, 1, &n); + if (!s) + rc = GPG_ERR_NO_OBJ; + else if (n > 0) + { + random_override = xtrymalloc (n); + if (!random_override) + rc = gpg_err_code_from_syserror (); + else + { + memcpy (random_override, s, n); + random_override_len = n; + } + } + sexp_release (list); + if (rc) + goto leave; + } + + /* Encode the data. (NBITS-1 is due to 8.1.1, step 1.) */ + rc = _gcry_rsa_pss_encode (ret_mpi, ctx->nbits - 1, + ctx->hash_algo, + value, valuelen, ctx->saltlen, + random_override, random_override_len); + + xfree (random_override); + } + } + } + else if (ctx->encoding == PUBKEY_ENC_PSS && lhash + && ctx->op == PUBKEY_OP_VERIFY) + { + if (sexp_length (lhash) != 3) + rc = GPG_ERR_INV_OBJ; + else if ( !(s=sexp_nth_data (lhash, 1, &n)) || !n ) + rc = GPG_ERR_INV_OBJ; + else + { + ctx->hash_algo = get_hash_algo (s, n); + + if (!ctx->hash_algo) + rc = GPG_ERR_DIGEST_ALGO; + else + { + *ret_mpi = sexp_nth_mpi (lhash, 2, GCRYMPI_FMT_USG); + if (!*ret_mpi) + rc = GPG_ERR_INV_OBJ; + ctx->verify_cmp = pss_verify_cmp; + ctx->verify_arg = *ret_mpi; + } + } + } + else + rc = GPG_ERR_CONFLICT; + + leave: + sexp_release (ldata); + sexp_release (lhash); + sexp_release (lvalue); + + if (!rc) + ctx->flags = parsed_flags; + else + { + xfree (ctx->label); + ctx->label = NULL; + } + + return rc; +} diff --git a/plugins/MirOTR/Libgcrypt/cipher/pubkey.c b/plugins/MirOTR/Libgcrypt/cipher/pubkey.c index f163ea1696..b31e9df2f9 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/pubkey.c +++ b/plugins/MirOTR/Libgcrypt/cipher/pubkey.c @@ -1,6 +1,7 @@ /* pubkey.c - pubkey dispatcher - * Copyright (C) 1998, 1999, 2000, 2002, 2003, 2005, - * 2007, 2008 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2002, 2003, 2005, + * 2007, 2008, 2011 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH * * This file is part of Libgcrypt. * @@ -28,305 +29,173 @@ #include "mpi.h" #include "cipher.h" #include "ath.h" +#include "context.h" +#include "pubkey-internal.h" -static gcry_err_code_t pubkey_decrypt (int algo, gcry_mpi_t *result, - gcry_mpi_t *data, gcry_mpi_t *skey, - int flags); -static gcry_err_code_t pubkey_sign (int algo, gcry_mpi_t *resarr, - gcry_mpi_t hash, gcry_mpi_t *skey); -static gcry_err_code_t pubkey_verify (int algo, gcry_mpi_t hash, - gcry_mpi_t *data, gcry_mpi_t *pkey, - int (*cmp) (void *, gcry_mpi_t), - void *opaque); - - -/* A dummy extraspec so that we do not need to tests the extraspec - field from the module specification against NULL and instead - directly test the respective fields of extraspecs. */ -static pk_extra_spec_t dummy_extra_spec; - - -/* This is the list of the default public-key ciphers included in - libgcrypt. FIPS_ALLOWED indicated whether the algorithm is used in - FIPS mode. */ -static struct pubkey_table_entry -{ - gcry_pk_spec_t *pubkey; - pk_extra_spec_t *extraspec; - unsigned int algorithm; - int fips_allowed; -} pubkey_table[] = +/* This is the list of the public-key algorithms included in + Libgcrypt. */ +static gcry_pk_spec_t *pubkey_list[] = { -#if USE_RSA - { &_gcry_pubkey_spec_rsa, - &_gcry_pubkey_extraspec_rsa, GCRY_PK_RSA, 1}, +#if USE_ECC + &_gcry_pubkey_spec_ecc, #endif -#if USE_ELGAMAL - { &_gcry_pubkey_spec_elg, - &_gcry_pubkey_extraspec_elg, GCRY_PK_ELG }, - { &_gcry_pubkey_spec_elg, - &_gcry_pubkey_extraspec_elg, GCRY_PK_ELG_E }, +#if USE_RSA + &_gcry_pubkey_spec_rsa, #endif #if USE_DSA - { &_gcry_pubkey_spec_dsa, - &_gcry_pubkey_extraspec_dsa, GCRY_PK_DSA, 1 }, + &_gcry_pubkey_spec_dsa, #endif -#if USE_ECC - { &_gcry_pubkey_spec_ecdsa, - &_gcry_pubkey_extraspec_ecdsa, GCRY_PK_ECDSA, 0 }, +#if USE_ELGAMAL + &_gcry_pubkey_spec_elg, #endif - { NULL, 0 }, + NULL }; -/* List of registered ciphers. */ -static gcry_module_t pubkeys_registered; - -/* This is the lock protecting PUBKEYS_REGISTERED. */ -static ath_mutex_t pubkeys_registered_lock = ATH_MUTEX_INITIALIZER;; - -/* Flag to check wether the default pubkeys have already been - registered. */ -static int default_pubkeys_registered; - -/* Convenient macro for registering the default digests. */ -#define REGISTER_DEFAULT_PUBKEYS \ - do \ - { \ - ath_mutex_lock (&pubkeys_registered_lock); \ - if (! default_pubkeys_registered) \ - { \ - pk_register_default (); \ - default_pubkeys_registered = 1; \ - } \ - ath_mutex_unlock (&pubkeys_registered_lock); \ - } \ - while (0) - -/* These dummy functions are used in case a cipher implementation - refuses to provide it's own functions. */ -static gcry_err_code_t -dummy_generate (int algorithm, unsigned int nbits, unsigned long dummy, - gcry_mpi_t *skey, gcry_mpi_t **retfactors) +static int +map_algo (int algo) { - (void)algorithm; - (void)nbits; - (void)dummy; - (void)skey; - (void)retfactors; - fips_signal_error ("using dummy public key function"); - return GPG_ERR_NOT_IMPLEMENTED; + switch (algo) + { + case GCRY_PK_RSA_E: return GCRY_PK_RSA; + case GCRY_PK_RSA_S: return GCRY_PK_RSA; + case GCRY_PK_ELG_E: return GCRY_PK_ELG; + case GCRY_PK_ECDSA: return GCRY_PK_ECC; + case GCRY_PK_ECDH: return GCRY_PK_ECC; + default: return algo; + } } -static gcry_err_code_t -dummy_check_secret_key (int algorithm, gcry_mpi_t *skey) -{ - (void)algorithm; - (void)skey; - fips_signal_error ("using dummy public key function"); - return GPG_ERR_NOT_IMPLEMENTED; -} -static gcry_err_code_t -dummy_encrypt (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data, - gcry_mpi_t *pkey, int flags) +/* Return the spec structure for the public key algorithm ALGO. For + an unknown algorithm NULL is returned. */ +static gcry_pk_spec_t * +spec_from_algo (int algo) { - (void)algorithm; - (void)resarr; - (void)data; - (void)pkey; - (void)flags; - fips_signal_error ("using dummy public key function"); - return GPG_ERR_NOT_IMPLEMENTED; -} + int idx; + gcry_pk_spec_t *spec; -static gcry_err_code_t -dummy_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data, - gcry_mpi_t *skey, int flags) -{ - (void)algorithm; - (void)result; - (void)data; - (void)skey; - (void)flags; - fips_signal_error ("using dummy public key function"); - return GPG_ERR_NOT_IMPLEMENTED; -} + algo = map_algo (algo); -static gcry_err_code_t -dummy_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data, - gcry_mpi_t *skey) -{ - (void)algorithm; - (void)resarr; - (void)data; - (void)skey; - fips_signal_error ("using dummy public key function"); - return GPG_ERR_NOT_IMPLEMENTED; + for (idx = 0; (spec = pubkey_list[idx]); idx++) + if (algo == spec->algo) + return spec; + return NULL; } -static gcry_err_code_t -dummy_verify (int algorithm, gcry_mpi_t hash, gcry_mpi_t *data, - gcry_mpi_t *pkey, - int (*cmp) (void *, gcry_mpi_t), void *opaquev) -{ - (void)algorithm; - (void)hash; - (void)data; - (void)pkey; - (void)cmp; - (void)opaquev; - fips_signal_error ("using dummy public key function"); - return GPG_ERR_NOT_IMPLEMENTED; -} -static unsigned -dummy_get_nbits (int algorithm, gcry_mpi_t *pkey) +/* Return the spec structure for the public key algorithm with NAME. + For an unknown name NULL is returned. */ +static gcry_pk_spec_t * +spec_from_name (const char *name) { - (void)algorithm; - (void)pkey; - fips_signal_error ("using dummy public key function"); - return 0; -} + gcry_pk_spec_t *spec; + int idx; + const char **aliases; -/* Internal function. Register all the pubkeys included in - PUBKEY_TABLE. Returns zero on success or an error code. */ -static void -pk_register_default (void) -{ - gcry_err_code_t err = 0; - int i; - - for (i = 0; (! err) && pubkey_table[i].pubkey; i++) + for (idx=0; (spec = pubkey_list[idx]); idx++) { -#define pubkey_use_dummy(func) \ - if (! pubkey_table[i].pubkey->func) \ - pubkey_table[i].pubkey->func = dummy_##func; - - pubkey_use_dummy (generate); - pubkey_use_dummy (check_secret_key); - pubkey_use_dummy (encrypt); - pubkey_use_dummy (decrypt); - pubkey_use_dummy (sign); - pubkey_use_dummy (verify); - pubkey_use_dummy (get_nbits); -#undef pubkey_use_dummy - - err = _gcry_module_add (&pubkeys_registered, - pubkey_table[i].algorithm, - (void *) pubkey_table[i].pubkey, - (void *) pubkey_table[i].extraspec, - NULL); + if (!stricmp (name, spec->name)) + return spec; + for (aliases = spec->aliases; *aliases; aliases++) + if (!stricmp (name, *aliases)) + return spec; } - if (err) - BUG (); -} - -/* Internal callback function. Used via _gcry_module_lookup. */ -static int -gcry_pk_lookup_func_name (void *spec, void *data) -{ - gcry_pk_spec_t *pubkey = (gcry_pk_spec_t *) spec; - char *name = (char *) data; - const char **aliases = pubkey->aliases; - int ret = _stricmp (name, pubkey->name); - - while (ret && *aliases) - ret = _stricmp (name, *aliases++); - - return ! ret; + return NULL; } -/* Internal function. Lookup a pubkey entry by it's name. */ -static gcry_module_t -gcry_pk_lookup_name (const char *name) -{ - gcry_module_t pubkey; - pubkey = _gcry_module_lookup (pubkeys_registered, (void *) name, - gcry_pk_lookup_func_name); - - return pubkey; -} -/* Register a new pubkey module whose specification can be found in - PUBKEY. On success, a new algorithm ID is stored in ALGORITHM_ID - and a pointer representhing this module is stored in MODULE. */ -gcry_error_t -_gcry_pk_register (gcry_pk_spec_t *pubkey, - pk_extra_spec_t *extraspec, - unsigned int *algorithm_id, - gcry_module_t *module) +/* Given the s-expression SEXP with the first element be either + * "private-key" or "public-key" return the spec structure for it. We + * look through the list to find a list beginning with "private-key" + * or "public-key" - the first one found is used. If WANT_PRIVATE is + * set the function will only succeed if a private key has been given. + * On success the spec is stored at R_SPEC. On error NULL is stored + * at R_SPEC and an error code returned. If R_PARMS is not NULL and + * the fucntion returns success, the parameter list below + * "private-key" or "public-key" is stored there and the caller must + * call gcry_sexp_release on it. + */ +static gcry_err_code_t +spec_from_sexp (gcry_sexp_t sexp, int want_private, + gcry_pk_spec_t **r_spec, gcry_sexp_t *r_parms) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_module_t mod; - - /* We do not support module loading in fips mode. */ - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); + gcry_sexp_t list, l2; + char *name; + gcry_pk_spec_t *spec; - ath_mutex_lock (&pubkeys_registered_lock); - err = _gcry_module_add (&pubkeys_registered, 0, - (void *) pubkey, - (void *)(extraspec? extraspec : &dummy_extra_spec), - &mod); - ath_mutex_unlock (&pubkeys_registered_lock); + *r_spec = NULL; + if (r_parms) + *r_parms = NULL; + + /* Check that the first element is valid. If we are looking for a + public key but a private key was supplied, we allow the use of + the private key anyway. The rationale for this is that the + private key is a superset of the public key. */ + list = sexp_find_token (sexp, want_private? "private-key":"public-key", 0); + if (!list && !want_private) + list = sexp_find_token (sexp, "private-key", 0); + if (!list) + return GPG_ERR_INV_OBJ; /* Does not contain a key object. */ - if (! err) + l2 = sexp_cadr (list); + sexp_release (list); + list = l2; + name = sexp_nth_string (list, 0); + if (!name) { - *module = mod; - *algorithm_id = mod->mod_id; + sexp_release ( list ); + return GPG_ERR_INV_OBJ; /* Invalid structure of object. */ } - - return err; + spec = spec_from_name (name); + xfree (name); + if (!spec) + { + sexp_release (list); + return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ + } + *r_spec = spec; + if (r_parms) + *r_parms = list; + else + sexp_release (list); + return 0; } -/* Unregister the pubkey identified by ID, which must have been - registered with gcry_pk_register. */ -void -gcry_pk_unregister (gcry_module_t module) -{ - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); -} + +/* Disable the use of the algorithm ALGO. This is not thread safe and + should thus be called early. */ static void -release_mpi_array (gcry_mpi_t *array) +disable_pubkey_algo (int algo) { - for (; *array; array++) - { - mpi_free(*array); - *array = NULL; - } + gcry_pk_spec_t *spec = spec_from_algo (algo); + + if (spec) + spec->flags.disabled = 1; } -/**************** + + +/* * Map a string to the pubkey algo */ int -gcry_pk_map_name (const char *string) +_gcry_pk_map_name (const char *string) { - gcry_module_t pubkey; - int algorithm = 0; + gcry_pk_spec_t *spec; if (!string) return 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = gcry_pk_lookup_name (string); - if (pubkey) - { - algorithm = pubkey->mod_id; - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return algorithm; + spec = spec_from_name (string); + if (!spec) + return 0; + if (spec->flags.disabled) + return 0; + return spec->algo; } @@ -334,70 +203,14 @@ gcry_pk_map_name (const char *string) a string representation of the algorithm name. For unknown algorithm IDs this functions returns "?". */ const char * -gcry_pk_algo_name (int algorithm) -{ - gcry_module_t pubkey; - const char *name; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - name = ((gcry_pk_spec_t *) pubkey->spec)->name; - _gcry_module_release (pubkey); - } - else - name = "?"; - ath_mutex_unlock (&pubkeys_registered_lock); - - return name; -} - - -/* A special version of gcry_pk_algo name to return the first aliased - name of the algorithm. This is required to adhere to the spki - specs where the algorithm names are lowercase. */ -const char * -_gcry_pk_aliased_algo_name (int algorithm) -{ - const char *name = NULL; - gcry_module_t module; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (module) - { - gcry_pk_spec_t *pubkey = (gcry_pk_spec_t *) module->spec; - - name = pubkey->aliases? *pubkey->aliases : NULL; - if (!name || !*name) - name = pubkey->name; - _gcry_module_release (module); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return name; -} - - -static void -disable_pubkey_algo (int algorithm) +_gcry_pk_algo_name (int algo) { - gcry_module_t pubkey; + gcry_pk_spec_t *spec; - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - if (! (pubkey-> flags & FLAG_MODULE_DISABLED)) - pubkey->flags |= FLAG_MODULE_DISABLED; - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); + spec = spec_from_algo (algo); + if (spec) + return spec->name; + return "?"; } @@ -405,32 +218,22 @@ disable_pubkey_algo (int algorithm) * A USE of 0 means: don't care. */ static gcry_err_code_t -check_pubkey_algo (int algorithm, unsigned use) +check_pubkey_algo (int algo, unsigned use) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_pk_spec_t *pubkey; - gcry_module_t module; - - REGISTER_DEFAULT_PUBKEYS; + gcry_err_code_t err = 0; + gcry_pk_spec_t *spec; - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (module) + spec = spec_from_algo (algo); + if (spec) { - pubkey = (gcry_pk_spec_t *) module->spec; - if (((use & GCRY_PK_USAGE_SIGN) - && (! (pubkey->use & GCRY_PK_USAGE_SIGN))) + && (! (spec->use & GCRY_PK_USAGE_SIGN))) || ((use & GCRY_PK_USAGE_ENCR) - && (! (pubkey->use & GCRY_PK_USAGE_ENCR)))) + && (! (spec->use & GCRY_PK_USAGE_ENCR)))) err = GPG_ERR_WRONG_PUBKEY_ALGO; - else if (module->flags & FLAG_MODULE_DISABLED) - err = GPG_ERR_PUBKEY_ALGO; - _gcry_module_release (module); } else err = GPG_ERR_PUBKEY_ALGO; - ath_mutex_unlock (&pubkeys_registered_lock); return err; } @@ -440,1142 +243,63 @@ check_pubkey_algo (int algorithm, unsigned use) * Return the number of public key material numbers */ static int -pubkey_get_npkey (int algorithm) +pubkey_get_npkey (int algo) { - gcry_module_t pubkey; - int npkey = 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - npkey = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_pkey); - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); + gcry_pk_spec_t *spec = spec_from_algo (algo); - return npkey; + return spec? strlen (spec->elements_pkey) : 0; } + /**************** * Return the number of secret key material numbers */ static int -pubkey_get_nskey (int algorithm) +pubkey_get_nskey (int algo) { - gcry_module_t pubkey; - int nskey = 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - nskey = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_skey); - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); + gcry_pk_spec_t *spec = spec_from_algo (algo); - return nskey; + return spec? strlen (spec->elements_skey) : 0; } + /**************** * Return the number of signature material numbers */ static int -pubkey_get_nsig (int algorithm) +pubkey_get_nsig (int algo) { - gcry_module_t pubkey; - int nsig = 0; + gcry_pk_spec_t *spec = spec_from_algo (algo); - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - nsig = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_sig); - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return nsig; + return spec? strlen (spec->elements_sig) : 0; } /**************** * Return the number of encryption material numbers */ static int -pubkey_get_nenc (int algorithm) -{ - gcry_module_t pubkey; - int nenc = 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - nenc = strlen (((gcry_pk_spec_t *) pubkey->spec)->elements_enc); - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return nenc; -} - - -/* Generate a new public key with algorithm ALGORITHM of size NBITS - and return it at SKEY. USE_E depends on the ALGORITHM. GENPARMS - is passed to the algorithm module if it features an extended - generation function. RETFACTOR is used by some algorithms to - return certain additional information which are in general not - required. - - The function returns the error code number or 0 on success. */ -static gcry_err_code_t -pubkey_generate (int algorithm, - unsigned int nbits, - unsigned long use_e, - gcry_sexp_t genparms, - gcry_mpi_t *skey, gcry_mpi_t **retfactors, - gcry_sexp_t *r_extrainfo) -{ - gcry_err_code_t ec = GPG_ERR_PUBKEY_ALGO; - gcry_module_t pubkey; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - pk_extra_spec_t *extraspec = pubkey->extraspec; - - if (extraspec && extraspec->ext_generate) - { - /* Use the extended generate function. */ - ec = extraspec->ext_generate - (algorithm, nbits, use_e, genparms, skey, retfactors, r_extrainfo); - } - else - { - /* Use the standard generate function. */ - ec = ((gcry_pk_spec_t *) pubkey->spec)->generate - (algorithm, nbits, use_e, skey, retfactors); - } - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return ec; -} - - -static gcry_err_code_t -pubkey_check_secret_key (int algorithm, gcry_mpi_t *skey) -{ - gcry_err_code_t err = GPG_ERR_PUBKEY_ALGO; - gcry_module_t pubkey; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - err = ((gcry_pk_spec_t *) pubkey->spec)->check_secret_key - (algorithm, skey); - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - return err; -} - - -/**************** - * This is the interface to the public key encryption. Encrypt DATA - * with PKEY and put it into RESARR which should be an array of MPIs - * of size PUBKEY_MAX_NENC (or less if the algorithm allows this - - * check with pubkey_get_nenc() ) - */ -static gcry_err_code_t -pubkey_encrypt (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data, - gcry_mpi_t *pkey, int flags) -{ - gcry_pk_spec_t *pubkey; - gcry_module_t module; - gcry_err_code_t rc; - int i; - - /* Note: In fips mode DBG_CIPHER will enver evaluate to true but as - an extra failsafe protection we explicitly test for fips mode - here. */ - if (DBG_CIPHER && !fips_mode ()) - { - log_debug ("pubkey_encrypt: algo=%d\n", algorithm); - for(i = 0; i < pubkey_get_npkey (algorithm); i++) - log_mpidump (" pkey:", pkey[i]); - log_mpidump (" data:", data); - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (module) - { - pubkey = (gcry_pk_spec_t *) module->spec; - rc = pubkey->encrypt (algorithm, resarr, data, pkey, flags); - _gcry_module_release (module); - goto ready; - } - rc = GPG_ERR_PUBKEY_ALGO; - - ready: - ath_mutex_unlock (&pubkeys_registered_lock); - - if (!rc && DBG_CIPHER && !fips_mode ()) - { - for(i = 0; i < pubkey_get_nenc (algorithm); i++) - log_mpidump(" encr:", resarr[i] ); - } - return rc; -} - - -/**************** - * This is the interface to the public key decryption. - * ALGO gives the algorithm to use and this implicitly determines - * the size of the arrays. - * result is a pointer to a mpi variable which will receive a - * newly allocated mpi or NULL in case of an error. - */ -static gcry_err_code_t -pubkey_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data, - gcry_mpi_t *skey, int flags) -{ - gcry_pk_spec_t *pubkey; - gcry_module_t module; - gcry_err_code_t rc; - int i; - - *result = NULL; /* so the caller can always do a mpi_free */ - if (DBG_CIPHER && !fips_mode ()) - { - log_debug ("pubkey_decrypt: algo=%d\n", algorithm); - for(i = 0; i < pubkey_get_nskey (algorithm); i++) - log_mpidump (" skey:", skey[i]); - for(i = 0; i < pubkey_get_nenc (algorithm); i++) - log_mpidump (" data:", data[i]); - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (module) - { - pubkey = (gcry_pk_spec_t *) module->spec; - rc = pubkey->decrypt (algorithm, result, data, skey, flags); - _gcry_module_release (module); - goto ready; - } - - rc = GPG_ERR_PUBKEY_ALGO; - - ready: - ath_mutex_unlock (&pubkeys_registered_lock); - - if (!rc && DBG_CIPHER && !fips_mode ()) - log_mpidump (" plain:", *result); - - return rc; -} - - -/**************** - * This is the interface to the public key signing. - * Sign data with skey and put the result into resarr which - * should be an array of MPIs of size PUBKEY_MAX_NSIG (or less if the - * algorithm allows this - check with pubkey_get_nsig() ) - */ -static gcry_err_code_t -pubkey_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data, - gcry_mpi_t *skey) -{ - gcry_pk_spec_t *pubkey; - gcry_module_t module; - gcry_err_code_t rc; - int i; - - if (DBG_CIPHER && !fips_mode ()) - { - log_debug ("pubkey_sign: algo=%d\n", algorithm); - for(i = 0; i < pubkey_get_nskey (algorithm); i++) - log_mpidump (" skey:", skey[i]); - log_mpidump(" data:", data ); - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (module) - { - pubkey = (gcry_pk_spec_t *) module->spec; - rc = pubkey->sign (algorithm, resarr, data, skey); - _gcry_module_release (module); - goto ready; - } - - rc = GPG_ERR_PUBKEY_ALGO; - - ready: - ath_mutex_unlock (&pubkeys_registered_lock); - - if (!rc && DBG_CIPHER && !fips_mode ()) - for (i = 0; i < pubkey_get_nsig (algorithm); i++) - log_mpidump (" sig:", resarr[i]); - - return rc; -} - -/**************** - * Verify a public key signature. - * Return 0 if the signature is good - */ -static gcry_err_code_t -pubkey_verify (int algorithm, gcry_mpi_t hash, gcry_mpi_t *data, - gcry_mpi_t *pkey, - int (*cmp)(void *, gcry_mpi_t), void *opaquev) -{ - gcry_pk_spec_t *pubkey; - gcry_module_t module; - gcry_err_code_t rc; - int i; - - if (DBG_CIPHER && !fips_mode ()) - { - log_debug ("pubkey_verify: algo=%d\n", algorithm); - for (i = 0; i < pubkey_get_npkey (algorithm); i++) - log_mpidump (" pkey:", pkey[i]); - for (i = 0; i < pubkey_get_nsig (algorithm); i++) - log_mpidump (" sig:", data[i]); - log_mpidump (" hash:", hash); - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (module) - { - pubkey = (gcry_pk_spec_t *) module->spec; - rc = pubkey->verify (algorithm, hash, data, pkey, cmp, opaquev); - _gcry_module_release (module); - goto ready; - } - - rc = GPG_ERR_PUBKEY_ALGO; - - ready: - ath_mutex_unlock (&pubkeys_registered_lock); - return rc; -} - - -/* Internal function. */ -static gcry_err_code_t -sexp_elements_extract (gcry_sexp_t key_sexp, const char *element_names, - gcry_mpi_t *elements, const char *algo_name) -{ - gcry_err_code_t err = 0; - int i, idx; - const char *name; - gcry_sexp_t list; - - for (name = element_names, idx = 0; *name && !err; name++, idx++) - { - list = gcry_sexp_find_token (key_sexp, name, 1); - if (!list) - elements[idx] = NULL; - else - { - elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (list); - if (!elements[idx]) - err = GPG_ERR_INV_OBJ; - } - } - - if (!err) - { - /* Check that all elements are available. */ - for (name = element_names, idx = 0; *name; name++, idx++) - if (!elements[idx]) - break; - if (*name) - { - err = GPG_ERR_NO_OBJ; - /* Some are missing. Before bailing out we test for - optional parameters. */ - if (algo_name && !strcmp (algo_name, "RSA") - && !strcmp (element_names, "nedpqu") ) - { - /* This is RSA. Test whether we got N, E and D and that - the optional P, Q and U are all missing. */ - if (elements[0] && elements[1] && elements[2] - && !elements[3] && !elements[4] && !elements[5]) - err = 0; - } - } - } - - - if (err) - { - for (i = 0; i < idx; i++) - if (elements[i]) - gcry_free (elements[i]); - } - return err; -} - - -/* Internal function used for ecc. Note, that this function makes use - of its intimate knowledge about the ECC parameters from ecc.c. */ -static gcry_err_code_t -sexp_elements_extract_ecc (gcry_sexp_t key_sexp, const char *element_names, - gcry_mpi_t *elements, pk_extra_spec_t *extraspec) - -{ - gcry_err_code_t err = 0; - int idx; - const char *name; - gcry_sexp_t list; - - /* Clear the array for easier error cleanup. */ - for (name = element_names, idx = 0; *name; name++, idx++) - elements[idx] = NULL; - gcry_assert (idx >= 6); /* We know that ECC has at least 6 elements. */ - - /* Init the array with the available curve parameters. */ - for (name = element_names, idx = 0; *name && !err; name++, idx++) - { - list = gcry_sexp_find_token (key_sexp, name, 1); - if (!list) - elements[idx] = NULL; - else - { - elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (list); - if (!elements[idx]) - { - err = GPG_ERR_INV_OBJ; - goto leave; - } - } - } - - /* Check whether a curve parameter has been given and then fill any - missing elements. */ - list = gcry_sexp_find_token (key_sexp, "curve", 5); - if (list) - { - if (extraspec->get_param) - { - char *curve; - gcry_mpi_t params[6]; - - for (idx = 0; idx < DIM(params); idx++) - params[idx] = NULL; - - curve = _gcry_sexp_nth_string (list, 1); - gcry_sexp_release (list); - if (!curve) - { - /* No curve name given (or out of core). */ - err = GPG_ERR_INV_OBJ; - goto leave; - } - err = extraspec->get_param (curve, params); - gcry_free (curve); - if (err) - goto leave; - - for (idx = 0; idx < DIM(params); idx++) - { - if (!elements[idx]) - elements[idx] = params[idx]; - else - mpi_free (params[idx]); - } - } - else - { - gcry_sexp_release (list); - err = GPG_ERR_INV_OBJ; /* "curve" given but ECC not supported. */ - goto leave; - } - } - - /* Check that all parameters are known. */ - for (name = element_names, idx = 0; *name; name++, idx++) - if (!elements[idx]) - { - err = GPG_ERR_NO_OBJ; - goto leave; - } - - leave: - if (err) - { - for (name = element_names, idx = 0; *name; name++, idx++) - if (elements[idx]) - gcry_free (elements[idx]); - } - return err; -} - - - -/**************** - * Convert a S-Exp with either a private or a public key to our - * internal format. Currently we do only support the following - * algorithms: - * dsa - * rsa - * openpgp-dsa - * openpgp-rsa - * openpgp-elg - * openpgp-elg-sig - * ecdsa - * Provide a SE with the first element be either "private-key" or - * or "public-key". It is followed by a list with its first element - * be one of the above algorithm identifiers and the remaning - * elements are pairs with parameter-id and value. - * NOTE: we look through the list to find a list beginning with - * "private-key" or "public-key" - the first one found is used. - * - * Returns: A pointer to an allocated array of MPIs if the return value is - * zero; the caller has to release this array. - * - * Example of a DSA public key: - * (private-key - * (dsa - * (p <mpi>) - * (g <mpi>) - * (y <mpi>) - * (x <mpi>) - * ) - * ) - * The <mpi> are expected to be in GCRYMPI_FMT_USG - */ -static gcry_err_code_t -sexp_to_key (gcry_sexp_t sexp, int want_private, gcry_mpi_t **retarray, - gcry_module_t *retalgo) -{ - gcry_err_code_t err = 0; - gcry_sexp_t list, l2; - char *name; - const char *elems; - gcry_mpi_t *array; - gcry_module_t module; - gcry_pk_spec_t *pubkey; - pk_extra_spec_t *extraspec; - int is_ecc; - - /* Check that the first element is valid. */ - list = gcry_sexp_find_token (sexp, - want_private? "private-key":"public-key", 0); - if (!list) - return GPG_ERR_INV_OBJ; /* Does not contain a key object. */ - - l2 = gcry_sexp_cadr( list ); - gcry_sexp_release ( list ); - list = l2; - name = _gcry_sexp_nth_string (list, 0); - if (!name) - { - gcry_sexp_release ( list ); - return GPG_ERR_INV_OBJ; /* Invalid structure of object. */ - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = gcry_pk_lookup_name (name); - ath_mutex_unlock (&pubkeys_registered_lock); - - /* Fixme: We should make sure that an ECC key is always named "ecc" - and not "ecdsa". "ecdsa" should be used for the signature - itself. We need a function to test whether an algorithm given - with a key is compatible with an application of the key (signing, - encryption). For RSA this is easy, but ECC is the first - algorithm which has many flavours. */ - is_ecc = ( !strcmp (name, "ecdsa") || !strcmp (name, "ecc") ); - gcry_free (name); - - if (!module) - { - gcry_sexp_release (list); - return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ - } - else - { - pubkey = (gcry_pk_spec_t *) module->spec; - extraspec = module->extraspec; - } - - elems = want_private ? pubkey->elements_skey : pubkey->elements_pkey; - array = gcry_calloc (strlen (elems) + 1, sizeof (*array)); - if (!array) - err = gpg_err_code_from_errno (errno); - if (!err) - { - if (is_ecc) - err = sexp_elements_extract_ecc (list, elems, array, extraspec); - else - err = sexp_elements_extract (list, elems, array, pubkey->name); - } - - gcry_sexp_release (list); - - if (err) - { - gcry_free (array); - - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - } - else - { - *retarray = array; - *retalgo = module; - } - - return err; -} - - -static gcry_err_code_t -sexp_to_sig (gcry_sexp_t sexp, gcry_mpi_t **retarray, - gcry_module_t *retalgo) -{ - gcry_err_code_t err = 0; - gcry_sexp_t list, l2; - char *name; - const char *elems; - gcry_mpi_t *array; - gcry_module_t module; - gcry_pk_spec_t *pubkey; - - /* Check that the first element is valid. */ - list = gcry_sexp_find_token( sexp, "sig-val" , 0 ); - if (!list) - return GPG_ERR_INV_OBJ; /* Does not contain a signature value object. */ - - l2 = gcry_sexp_nth (list, 1); - if (!l2) - { - gcry_sexp_release (list); - return GPG_ERR_NO_OBJ; /* No cadr for the sig object. */ - } - name = _gcry_sexp_nth_string (l2, 0); - if (!name) - { - gcry_sexp_release (list); - gcry_sexp_release (l2); - return GPG_ERR_INV_OBJ; /* Invalid structure of object. */ - } - else if (!strcmp (name, "flags")) - { - /* Skip flags, since they are not used but here just for the - sake of consistent S-expressions. */ - gcry_free (name); - gcry_sexp_release (l2); - l2 = gcry_sexp_nth (list, 2); - if (!l2) - { - gcry_sexp_release (list); - return GPG_ERR_INV_OBJ; - } - name = _gcry_sexp_nth_string (l2, 0); - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = gcry_pk_lookup_name (name); - ath_mutex_unlock (&pubkeys_registered_lock); - gcry_free (name); - name = NULL; - - if (!module) - { - gcry_sexp_release (l2); - gcry_sexp_release (list); - return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ - } - else - pubkey = (gcry_pk_spec_t *) module->spec; - - elems = pubkey->elements_sig; - array = gcry_calloc (strlen (elems) + 1 , sizeof *array ); - if (!array) - err = gpg_err_code_from_errno (errno); - - if (!err) - err = sexp_elements_extract (list, elems, array, NULL); - - gcry_sexp_release (l2); - gcry_sexp_release (list); - - if (err) - { - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - - gcry_free (array); - } - else - { - *retarray = array; - *retalgo = module; - } - - return err; -} - - -/**************** - * Take sexp and return an array of MPI as used for our internal decrypt - * function. - * s_data = (enc-val - * [(flags [pkcs1])] - * (<algo> - * (<param_name1> <mpi>) - * ... - * (<param_namen> <mpi>) - * )) - * RET_MODERN is set to true when at least an empty flags list has been found. - */ -static gcry_err_code_t -sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo, - int *ret_modern, int *ret_want_pkcs1, int *flags) -{ - gcry_err_code_t err = 0; - gcry_sexp_t list = NULL, l2 = NULL; - gcry_pk_spec_t *pubkey = NULL; - gcry_module_t module = NULL; - char *name = NULL; - size_t n; - int parsed_flags = 0; - const char *elems; - gcry_mpi_t *array = NULL; - - *ret_want_pkcs1 = 0; - *ret_modern = 0; - - /* Check that the first element is valid. */ - list = gcry_sexp_find_token (sexp, "enc-val" , 0); - if (!list) - { - err = GPG_ERR_INV_OBJ; /* Does not contain an encrypted value object. */ - goto leave; - } - - l2 = gcry_sexp_nth (list, 1); - if (!l2) - { - err = GPG_ERR_NO_OBJ; /* No cdr for the data object. */ - goto leave; - } - - /* Extract identifier of sublist. */ - name = _gcry_sexp_nth_string (l2, 0); - if (!name) - { - err = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ - goto leave; - } - - if (!strcmp (name, "flags")) - { - /* There is a flags element - process it. */ - const char *s; - int i; - - *ret_modern = 1; - for (i = gcry_sexp_length (l2) - 1; i > 0; i--) - { - s = gcry_sexp_nth_data (l2, i, &n); - if (! s) - ; /* Not a data element - ignore. */ - else if (n == 3 && !memcmp (s, "raw", 3)) - ; /* This is just a dummy as it is the default. */ - else if (n == 5 && !memcmp (s, "pkcs1", 5)) - *ret_want_pkcs1 = 1; - else if (n == 11 && ! memcmp (s, "no-blinding", 11)) - parsed_flags |= PUBKEY_FLAG_NO_BLINDING; - else - { - err = GPG_ERR_INV_FLAG; - goto leave; - } - } - - /* Get the next which has the actual data. */ - gcry_sexp_release (l2); - l2 = gcry_sexp_nth (list, 2); - if (!l2) - { - err = GPG_ERR_NO_OBJ; /* No cdr for the data object. */ - goto leave; - } - - /* Extract sublist identifier. */ - gcry_free (name); - name = _gcry_sexp_nth_string (l2, 0); - if (!name) - { - err = GPG_ERR_INV_OBJ; /* Invalid structure of object. */ - goto leave; - } - - gcry_sexp_release (list); - list = l2; - l2 = NULL; - } - - ath_mutex_lock (&pubkeys_registered_lock); - module = gcry_pk_lookup_name (name); - ath_mutex_unlock (&pubkeys_registered_lock); - - if (!module) - { - err = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ - goto leave; - } - pubkey = (gcry_pk_spec_t *) module->spec; - - elems = pubkey->elements_enc; - array = gcry_calloc (strlen (elems) + 1, sizeof (*array)); - if (!array) - { - err = gpg_err_code_from_errno (errno); - goto leave; - } - - err = sexp_elements_extract (list, elems, array, NULL); - - leave: - gcry_sexp_release (list); - gcry_sexp_release (l2); - gcry_free (name); - - if (err) - { - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - gcry_free (array); - } - else - { - *retarray = array; - *retalgo = module; - *flags = parsed_flags; - } - - return err; -} - -/* Take the hash value and convert into an MPI, suitable for - passing to the low level functions. We currently support the - old style way of passing just a MPI and the modern interface which - allows to pass flags so that we can choose between raw and pkcs1 - padding - may be more padding options later. - - (<mpi>) - or - (data - [(flags [pkcs1])] - [(hash <algo> <value>)] - [(value <text>)] - ) - - Either the VALUE or the HASH element must be present for use - with signatures. VALUE is used for encryption. - - NBITS is the length of the key in bits. - -*/ -static gcry_err_code_t -sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi, - int for_encryption, int *flags) +pubkey_get_nenc (int algo) { - gcry_err_code_t rc = 0; - gcry_sexp_t ldata, lhash, lvalue; - int i; - size_t n; - const char *s; - int is_raw = 0, is_pkcs1 = 0, unknown_flag=0; - int parsed_flags = 0, dummy_flags; - - if (! flags) - flags = &dummy_flags; - - *ret_mpi = NULL; - ldata = gcry_sexp_find_token (input, "data", 0); - if (!ldata) - { /* assume old style */ - *ret_mpi = gcry_sexp_nth_mpi (input, 0, 0); - return *ret_mpi ? GPG_ERR_NO_ERROR : GPG_ERR_INV_OBJ; - } + gcry_pk_spec_t *spec = spec_from_algo (algo); - /* see whether there is a flags object */ - { - gcry_sexp_t lflags = gcry_sexp_find_token (ldata, "flags", 0); - if (lflags) - { /* parse the flags list. */ - for (i=gcry_sexp_length (lflags)-1; i > 0; i--) - { - s = gcry_sexp_nth_data (lflags, i, &n); - if (!s) - ; /* not a data element*/ - else if ( n == 3 && !memcmp (s, "raw", 3)) - is_raw = 1; - else if ( n == 5 && !memcmp (s, "pkcs1", 5)) - is_pkcs1 = 1; - else if (n == 11 && ! memcmp (s, "no-blinding", 11)) - parsed_flags |= PUBKEY_FLAG_NO_BLINDING; - else - unknown_flag = 1; - } - gcry_sexp_release (lflags); - } - } - - if (!is_pkcs1 && !is_raw) - is_raw = 1; /* default to raw */ - - /* Get HASH or MPI */ - lhash = gcry_sexp_find_token (ldata, "hash", 0); - lvalue = lhash? NULL : gcry_sexp_find_token (ldata, "value", 0); - - if (!(!lhash ^ !lvalue)) - rc = GPG_ERR_INV_OBJ; /* none or both given */ - else if (unknown_flag) - rc = GPG_ERR_INV_FLAG; - else if (is_raw && is_pkcs1 && !for_encryption) - rc = GPG_ERR_CONFLICT; - else if (is_raw && lvalue) - { - *ret_mpi = gcry_sexp_nth_mpi (lvalue, 1, 0); - if (!*ret_mpi) - rc = GPG_ERR_INV_OBJ; - } - else if (is_pkcs1 && lvalue && for_encryption) - { - /* Create pkcs#1 block type 2 padding. */ - unsigned char *frame = NULL; - size_t nframe = (nbits+7) / 8; - const void * value; - size_t valuelen; - unsigned char *p; - - if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen ) - rc = GPG_ERR_INV_OBJ; - else if (valuelen + 7 > nframe || !nframe) - { - /* Can't encode a VALUELEN value in a NFRAME bytes frame. */ - rc = GPG_ERR_TOO_SHORT; /* the key is too short */ - } - else if ( !(frame = gcry_malloc_secure (nframe))) - rc = gpg_err_code_from_errno (errno); - else - { - n = 0; - frame[n++] = 0; - frame[n++] = 2; /* block type */ - i = nframe - 3 - valuelen; - gcry_assert (i > 0); - p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM); - /* Replace zero bytes by new values. */ - for (;;) - { - int j, k; - unsigned char *pp; - - /* Count the zero bytes. */ - for (j=k=0; j < i; j++) - { - if (!p[j]) - k++; - } - if (!k) - break; /* Okay: no (more) zero bytes. */ - - k += k/128 + 3; /* Better get some more. */ - pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM); - for (j=0; j < i && k; ) - { - if (!p[j]) - p[j] = pp[--k]; - if (p[j]) - j++; - } - gcry_free (pp); - } - memcpy (frame+n, p, i); - n += i; - gcry_free (p); - - frame[n++] = 0; - memcpy (frame+n, value, valuelen); - n += valuelen; - gcry_assert (n == nframe); - - /* FIXME, error checking? */ - gcry_mpi_scan (ret_mpi, GCRYMPI_FMT_USG, frame, n, &nframe); - } - - gcry_free(frame); - } - else if (is_pkcs1 && lhash && !for_encryption) - { - /* Create pkcs#1 block type 1 padding. */ - if (gcry_sexp_length (lhash) != 3) - rc = GPG_ERR_INV_OBJ; - else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n ) - rc = GPG_ERR_INV_OBJ; - else - { - static struct { const char *name; int algo; } hashnames[] = - { { "sha1", GCRY_MD_SHA1 }, - { "md5", GCRY_MD_MD5 }, - { "sha256", GCRY_MD_SHA256 }, - { "ripemd160", GCRY_MD_RMD160 }, - { "rmd160", GCRY_MD_RMD160 }, - { "sha384", GCRY_MD_SHA384 }, - { "sha512", GCRY_MD_SHA512 }, - { "sha224", GCRY_MD_SHA224 }, - { "md2", GCRY_MD_MD2 }, - { "md4", GCRY_MD_MD4 }, - { "tiger", GCRY_MD_TIGER }, - { "haval", GCRY_MD_HAVAL }, - { NULL, 0 } - }; - int algo; - byte asn[100]; - byte *frame = NULL; - size_t nframe = (nbits+7) / 8; - const void * value; - size_t valuelen; - size_t asnlen, dlen; - - for (i=0; hashnames[i].name; i++) - { - if ( strlen (hashnames[i].name) == n - && !memcmp (hashnames[i].name, s, n)) - break; - } - if (hashnames[i].name) - algo = hashnames[i].algo; - else - { - /* In case of not listed or dynamically allocated hash - algorithm we fall back to this somewhat slower - method. Further, it also allows to use OIDs as - algorithm names. */ - char *tmpname; - - tmpname = gcry_malloc (n+1); - if (!tmpname) - algo = 0; /* Out of core - silently give up. */ - else - { - memcpy (tmpname, s, n); - tmpname[n] = 0; - algo = gcry_md_map_name (tmpname); - gcry_free (tmpname); - } - } - - asnlen = DIM(asn); - dlen = gcry_md_get_algo_dlen (algo); - - if (!algo) - rc = GPG_ERR_DIGEST_ALGO; - else if ( !(value=gcry_sexp_nth_data (lhash, 2, &valuelen)) - || !valuelen ) - rc = GPG_ERR_INV_OBJ; - else if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen)) - { - /* We don't have yet all of the above algorithms. */ - rc = GPG_ERR_NOT_IMPLEMENTED; - } - else if ( valuelen != dlen ) - { - /* Hash value does not match the length of digest for - the given algorithm. */ - rc = GPG_ERR_CONFLICT; - } - else if( !dlen || dlen + asnlen + 4 > nframe) - { - /* Can't encode an DLEN byte digest MD into a NFRAME - byte frame. */ - rc = GPG_ERR_TOO_SHORT; - } - else if ( !(frame = gcry_malloc (nframe)) ) - rc = gpg_err_code_from_errno (errno); - else - { /* Assemble the pkcs#1 block type 1. */ - n = 0; - frame[n++] = 0; - frame[n++] = 1; /* block type */ - i = nframe - valuelen - asnlen - 3 ; - gcry_assert (i > 1); - memset (frame+n, 0xff, i ); - n += i; - frame[n++] = 0; - memcpy (frame+n, asn, asnlen); - n += asnlen; - memcpy (frame+n, value, valuelen ); - n += valuelen; - gcry_assert (n == nframe); - - /* Convert it into an MPI. FIXME: error checking? */ - gcry_mpi_scan (ret_mpi, GCRYMPI_FMT_USG, frame, n, &nframe); - } - - gcry_free (frame); - } - } - else - rc = GPG_ERR_CONFLICT; - - gcry_sexp_release (ldata); - gcry_sexp_release (lhash); - gcry_sexp_release (lvalue); - - if (!rc) - *flags = parsed_flags; - - return rc; + return spec? strlen (spec->elements_enc) : 0; } + /* Do a PK encrypt operation - + Caller has to provide a public key as the SEXP pkey and data as a - SEXP with just one MPI in it. Alternativly S_DATA might be a + SEXP with just one MPI in it. Alternatively S_DATA might be a complex S-Expression, similar to the one used for signature verification. This provides a flag which allows to handle PKCS#1 - block type 2 padding. The function returns a a sexp which may be + block type 2 padding. The function returns a sexp which may be passed to to pk_decrypt. - + Returns: 0 or an errorcode. - - s_data = See comment for sexp_data_to_mpi + + s_data = See comment for _gcry_pk_util_data_to_mpi s_pkey = <key-as-defined-in-sexp_to_key> r_ciph = (enc-val (<algo> @@ -1585,141 +309,44 @@ sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi, )) */ -gcry_error_t -gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey) +gcry_err_code_t +_gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey) { - gcry_mpi_t *pkey = NULL, data = NULL, *ciph = NULL; - const char *algo_name, *algo_elems; - int flags; gcry_err_code_t rc; - gcry_pk_spec_t *pubkey = NULL; - gcry_module_t module = NULL; + gcry_pk_spec_t *spec; + gcry_sexp_t keyparms; *r_ciph = NULL; - REGISTER_DEFAULT_PUBKEYS; - - /* Get the key. */ - rc = sexp_to_key (s_pkey, 0, &pkey, &module); - if (rc) - goto leave; - - gcry_assert (module); - pubkey = (gcry_pk_spec_t *) module->spec; - - /* If aliases for the algorithm name exists, take the first one - instead of the regular name to adhere to SPKI conventions. We - assume that the first alias name is the lowercase version of the - regular one. This change is required for compatibility with - 1.1.12 generated S-expressions. */ - algo_name = pubkey->aliases? *pubkey->aliases : NULL; - if (!algo_name || !*algo_name) - algo_name = pubkey->name; - - algo_elems = pubkey->elements_enc; - - /* Get the stuff we want to encrypt. */ - rc = sexp_data_to_mpi (s_data, gcry_pk_get_nbits (s_pkey), &data, 1, - &flags); + rc = spec_from_sexp (s_pkey, 0, &spec, &keyparms); if (rc) goto leave; - /* Now we can encrypt DATA to CIPH. */ - ciph = gcry_calloc (strlen (algo_elems) + 1, sizeof (*ciph)); - if (!ciph) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - rc = pubkey_encrypt (module->mod_id, ciph, data, pkey, flags); - mpi_free (data); - data = NULL; - if (rc) - goto leave; - - /* We did it. Now build the return list */ - { - char *string, *p; - int i; - size_t nelem = strlen (algo_elems); - size_t needed = 19 + strlen (algo_name) + (nelem * 5); - void **arg_list; - - /* Build the string. */ - string = p = gcry_malloc (needed); - if (!string) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - p = stpcpy ( p, "(enc-val(" ); - p = stpcpy ( p, algo_name ); - for (i=0; algo_elems[i]; i++ ) - { - *p++ = '('; - *p++ = algo_elems[i]; - p = stpcpy ( p, "%m)" ); - } - strcpy ( p, "))" ); - - /* And now the ugly part: We don't have a function to pass an - * array to a format string, so we have to do it this way :-(. */ - /* FIXME: There is now such a format specifier, so we can - change the code to be more clear. */ - arg_list = malloc (nelem * sizeof *arg_list); - if (!arg_list) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - - for (i = 0; i < nelem; i++) - arg_list[i] = ciph + i; - - rc = gcry_sexp_build_array (r_ciph, NULL, string, arg_list); - free (arg_list); - if (rc) - BUG (); - gcry_free (string); - } + if (spec->encrypt) + rc = spec->encrypt (r_ciph, s_data, keyparms); + else + rc = GPG_ERR_NOT_IMPLEMENTED; leave: - if (pkey) - { - release_mpi_array (pkey); - gcry_free (pkey); - } - - if (ciph) - { - release_mpi_array (ciph); - gcry_free (ciph); - } - - if (module) - { - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - } - - return gcry_error (rc); + sexp_release (keyparms); + return rc; } -/* + +/* Do a PK decrypt operation - + Caller has to provide a secret key as the SEXP skey and data in a format as created by gcry_pk_encrypt. For historic reasons the function returns simply an MPI as an S-expression part; this is deprecated and the new method should be used which returns a real S-expressionl this is selected by adding at least an empty flags list to S_DATA. - + Returns: 0 or an errorcode. - + s_data = (enc-val - [(flags)] + [(flags [raw, pkcs1, oaep])] (<algo> (<param_name1> <mpi>) ... @@ -1728,207 +355,86 @@ gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey) s_skey = <key-as-defined-in-sexp_to_key> r_plain= Either an incomplete S-expression without the parentheses or if the flags list is used (even if empty) a real S-expression: - (value PLAIN). + (value PLAIN). In raw mode (or no flags given) the returned value + is to be interpreted as a signed MPI, thus it may have an extra + leading zero octet even if not included in the original data. + With pkcs1 or oaep decoding enabled the returned value is a + verbatim octet string. */ -gcry_error_t -gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey) +gcry_err_code_t +_gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey) { - gcry_mpi_t *skey = NULL, *data = NULL, plain = NULL; - int modern, want_pkcs1, flags; gcry_err_code_t rc; - gcry_module_t module_enc = NULL, module_key = NULL; - gcry_pk_spec_t *pubkey = NULL; + gcry_pk_spec_t *spec; + gcry_sexp_t keyparms; *r_plain = NULL; - REGISTER_DEFAULT_PUBKEYS; - - rc = sexp_to_key (s_skey, 1, &skey, &module_key); - if (rc) - goto leave; - - rc = sexp_to_enc (s_data, &data, &module_enc, &modern, &want_pkcs1, &flags); + rc = spec_from_sexp (s_skey, 1, &spec, &keyparms); if (rc) goto leave; - - if (module_key->mod_id != module_enc->mod_id) - { - rc = GPG_ERR_CONFLICT; /* Key algo does not match data algo. */ - goto leave; - } - pubkey = (gcry_pk_spec_t *) module_key->spec; - - rc = pubkey_decrypt (module_key->mod_id, &plain, data, skey, flags); - if (rc) - goto leave; + if (spec->decrypt) + rc = spec->decrypt (r_plain, s_data, keyparms); + else + rc = GPG_ERR_NOT_IMPLEMENTED; - if (gcry_sexp_build (r_plain, NULL, modern? "(value %m)" : "%m", plain)) - BUG (); - leave: - if (skey) - { - release_mpi_array (skey); - gcry_free (skey); - } - - if (plain) - mpi_free (plain); - - if (data) - { - release_mpi_array (data); - gcry_free (data); - } - - if (module_key || module_enc) - { - ath_mutex_lock (&pubkeys_registered_lock); - if (module_key) - _gcry_module_release (module_key); - if (module_enc) - _gcry_module_release (module_enc); - ath_mutex_unlock (&pubkeys_registered_lock); - } - - return gcry_error (rc); + sexp_release (keyparms); + return rc; } /* Create a signature. - + Caller has to provide a secret key as the SEXP skey and data expressed as a SEXP list hash with only one element which should instantly be available as a MPI. Alternatively the structure given below may be used for S_HASH, it provides the abiliy to pass flags - to the operation; the only flag defined by now is "pkcs1" which - does PKCS#1 block type 1 style padding. - + to the operation; the flags defined by now are "pkcs1" which does + PKCS#1 block type 1 style padding and "pss" for PSS encoding. + Returns: 0 or an errorcode. In case of 0 the function returns a new SEXP with the signature value; the structure of this signature depends on the other arguments but is always suitable to be passed to gcry_pk_verify - - s_hash = See comment for sexp_data_to_mpi - + + s_hash = See comment for _gcry-pk_util_data_to_mpi + s_skey = <key-as-defined-in-sexp_to_key> r_sig = (sig-val (<algo> (<param_name1> <mpi>) ... (<param_namen> <mpi>)) - [(hash algo)]) + [(hash algo)]) Note that (hash algo) in R_SIG is not used. */ -gcry_error_t -gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey) +gcry_err_code_t +_gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey) { - gcry_mpi_t *skey = NULL, hash = NULL, *result = NULL; - gcry_pk_spec_t *pubkey = NULL; - gcry_module_t module = NULL; - const char *algo_name, *algo_elems; - int i; gcry_err_code_t rc; + gcry_pk_spec_t *spec; + gcry_sexp_t keyparms; *r_sig = NULL; - REGISTER_DEFAULT_PUBKEYS; - - rc = sexp_to_key (s_skey, 1, &skey, &module); - if (rc) - goto leave; - - gcry_assert (module); - pubkey = (gcry_pk_spec_t *) module->spec; - algo_name = pubkey->aliases? *pubkey->aliases : NULL; - if (!algo_name || !*algo_name) - algo_name = pubkey->name; - - algo_elems = pubkey->elements_sig; - - /* Get the stuff we want to sign. Note that pk_get_nbits does also - work on a private key. */ - rc = sexp_data_to_mpi (s_hash, gcry_pk_get_nbits (s_skey), - &hash, 0, NULL); + rc = spec_from_sexp (s_skey, 1, &spec, &keyparms); if (rc) goto leave; - result = gcry_calloc (strlen (algo_elems) + 1, sizeof (*result)); - if (!result) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - rc = pubkey_sign (module->mod_id, result, hash, skey); - if (rc) - goto leave; - - { - char *string, *p; - size_t nelem, needed = strlen (algo_name) + 20; - void **arg_list; - - nelem = strlen (algo_elems); - - /* Count elements, so that we can allocate enough space. */ - needed += 10 * nelem; - - /* Build the string. */ - string = p = gcry_malloc (needed); - if (!string) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - p = stpcpy (p, "(sig-val("); - p = stpcpy (p, algo_name); - for (i = 0; algo_elems[i]; i++) - { - *p++ = '('; - *p++ = algo_elems[i]; - p = stpcpy (p, "%m)"); - } - strcpy (p, "))"); - - arg_list = malloc (nelem * sizeof *arg_list); - if (!arg_list) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - - for (i = 0; i < nelem; i++) - arg_list[i] = result + i; - - rc = gcry_sexp_build_array (r_sig, NULL, string, arg_list); - free (arg_list); - if (rc) - BUG (); - gcry_free (string); - } + if (spec->sign) + rc = spec->sign (r_sig, s_hash, keyparms); + else + rc = GPG_ERR_NOT_IMPLEMENTED; leave: - if (skey) - { - release_mpi_array (skey); - gcry_free (skey); - } - - if (hash) - mpi_free (hash); - - if (result) - { - release_mpi_array (result); - gcry_free (result); - } - - return gcry_error (rc); + sexp_release (keyparms); + return rc; } @@ -1939,63 +445,25 @@ gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey) hashvalue data. Public key has to be a standard public key given as an S-Exp, sig is a S-Exp as returned from gcry_pk_sign and data must be an S-Exp like the one in sign too. */ -gcry_error_t -gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey) +gcry_err_code_t +_gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey) { - gcry_module_t module_key = NULL, module_sig = NULL; - gcry_mpi_t *pkey = NULL, hash = NULL, *sig = NULL; gcry_err_code_t rc; + gcry_pk_spec_t *spec; + gcry_sexp_t keyparms; - REGISTER_DEFAULT_PUBKEYS; - - rc = sexp_to_key (s_pkey, 0, &pkey, &module_key); - if (rc) - goto leave; - - rc = sexp_to_sig (s_sig, &sig, &module_sig); - if (rc) - goto leave; - - /* Fixme: Check that the algorithm of S_SIG is compatible to the one - of S_PKEY. */ - - if (module_key->mod_id != module_sig->mod_id) - { - rc = GPG_ERR_CONFLICT; - goto leave; - } - - rc = sexp_data_to_mpi (s_hash, gcry_pk_get_nbits (s_pkey), &hash, 0, 0); + rc = spec_from_sexp (s_pkey, 0, &spec, &keyparms); if (rc) goto leave; - rc = pubkey_verify (module_key->mod_id, hash, sig, pkey, NULL, NULL); + if (spec->verify) + rc = spec->verify (s_sig, s_hash, keyparms); + else + rc = GPG_ERR_NOT_IMPLEMENTED; leave: - if (pkey) - { - release_mpi_array (pkey); - gcry_free (pkey); - } - if (sig) - { - release_mpi_array (sig); - gcry_free (sig); - } - if (hash) - mpi_free (hash); - - if (module_key || module_sig) - { - ath_mutex_lock (&pubkeys_registered_lock); - if (module_key) - _gcry_module_release (module_key); - if (module_sig) - _gcry_module_release (module_sig); - ath_mutex_unlock (&pubkeys_registered_lock); - } - - return gcry_error (rc); + sexp_release (keyparms); + return rc; } @@ -2004,28 +472,29 @@ gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey) This may be used either for a public or a secret key to see whether the internal structure is okay. - + Returns: 0 or an errorcode. - - s_key = <key-as-defined-in-sexp_to_key> */ -gcry_error_t -gcry_pk_testkey (gcry_sexp_t s_key) + + NOTE: We currently support only secret key checking. */ +gcry_err_code_t +_gcry_pk_testkey (gcry_sexp_t s_key) { - gcry_module_t module = NULL; - gcry_mpi_t *key = NULL; gcry_err_code_t rc; - - REGISTER_DEFAULT_PUBKEYS; + gcry_pk_spec_t *spec; + gcry_sexp_t keyparms; - /* Note we currently support only secret key checking. */ - rc = sexp_to_key (s_key, 1, &key, &module); - if (! rc) - { - rc = pubkey_check_secret_key (module->mod_id, key); - release_mpi_array (key); - gcry_free (key); - } - return gcry_error (rc); + rc = spec_from_sexp (s_key, 1, &spec, &keyparms); + if (rc) + goto leave; + + if (spec->check_secret_key) + rc = spec->check_secret_key (keyparms); + else + rc = GPG_ERR_NOT_IMPLEMENTED; + + leave: + sexp_release (keyparms); + return rc; } @@ -2062,41 +531,26 @@ gcry_pk_testkey (gcry_sexp_t s_key) (pm1-factors n1 n2 ... nn) )) */ -gcry_error_t -gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms) +gcry_err_code_t +_gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms) { - gcry_pk_spec_t *pubkey = NULL; - gcry_module_t module = NULL; + gcry_pk_spec_t *spec = NULL; gcry_sexp_t list = NULL; gcry_sexp_t l2 = NULL; - gcry_sexp_t l3 = NULL; char *name = NULL; - size_t n; - gcry_err_code_t rc = GPG_ERR_NO_ERROR; - int i; - const char *algo_name = NULL; - int algo; - const char *sec_elems = NULL, *pub_elems = NULL; - gcry_mpi_t skey[12]; - gcry_mpi_t *factors = NULL; - gcry_sexp_t extrainfo = NULL; - unsigned int nbits = 0; - unsigned long use_e = 0; - - skey[0] = NULL; - *r_key = NULL; + gcry_err_code_t rc; - REGISTER_DEFAULT_PUBKEYS; + *r_key = NULL; - list = gcry_sexp_find_token (s_parms, "genkey", 0); + list = sexp_find_token (s_parms, "genkey", 0); if (!list) { rc = GPG_ERR_INV_OBJ; /* Does not contain genkey data. */ goto leave; } - l2 = gcry_sexp_cadr (list); - gcry_sexp_release (list); + l2 = sexp_cadr (list); + sexp_release (list); list = l2; l2 = NULL; if (! list) @@ -2111,286 +565,90 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms) rc = GPG_ERR_INV_OBJ; /* Algo string missing. */ goto leave; } - - ath_mutex_lock (&pubkeys_registered_lock); - module = gcry_pk_lookup_name (name); - ath_mutex_unlock (&pubkeys_registered_lock); - gcry_free (name); + + spec = spec_from_name (name); + xfree (name); name = NULL; - if (!module) + if (!spec) { rc = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */ goto leave; } - - pubkey = (gcry_pk_spec_t *) module->spec; - algo = module->mod_id; - algo_name = pubkey->aliases? *pubkey->aliases : NULL; - if (!algo_name || !*algo_name) - algo_name = pubkey->name; - pub_elems = pubkey->elements_pkey; - sec_elems = pubkey->elements_skey; - if (strlen (sec_elems) >= DIM(skey)) - BUG (); - - /* Handle the optional rsa-use-e element. Actually this belong into - the algorithm module but we have this parameter in the public - module API, so we need to parse it right here. */ - l2 = gcry_sexp_find_token (list, "rsa-use-e", 0); - if (l2) - { - char buf[50]; - const char *s; - s = gcry_sexp_nth_data (l2, 1, &n); - if ( !s || n >= DIM (buf) - 1 ) - { - rc = GPG_ERR_INV_OBJ; /* No value or value too large. */ - goto leave; - } - memcpy (buf, s, n); - buf[n] = 0; - use_e = strtoul (buf, NULL, 0); - gcry_sexp_release (l2); - l2 = NULL; - } + if (spec->generate) + rc = spec->generate (list, r_key); else - use_e = 65537; /* Not given, use the value generated by old versions. */ - - - /* Get the "nbits" parameter. */ - l2 = gcry_sexp_find_token (list, "nbits", 0); - if (l2) - { - char buf[50]; - const char *s; - - s = gcry_sexp_nth_data (l2, 1, &n); - if (!s || n >= DIM (buf) - 1 ) - { - rc = GPG_ERR_INV_OBJ; /* NBITS given without a cdr. */ - goto leave; - } - memcpy (buf, s, n); - buf[n] = 0; - nbits = (unsigned int)strtoul (buf, NULL, 0); - gcry_sexp_release (l2); l2 = NULL; - } - else - nbits = 0; - - /* Pass control to the algorithm module. */ - rc = pubkey_generate (module->mod_id, nbits, use_e, list, skey, - &factors, &extrainfo); - gcry_sexp_release (list); list = NULL; - if (rc) - goto leave; - - /* Key generation succeeded: Build an S-expression. */ - { - char *string, *p; - size_t nelem=0, nelem_cp = 0, needed=0; - gcry_mpi_t mpis[30]; - - /* Estimate size of format string. */ - nelem = strlen (pub_elems) + strlen (sec_elems); - if (factors) - { - for (i = 0; factors[i]; i++) - nelem++; - } - nelem_cp = nelem; - - needed += nelem * 10; - /* (+5 is for EXTRAINFO ("%S")). */ - needed += 2 * strlen (algo_name) + 300 + 5; - if (nelem > DIM (mpis)) - BUG (); - - /* Build the string. */ - nelem = 0; - string = p = gcry_malloc (needed); - if (!string) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - p = stpcpy (p, "(key-data"); - p = stpcpy (p, "(public-key("); - p = stpcpy (p, algo_name); - for(i = 0; pub_elems[i]; i++) - { - *p++ = '('; - *p++ = pub_elems[i]; - p = stpcpy (p, "%m)"); - mpis[nelem++] = skey[i]; - } - p = stpcpy (p, "))"); - p = stpcpy (p, "(private-key("); - p = stpcpy (p, algo_name); - for (i = 0; sec_elems[i]; i++) - { - *p++ = '('; - *p++ = sec_elems[i]; - p = stpcpy (p, "%m)"); - mpis[nelem++] = skey[i]; - } - p = stpcpy (p, "))"); - - /* Hack to make release_mpi_array() work. */ - skey[i] = NULL; - - if (extrainfo) - { - /* If we have extrainfo we should not have any factors. */ - p = stpcpy (p, "%S"); - } - else if (factors && factors[0]) - { - p = stpcpy (p, "(misc-key-info(pm1-factors"); - for(i = 0; factors[i]; i++) - { - p = stpcpy (p, "%m"); - mpis[nelem++] = factors[i]; - } - p = stpcpy (p, "))"); - } - strcpy (p, ")"); - gcry_assert (p - string < needed); - - while (nelem < DIM (mpis)) - mpis[nelem++] = NULL; - - { - int elem_n = strlen (pub_elems) + strlen (sec_elems); - void **arg_list; - - /* Allocate one extra for EXTRAINFO ("%S"). */ - arg_list = gcry_calloc (nelem_cp+1, sizeof *arg_list); - if (!arg_list) - { - rc = gpg_err_code_from_errno (errno); - goto leave; - } - for (i = 0; i < elem_n; i++) - arg_list[i] = mpis + i; - if (extrainfo) - arg_list[i] = &extrainfo; - else if (factors && factors[0]) - { - for (; i < nelem_cp; i++) - arg_list[i] = factors + i - elem_n; - } - - rc = gcry_sexp_build_array (r_key, NULL, string, arg_list); - gcry_free (arg_list); - if (rc) - BUG (); - gcry_assert (DIM (mpis) == 30); /* Reminder to make sure that - the array gets increased if - new parameters are added. */ - } - gcry_free (string); - } + rc = GPG_ERR_NOT_IMPLEMENTED; leave: - gcry_free (name); - gcry_sexp_release (extrainfo); - release_mpi_array (skey); - /* Don't free SKEY itself, it is an stack allocated array. */ - - if (factors) - { - release_mpi_array ( factors ); - gcry_free (factors); - } - - gcry_sexp_release (l3); - gcry_sexp_release (l2); - gcry_sexp_release (list); + sexp_release (list); + xfree (name); + sexp_release (l2); - if (module) - { - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - } - - return gcry_error (rc); + return rc; } -/* +/* Get the number of nbits from the public key. Hmmm: Should we have really this function or is it better to have a more general function to retrieve different properties of the key? */ unsigned int -gcry_pk_get_nbits (gcry_sexp_t key) +_gcry_pk_get_nbits (gcry_sexp_t key) { - gcry_module_t module = NULL; - gcry_pk_spec_t *pubkey; - gcry_mpi_t *keyarr = NULL; - unsigned int nbits = 0; - gcry_err_code_t rc; - - REGISTER_DEFAULT_PUBKEYS; - - rc = sexp_to_key (key, 0, &keyarr, &module); - if (rc == GPG_ERR_INV_OBJ) - rc = sexp_to_key (key, 1, &keyarr, &module); - if (rc) - return 0; /* Error - 0 is a suitable indication for that. */ + gcry_pk_spec_t *spec; + gcry_sexp_t parms; + unsigned int nbits; - pubkey = (gcry_pk_spec_t *) module->spec; - nbits = (*pubkey->get_nbits) (module->mod_id, keyarr); - - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); + /* Parsing KEY might be considered too much overhead. For example + for RSA we would only need to look at P and stop parsing right + away. However, with ECC things are more complicate in that only + a curve name might be specified. Thus we need to tear the sexp + apart. */ - release_mpi_array (keyarr); - gcry_free (keyarr); + if (spec_from_sexp (key, 0, &spec, &parms)) + return 0; /* Error - 0 is a suitable indication for that. */ + nbits = spec->get_nbits (parms); + sexp_release (parms); return nbits; } /* Return the so called KEYGRIP which is the SHA-1 hash of the public - key parameters expressed in a way depended on the algorithm. + key parameters expressed in a way depending on the algorithm. ARRAY must either be 20 bytes long or NULL; in the latter case a newly allocated array of that size is returned, otherwise ARRAY or NULL is returned to indicate an error which is most likely an unknown algorithm. The function accepts public or secret keys. */ unsigned char * -gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array) +_gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array) { - gcry_sexp_t list = NULL, l2 = NULL; - gcry_pk_spec_t *pubkey = NULL; - gcry_module_t module = NULL; - pk_extra_spec_t *extraspec; + gcry_sexp_t list = NULL; + gcry_sexp_t l2 = NULL; + gcry_pk_spec_t *spec = NULL; const char *s; char *name = NULL; int idx; const char *elems; gcry_md_hd_t md = NULL; - - REGISTER_DEFAULT_PUBKEYS; + int okay = 0; /* Check that the first element is valid. */ - list = gcry_sexp_find_token (key, "public-key", 0); + list = sexp_find_token (key, "public-key", 0); if (! list) - list = gcry_sexp_find_token (key, "private-key", 0); + list = sexp_find_token (key, "private-key", 0); if (! list) - list = gcry_sexp_find_token (key, "protected-private-key", 0); + list = sexp_find_token (key, "protected-private-key", 0); if (! list) - list = gcry_sexp_find_token (key, "shadowed-private-key", 0); + list = sexp_find_token (key, "shadowed-private-key", 0); if (! list) return NULL; /* No public- or private-key object. */ - l2 = gcry_sexp_cadr (list); - gcry_sexp_release (list); + l2 = sexp_cadr (list); + sexp_release (list); list = l2; l2 = NULL; @@ -2398,27 +656,21 @@ gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array) if (!name) goto fail; /* Invalid structure of object. */ - ath_mutex_lock (&pubkeys_registered_lock); - module = gcry_pk_lookup_name (name); - ath_mutex_unlock (&pubkeys_registered_lock); - - if (!module) + spec = spec_from_name (name); + if (!spec) goto fail; /* Unknown algorithm. */ - pubkey = (gcry_pk_spec_t *) module->spec; - extraspec = module->extraspec; - - elems = pubkey->elements_grip; + elems = spec->elements_grip; if (!elems) goto fail; /* No grip parameter. */ - - if (gcry_md_open (&md, GCRY_MD_SHA1, 0)) + + if (_gcry_md_open (&md, GCRY_MD_SHA1, 0)) goto fail; - if (extraspec && extraspec->comp_keygrip) + if (spec->comp_keygrip) { /* Module specific method to compute a keygrip. */ - if (extraspec->comp_keygrip (md, list)) + if (spec->comp_keygrip (md, list)) goto fail; } else @@ -2429,49 +681,102 @@ gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array) const char *data; size_t datalen; char buf[30]; - - l2 = gcry_sexp_find_token (list, s, 1); + + l2 = sexp_find_token (list, s, 1); if (! l2) goto fail; - data = gcry_sexp_nth_data (l2, 1, &datalen); + data = sexp_nth_data (l2, 1, &datalen); if (! data) goto fail; - + snprintf (buf, sizeof buf, "(1:%c%u:", *s, (unsigned int)datalen); - gcry_md_write (md, buf, strlen (buf)); - gcry_md_write (md, data, datalen); - gcry_sexp_release (l2); - gcry_md_write (md, ")", 1); + _gcry_md_write (md, buf, strlen (buf)); + _gcry_md_write (md, data, datalen); + sexp_release (l2); + l2 = NULL; + _gcry_md_write (md, ")", 1); } } - + if (!array) { - array = gcry_malloc (20); + array = xtrymalloc (20); if (! array) goto fail; } - memcpy (array, gcry_md_read (md, GCRY_MD_SHA1), 20); - gcry_md_close (md); - gcry_sexp_release (list); - return array; + memcpy (array, _gcry_md_read (md, GCRY_MD_SHA1), 20); + okay = 1; fail: - gcry_free (name); - gcry_sexp_release (l2); - gcry_md_close (md); - gcry_sexp_release (list); - return NULL; + xfree (name); + sexp_release (l2); + _gcry_md_close (md); + sexp_release (list); + return okay? array : NULL; } -gcry_error_t -gcry_pk_ctl (int cmd, void *buffer, size_t buflen) + +const char * +_gcry_pk_get_curve (gcry_sexp_t key, int iterator, unsigned int *r_nbits) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + const char *result = NULL; + gcry_pk_spec_t *spec; + gcry_sexp_t keyparms = NULL; + + if (r_nbits) + *r_nbits = 0; - REGISTER_DEFAULT_PUBKEYS; + if (key) + { + iterator = 0; + + if (spec_from_sexp (key, 0, &spec, &keyparms)) + return NULL; + } + else + { + spec = spec_from_name ("ecc"); + if (!spec) + return NULL; + } + + if (spec->get_curve) + result = spec->get_curve (keyparms, iterator, r_nbits); + + sexp_release (keyparms); + return result; +} + + + +gcry_sexp_t +_gcry_pk_get_param (int algo, const char *name) +{ + gcry_sexp_t result = NULL; + gcry_pk_spec_t *spec = NULL; + + algo = map_algo (algo); + + if (algo != GCRY_PK_ECC) + return NULL; + + spec = spec_from_name ("ecc"); + if (spec) + { + if (spec && spec->get_curve_param) + result = spec->get_curve_param (name); + } + return result; +} + + + +gcry_err_code_t +_gcry_pk_ctl (int cmd, void *buffer, size_t buflen) +{ + gcry_err_code_t rc = 0; switch (cmd) { @@ -2479,16 +784,16 @@ gcry_pk_ctl (int cmd, void *buffer, size_t buflen) /* This one expects a buffer pointing to an integer with the algo number. */ if ((! buffer) || (buflen != sizeof (int))) - err = GPG_ERR_INV_ARG; + rc = GPG_ERR_INV_ARG; else disable_pubkey_algo (*((int *) buffer)); break; default: - err = GPG_ERR_INV_OP; + rc = GPG_ERR_INV_OP; } - return gcry_error (err); + return rc; } @@ -2503,20 +808,20 @@ gcry_pk_ctl (int cmd, void *buffer, size_t buflen) care or a combination of the GCRY_PK_USAGE_xxx flags; GCRYCTL_GET_ALGO_USAGE: - Return the usage glafs for the give algo. An invalid alog - does return 0. Disabled algos are ignored here becuase we + Return the usage flags for the given algo. An invalid algo + returns 0. Disabled algos are ignored here because we only want to know whether the algo is at all capable of the usage. - + Note: Because this function is in most cases used to return an integer value, we can make it easier for the caller to just look at the return value. The caller will in all cases consult the value - and thereby detecting whether a error occured or not (i.e. while + and thereby detecting whether a error occurred or not (i.e. while checking the block size) */ -gcry_error_t -gcry_pk_algo_info (int algorithm, int what, void *buffer, size_t *nbytes) +gcry_err_code_t +_gcry_pk_algo_info (int algorithm, int what, void *buffer, size_t *nbytes) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_err_code_t rc = 0; switch (what) { @@ -2524,31 +829,18 @@ gcry_pk_algo_info (int algorithm, int what, void *buffer, size_t *nbytes) { int use = nbytes ? *nbytes : 0; if (buffer) - err = GPG_ERR_INV_ARG; + rc = GPG_ERR_INV_ARG; else if (check_pubkey_algo (algorithm, use)) - err = GPG_ERR_PUBKEY_ALGO; + rc = GPG_ERR_PUBKEY_ALGO; break; } case GCRYCTL_GET_ALGO_USAGE: { - gcry_module_t pubkey; - int use = 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - { - use = ((gcry_pk_spec_t *) pubkey->spec)->use; - _gcry_module_release (pubkey); - } - ath_mutex_unlock (&pubkeys_registered_lock); - - /* FIXME? */ - *nbytes = use; + gcry_pk_spec_t *spec; + spec = spec_from_algo (algorithm); + *nbytes = spec? spec->use : 0; break; } @@ -2582,69 +874,60 @@ gcry_pk_algo_info (int algorithm, int what, void *buffer, size_t *nbytes) } default: - err = GPG_ERR_INV_OP; + rc = GPG_ERR_INV_OP; } - return gcry_error (err); + return rc; } -/* Explicitly initialize this module. */ -gcry_err_code_t -_gcry_pk_init (void) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - REGISTER_DEFAULT_PUBKEYS; - - return err; -} - +/* Return an S-expression representing the context CTX. Depending on + the state of that context, the S-expression may either be a public + key, a private key or any other object used with public key + operations. On success a new S-expression is stored at R_SEXP and + 0 is returned, on error NULL is store there and an error code is + returned. MODE is either 0 or one of the GCRY_PK_GET_xxx values. + As of now it only support certain ECC operations because a context + object is right now only defined for ECC. Over time this function + will be extended to cover more algorithms. Note also that the name + of the function is gcry_pubkey_xxx and not gcry_pk_xxx. The idea + is that we will eventually provide variants of the existing + gcry_pk_xxx functions which will take a context parameter. */ gcry_err_code_t -_gcry_pk_module_lookup (int algorithm, gcry_module_t *module) +_gcry_pubkey_get_sexp (gcry_sexp_t *r_sexp, int mode, gcry_ctx_t ctx) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - gcry_module_t pubkey; + mpi_ec_t ec; - REGISTER_DEFAULT_PUBKEYS; + if (!r_sexp) + return GPG_ERR_INV_VALUE; + *r_sexp = NULL; + switch (mode) + { + case 0: + case GCRY_PK_GET_PUBKEY: + case GCRY_PK_GET_SECKEY: + break; + default: + return GPG_ERR_INV_VALUE; + } + if (!ctx) + return GPG_ERR_NO_CRYPT_CTX; - ath_mutex_lock (&pubkeys_registered_lock); - pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm); - if (pubkey) - *module = pubkey; - else - err = GPG_ERR_PUBKEY_ALGO; - ath_mutex_unlock (&pubkeys_registered_lock); + ec = _gcry_ctx_find_pointer (ctx, CONTEXT_TYPE_EC); + if (ec) + return _gcry_pk_ecc_get_sexp (r_sexp, mode, ec); - return err; + return GPG_ERR_WRONG_CRYPT_CTX; } -void -_gcry_pk_module_release (gcry_module_t module) -{ - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); -} - -/* Get a list consisting of the IDs of the loaded pubkey modules. If - LIST is zero, write the number of loaded pubkey modules to - LIST_LENGTH and return. If LIST is non-zero, the first - *LIST_LENGTH algorithm IDs are stored in LIST, which must be of - according size. In case there are less pubkey modules than - *LIST_LENGTH, *LIST_LENGTH is updated to the correct number. */ -gcry_error_t -gcry_pk_list (int *list, int *list_length) + +/* Explicitly initialize this module. */ +gcry_err_code_t +_gcry_pk_init (void) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - ath_mutex_lock (&pubkeys_registered_lock); - err = _gcry_module_list (pubkeys_registered, list, list_length); - ath_mutex_unlock (&pubkeys_registered_lock); - - return err; + return 0; } @@ -2653,97 +936,25 @@ gcry_pk_list (int *list, int *list_length) gpg_error_t _gcry_pk_selftest (int algo, int extended, selftest_report_func_t report) { - gcry_module_t module = NULL; - pk_extra_spec_t *extraspec = NULL; - gcry_err_code_t ec = 0; - - REGISTER_DEFAULT_PUBKEYS; - - ath_mutex_lock (&pubkeys_registered_lock); - module = _gcry_module_lookup_id (pubkeys_registered, algo); - if (module && !(module->flags & FLAG_MODULE_DISABLED)) - extraspec = module->extraspec; - ath_mutex_unlock (&pubkeys_registered_lock); - if (extraspec && extraspec->selftest) - ec = extraspec->selftest (algo, extended, report); + gcry_err_code_t ec; + gcry_pk_spec_t *spec; + + algo = map_algo (algo); + spec = spec_from_algo (algo); + if (spec && !spec->flags.disabled && spec->selftest) + ec = spec->selftest (algo, extended, report); else { ec = GPG_ERR_PUBKEY_ALGO; + /* Fixme: We need to change the report fucntion to allow passing + of an encryption mode (e.g. pkcs1, ecdsa, or ecdh). */ if (report) - report ("pubkey", algo, "module", - module && !(module->flags & FLAG_MODULE_DISABLED)? + report ("pubkey", algo, "module", + spec && !spec->flags.disabled? "no selftest available" : - module? "algorithm disabled" : "algorithm not found"); + spec? "algorithm disabled" : + "algorithm not found"); } - if (module) - { - ath_mutex_lock (&pubkeys_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&pubkeys_registered_lock); - } return gpg_error (ec); } - - -/* This function is only used by ac.c! */ -gcry_err_code_t -_gcry_pk_get_elements (int algo, char **enc, char **sig) -{ - gcry_module_t pubkey; - gcry_pk_spec_t *spec; - gcry_err_code_t err; - char *enc_cp; - char *sig_cp; - - REGISTER_DEFAULT_PUBKEYS; - - enc_cp = NULL; - sig_cp = NULL; - spec = NULL; - - pubkey = _gcry_module_lookup_id (pubkeys_registered, algo); - if (! pubkey) - { - err = GPG_ERR_INTERNAL; - goto out; - } - spec = pubkey->spec; - - if (enc) - { - enc_cp = _strdup (spec->elements_enc); - if (! enc_cp) - { - err = gpg_err_code_from_errno (errno); - goto out; - } - } - - if (sig) - { - sig_cp = _strdup (spec->elements_sig); - if (! sig_cp) - { - err = gpg_err_code_from_errno (errno); - goto out; - } - } - - if (enc) - *enc = enc_cp; - if (sig) - *sig = sig_cp; - err = 0; - - out: - - _gcry_module_release (pubkey); - if (err) - { - free (enc_cp); - free (sig_cp); - } - - return err; -} diff --git a/plugins/MirOTR/Libgcrypt/cipher/random.c b/plugins/MirOTR/Libgcrypt/cipher/random.c deleted file mode 100644 index 8df87e2dfa..0000000000 --- a/plugins/MirOTR/Libgcrypt/cipher/random.c +++ /dev/null @@ -1,323 +0,0 @@ -/* random.c - Random number switch - * Copyright (C) 2008 Free Software Foundation, Inc. - * - * This file is part of Libgcrypt. - * - * Libgcrypt is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * Libgcrypt is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -/* - This module switches between different implementations of random - number generators and provides a few help functions. - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> - -#include "g10lib.h" -#include "random.h" -#include "rand-internal.h" -#include "ath.h" - - -/* If not NULL a progress function called from certain places and the - opaque value passed along. Registred by - _gcry_register_random_progress (). */ -static void (*progress_cb) (void *,const char*,int,int, int ); -static void *progress_cb_data; - - - - -/* --- Functions --- */ - - -/* Used to register a progress callback. This needs to be called - before any threads are created. */ -void -_gcry_register_random_progress (void (*cb)(void *,const char*,int,int,int), - void *cb_data ) -{ - progress_cb = cb; - progress_cb_data = cb_data; -} - - -/* This progress function is currently used by the random modules to - give hints on how much more entropy is required. */ -void -_gcry_random_progress (const char *what, int printchar, int current, int total) -{ - if (progress_cb) - progress_cb (progress_cb_data, what, printchar, current, total); -} - - - -/* Initialize this random subsystem. If FULL is false, this function - merely calls the basic initialization of the module and does not do - anything more. Doing this is not really required but when running - in a threaded environment we might get a race condition - otherwise. */ -void -_gcry_random_initialize (int full) -{ - if (fips_mode ()) - _gcry_rngfips_initialize (full); - else - _gcry_rngcsprng_initialize (full); -} - - -void -_gcry_random_dump_stats (void) -{ - if (fips_mode ()) - _gcry_rngfips_dump_stats (); - else - _gcry_rngcsprng_dump_stats (); -} - - -/* This function should be called during initialization and beore - intialization of this module to place the random pools into secure - memory. */ -void -_gcry_secure_random_alloc (void) -{ - if (fips_mode ()) - ; /* Not used; the fips rng is allows in secure mode. */ - else - _gcry_rngcsprng_secure_alloc (); -} - - -/* This may be called before full initialization to degrade the - quality of the RNG for the sake of a faster running test suite. */ -void -_gcry_enable_quick_random_gen (void) -{ - if (fips_mode ()) - ; /* Not used. */ - else - _gcry_rngcsprng_enable_quick_gen (); -} - - -void -_gcry_set_random_daemon_socket (const char *socketname) -{ - if (fips_mode ()) - ; /* Not used. */ - else - _gcry_rngcsprng_set_daemon_socket (socketname); -} - -/* With ONOFF set to 1, enable the use of the daemon. With ONOFF set - to 0, disable the use of the daemon. With ONOF set to -1, return - whether the daemon has been enabled. */ -int -_gcry_use_random_daemon (int onoff) -{ - if (fips_mode ()) - return 0; /* Never enabled in fips mode. */ - else - return _gcry_rngcsprng_use_daemon (onoff); -} - - -/* This function returns true if no real RNG is available or the - quality of the RNG has been degraded for test purposes. */ -int -_gcry_random_is_faked (void) -{ - if (fips_mode ()) - return _gcry_rngfips_is_faked (); - else - return _gcry_rngcsprng_is_faked (); -} - - -/* Add BUFLEN bytes from BUF to the internal random pool. QUALITY - should be in the range of 0..100 to indicate the goodness of the - entropy added, or -1 for goodness not known. */ -gcry_error_t -gcry_random_add_bytes (const void *buf, size_t buflen, int quality) -{ - if (fips_mode ()) - return 0; /* No need for this in fips mode. */ - else - return _gcry_rngcsprng_add_bytes (buf, buflen, quality); -} - - -/* Helper function. */ -static void -do_randomize (void *buffer, size_t length, enum gcry_random_level level) -{ - if (fips_mode ()) - _gcry_rngfips_randomize (buffer, length, level); - else - _gcry_rngcsprng_randomize (buffer, length, level); -} - -/* The public function to return random data of the quality LEVEL. - Returns a pointer to a newly allocated and randomized buffer of - LEVEL and NBYTES length. Caller must free the buffer. */ -void * -gcry_random_bytes (size_t nbytes, enum gcry_random_level level) -{ - void *buffer; - - buffer = gcry_xmalloc (nbytes); - do_randomize (buffer, nbytes, level); - return buffer; -} - - -/* The public function to return random data of the quality LEVEL; - this version of the function returns the random in a buffer allocated - in secure memory. Caller must free the buffer. */ -void * -gcry_random_bytes_secure (size_t nbytes, enum gcry_random_level level) -{ - void *buffer; - - /* Historical note (1.3.0--1.4.1): The buffer was only allocated - in secure memory if the pool in random-csprng.c was also set to - use secure memory. */ - buffer = gcry_xmalloc_secure (nbytes); - do_randomize (buffer, nbytes, level); - return buffer; -} - - -/* Public function to fill the buffer with LENGTH bytes of - cryptographically strong random bytes. Level GCRY_WEAK_RANDOM is - not very strong, GCRY_STRONG_RANDOM is strong enough for most - usage, GCRY_VERY_STRONG_RANDOM is good for key generation stuff but - may be very slow. */ -void -gcry_randomize (void *buffer, size_t length, enum gcry_random_level level) -{ - do_randomize (buffer, length, level); -} - - -/* This function may be used to specify the file to be used as a seed - file for the PRNG. This fucntion should be called prior to the - initialization of the random module. NAME may not be NULL. */ -void -_gcry_set_random_seed_file (const char *name) -{ - if (fips_mode ()) - ; /* No need for this in fips mode. */ - else - _gcry_rngcsprng_set_seed_file (name); -} - - -/* If a seed file has been setup, this function may be used to write - back the random numbers entropy pool. */ -void -_gcry_update_random_seed_file (void) -{ - if (fips_mode ()) - ; /* No need for this in fips mode. */ - else - _gcry_rngcsprng_update_seed_file (); -} - - - -/* The fast random pool function as called at some places in - libgcrypt. This is merely a wrapper to make sure that this module - is initalized and to lock the pool. Note, that this function is a - NOP unless a random function has been used or _gcry_initialize (1) - has been used. We use this hack so that the internal use of this - function in cipher_open and md_open won't start filling up the - random pool, even if no random will be required by the process. */ -void -_gcry_fast_random_poll (void) -{ - if (fips_mode ()) - ; /* No need for this in fips mode. */ - else - _gcry_rngcsprng_fast_poll (); -} - - - -/* Create an unpredicable nonce of LENGTH bytes in BUFFER. */ -void -gcry_create_nonce (void *buffer, size_t length) -{ - if (fips_mode ()) - _gcry_rngfips_create_nonce (buffer, length); - else - _gcry_rngcsprng_create_nonce (buffer, length); -} - - -/* Run the self-tests for the RNG. This is currently only implemented - for the FIPS generator. */ -gpg_error_t -_gcry_random_selftest (selftest_report_func_t report) -{ - if (fips_mode ()) - return _gcry_rngfips_selftest (report); - else - return 0; /* No selftests yet. */ -} - - -/* Create a new test context for an external RNG test driver. On - success the test context is stored at R_CONTEXT; on failure NULL is - stored at R_CONTEXT and an error code is returned. */ -gcry_err_code_t -_gcry_random_init_external_test (void **r_context, - unsigned int flags, - const void *key, size_t keylen, - const void *seed, size_t seedlen, - const void *dt, size_t dtlen) -{ - (void)flags; - if (fips_mode ()) - return _gcry_rngfips_init_external_test (r_context, flags, key, keylen, - seed, seedlen, - dt, dtlen); - else - return GPG_ERR_NOT_SUPPORTED; -} - -/* Get BUFLEN bytes from the RNG using the test CONTEXT and store them - at BUFFER. Return 0 on success or an error code. */ -gcry_err_code_t -_gcry_random_run_external_test (void *context, char *buffer, size_t buflen) -{ - if (fips_mode ()) - return _gcry_rngfips_run_external_test (context, buffer, buflen); - else - return GPG_ERR_NOT_SUPPORTED; -} - -/* Release the test CONTEXT. */ -void -_gcry_random_deinit_external_test (void *context) -{ - if (fips_mode ()) - _gcry_rngfips_deinit_external_test (context); -} diff --git a/plugins/MirOTR/Libgcrypt/cipher/rfc2268.c b/plugins/MirOTR/Libgcrypt/cipher/rfc2268.c index 7d63fceffb..aed8cadbaf 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/rfc2268.c +++ b/plugins/MirOTR/Libgcrypt/cipher/rfc2268.c @@ -22,7 +22,7 @@ /* This implementation was written by Nikos Mavroyanopoulos for GNUTLS * as a Libgcrypt module (gnutls/lib/x509/rc2.c) and later adapted for * direct use by Libgcrypt by Werner Koch. This implementation is - * only useful for pkcs#12 descryption. + * only useful for pkcs#12 decryption. * * The implementation here is based on Peter Gutmann's RRC.2 paper. */ @@ -38,15 +38,15 @@ #define RFC2268_BLOCKSIZE 8 -typedef struct +typedef struct { u16 S[64]; } RFC2268_context; -static const unsigned char rfc2268_sbox[] = { - 217, 120, 249, 196, 25, 221, 181, 237, +static const unsigned char rfc2268_sbox[] = { + 217, 120, 249, 196, 25, 221, 181, 237, 40, 233, 253, 121, 74, 160, 216, 157, - 198, 126, 55, 131, 43, 118, 83, 142, + 198, 126, 55, 131, 43, 118, 83, 142, 98, 76, 100, 136, 68, 139, 251, 162, 23, 154, 89, 245, 135, 179, 79, 19, 97, 69, 109, 141, 9, 129, 125, 50, @@ -106,10 +106,10 @@ do_encrypt (void *context, unsigned char *outbuf, const unsigned char *inbuf) /* For some reason I cannot combine those steps. */ word0 += (word1 & ~word3) + (word2 & word3) + ctx->S[j]; word0 = rotl16(word0, 1); - + word1 += (word2 & ~word0) + (word3 & word0) + ctx->S[j + 1]; word1 = rotl16(word1, 2); - + word2 += (word3 & ~word1) + (word0 & word1) + ctx->S[j + 2]; word2 = rotl16(word2, 3); @@ -136,6 +136,13 @@ do_encrypt (void *context, unsigned char *outbuf, const unsigned char *inbuf) outbuf[7] = word3 >> 8; } +static unsigned int +encrypt_block (void *context, unsigned char *outbuf, const unsigned char *inbuf) +{ + do_encrypt (context, outbuf, inbuf); + return /*burn_stack*/ (4 * sizeof(void *) + sizeof(void *) + sizeof(u32) * 4); +} + static void do_decrypt (void *context, unsigned char *outbuf, const unsigned char *inbuf) { @@ -152,7 +159,7 @@ do_decrypt (void *context, unsigned char *outbuf, const unsigned char *inbuf) word3 = (word3 << 8) | inbuf[7]; word3 = (word3 << 8) | inbuf[6]; - for (i = 15; i >= 0; i--) + for (i = 15; i >= 0; i--) { j = i * 4; @@ -168,7 +175,7 @@ do_decrypt (void *context, unsigned char *outbuf, const unsigned char *inbuf) word0 = rotr16(word0, 1); word0 -= (word1 & ~word3) + (word2 & word3) + ctx->S[j]; - if (i == 5 || i == 11) + if (i == 5 || i == 11) { word3 = word3 - ctx->S[word2 & 63]; word2 = word2 - ctx->S[word1 & 63]; @@ -188,6 +195,13 @@ do_decrypt (void *context, unsigned char *outbuf, const unsigned char *inbuf) outbuf[7] = word3 >> 8; } +static unsigned int +decrypt_block (void *context, unsigned char *outbuf, const unsigned char *inbuf) +{ + do_decrypt (context, outbuf, inbuf); + return /*burn_stack*/ (4 * sizeof(void *) + sizeof(void *) + sizeof(u32) * 4); +} + static gpg_err_code_t setkey_core (void *context, const unsigned char *key, unsigned int keylen, int with_phase2) @@ -214,7 +228,7 @@ setkey_core (void *context, const unsigned char *key, unsigned int keylen, int w return GPG_ERR_INV_KEYLEN; S = (unsigned char *) ctx->S; - + for (i = 0; i < keylen; i++) S[i] = key[i]; @@ -232,8 +246,8 @@ setkey_core (void *context, const unsigned char *key, unsigned int keylen, int w i = 128 - len; x = rfc2268_sbox[S[i] & (255 >> (7 & -bits))]; S[i] = x; - - while (i--) + + while (i--) { x = rfc2268_sbox[x ^ S[i + len]]; S[i] = x; @@ -241,7 +255,7 @@ setkey_core (void *context, const unsigned char *key, unsigned int keylen, int w } /* Make the expanded key, endian independent. */ - for (i = 0; i < 64; i++) + for (i = 0; i < 64; i++) ctx->S[i] = ( (u16) S[i * 2] | (((u16) S[i * 2 + 1]) << 8)); return 0; @@ -297,7 +311,7 @@ selftest (void) return "RFC2268 encryption test 1 failed."; setkey_core (&ctx, key_1, sizeof(key_1), 0); - do_decrypt (&ctx, scratch, scratch); + do_decrypt (&ctx, scratch, scratch); if (memcmp (scratch, plaintext_1, sizeof(plaintext_1))) return "RFC2268 decryption test 1 failed."; @@ -308,7 +322,7 @@ selftest (void) return "RFC2268 encryption test 2 failed."; setkey_core (&ctx, key_2, sizeof(key_2), 0); - do_decrypt (&ctx, scratch, scratch); + do_decrypt (&ctx, scratch, scratch); if (memcmp (scratch, plaintext_2, sizeof(plaintext_2))) return "RFC2268 decryption test 2 failed."; @@ -320,7 +334,7 @@ selftest (void) return "RFC2268 encryption test 3 failed."; setkey_core (&ctx, key_3, sizeof(key_3), 0); - do_decrypt (&ctx, scratch, scratch); + do_decrypt (&ctx, scratch, scratch); if (memcmp(scratch, plaintext_3, sizeof(plaintext_3))) return "RFC2268 decryption test 3 failed."; @@ -337,9 +351,25 @@ static gcry_cipher_oid_spec_t oids_rfc2268_40[] = { NULL } }; -gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_40 = { - "RFC2268_40", NULL, oids_rfc2268_40, - RFC2268_BLOCKSIZE, 40, sizeof(RFC2268_context), - do_setkey, do_encrypt, do_decrypt -}; +static gcry_cipher_oid_spec_t oids_rfc2268_128[] = + { + /* pbeWithSHAAnd128BitRC2_CBC */ + { "1.2.840.113549.1.12.1.5", GCRY_CIPHER_MODE_CBC }, + { NULL } + }; +gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_40 = + { + GCRY_CIPHER_RFC2268_40, {0, 0}, + "RFC2268_40", NULL, oids_rfc2268_40, + RFC2268_BLOCKSIZE, 40, sizeof(RFC2268_context), + do_setkey, encrypt_block, decrypt_block + }; + +gcry_cipher_spec_t _gcry_cipher_spec_rfc2268_128 = + { + GCRY_CIPHER_RFC2268_128, {0, 0}, + "RFC2268_128", NULL, oids_rfc2268_128, + RFC2268_BLOCKSIZE, 128, sizeof(RFC2268_context), + do_setkey, encrypt_block, decrypt_block + }; diff --git a/plugins/MirOTR/Libgcrypt/cipher/rijndael-tables.h b/plugins/MirOTR/Libgcrypt/cipher/rijndael-tables.h index c9b6d77923..b6a5b158c9 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/rijndael-tables.h +++ b/plugins/MirOTR/Libgcrypt/cipher/rijndael-tables.h @@ -1,4 +1,4 @@ -/* rijndael-tables.h - Rijndael (AES) for GnuPG, +/* rijndael-tables.h - Rijndael (AES) for GnuPG, * Copyright (C) 2000, 2001, 2002, 2003, 2007, * 2008 Free Software Foundation, Inc. * @@ -21,1100 +21,1100 @@ /* To keep the actual implementation at a readable size we use this include file to define the tables. */ -static const unsigned char S[256] = +static const unsigned char S[256] = { 99, 124, 119, 123, 242, 107, 111, 197, - 48, 1, 103, 43, 254, 215, 171, 118, + 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, - 173, 212, 162, 175, 156, 164, 114, 192, + 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, - 52, 165, 229, 241, 113, 216, 49, 21, + 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, - 7, 18, 128, 226, 235, 39, 178, 117, - 9, 131, 44, 26, 27, 110, 90, 160, - 82, 59, 214, 179, 41, 227, 47, 132, + 7, 18, 128, 226, 235, 39, 178, 117, + 9, 131, 44, 26, 27, 110, 90, 160, + 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, - 106, 203, 190, 57, 74, 76, 88, 207, + 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, - 69, 249, 2, 127, 80, 60, 159, 168, + 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, - 188, 182, 218, 33, 16, 255, 243, 210, + 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, - 196, 167, 126, 61, 100, 93, 25, 115, + 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, - 70, 238, 184, 20, 222, 94, 11, 219, + 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, - 194, 211, 172, 98, 145, 149, 228, 121, - 231, 200, 55, 109, 141, 213, 78, 169, - 108, 86, 244, 234, 101, 122, 174, 8, - 186, 120, 37, 46, 28, 166, 180, 198, - 232, 221, 116, 31, 75, 189, 139, 138, + 194, 211, 172, 98, 145, 149, 228, 121, + 231, 200, 55, 109, 141, 213, 78, 169, + 108, 86, 244, 234, 101, 122, 174, 8, + 186, 120, 37, 46, 28, 166, 180, 198, + 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, - 97, 53, 87, 185, 134, 193, 29, 158, + 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, - 155, 30, 135, 233, 206, 85, 40, 223, - 140, 161, 137, 13, 191, 230, 66, 104, + 155, 30, 135, 233, 206, 85, 40, 223, + 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22 }; -static const unsigned char T1[256][4] = +static const unsigned char T1[256][4] = { { 0xc6,0x63,0x63,0xa5 }, { 0xf8,0x7c,0x7c,0x84 }, - { 0xee,0x77,0x77,0x99 }, { 0xf6,0x7b,0x7b,0x8d }, + { 0xee,0x77,0x77,0x99 }, { 0xf6,0x7b,0x7b,0x8d }, { 0xff,0xf2,0xf2,0x0d }, { 0xd6,0x6b,0x6b,0xbd }, - { 0xde,0x6f,0x6f,0xb1 }, { 0x91,0xc5,0xc5,0x54 }, + { 0xde,0x6f,0x6f,0xb1 }, { 0x91,0xc5,0xc5,0x54 }, { 0x60,0x30,0x30,0x50 }, { 0x02,0x01,0x01,0x03 }, - { 0xce,0x67,0x67,0xa9 }, { 0x56,0x2b,0x2b,0x7d }, + { 0xce,0x67,0x67,0xa9 }, { 0x56,0x2b,0x2b,0x7d }, { 0xe7,0xfe,0xfe,0x19 }, { 0xb5,0xd7,0xd7,0x62 }, - { 0x4d,0xab,0xab,0xe6 }, { 0xec,0x76,0x76,0x9a }, + { 0x4d,0xab,0xab,0xe6 }, { 0xec,0x76,0x76,0x9a }, { 0x8f,0xca,0xca,0x45 }, { 0x1f,0x82,0x82,0x9d }, - { 0x89,0xc9,0xc9,0x40 }, { 0xfa,0x7d,0x7d,0x87 }, - { 0xef,0xfa,0xfa,0x15 }, { 0xb2,0x59,0x59,0xeb }, - { 0x8e,0x47,0x47,0xc9 }, { 0xfb,0xf0,0xf0,0x0b }, + { 0x89,0xc9,0xc9,0x40 }, { 0xfa,0x7d,0x7d,0x87 }, + { 0xef,0xfa,0xfa,0x15 }, { 0xb2,0x59,0x59,0xeb }, + { 0x8e,0x47,0x47,0xc9 }, { 0xfb,0xf0,0xf0,0x0b }, { 0x41,0xad,0xad,0xec }, { 0xb3,0xd4,0xd4,0x67 }, - { 0x5f,0xa2,0xa2,0xfd }, { 0x45,0xaf,0xaf,0xea }, + { 0x5f,0xa2,0xa2,0xfd }, { 0x45,0xaf,0xaf,0xea }, { 0x23,0x9c,0x9c,0xbf }, { 0x53,0xa4,0xa4,0xf7 }, - { 0xe4,0x72,0x72,0x96 }, { 0x9b,0xc0,0xc0,0x5b }, + { 0xe4,0x72,0x72,0x96 }, { 0x9b,0xc0,0xc0,0x5b }, { 0x75,0xb7,0xb7,0xc2 }, { 0xe1,0xfd,0xfd,0x1c }, - { 0x3d,0x93,0x93,0xae }, { 0x4c,0x26,0x26,0x6a }, + { 0x3d,0x93,0x93,0xae }, { 0x4c,0x26,0x26,0x6a }, { 0x6c,0x36,0x36,0x5a }, { 0x7e,0x3f,0x3f,0x41 }, - { 0xf5,0xf7,0xf7,0x02 }, { 0x83,0xcc,0xcc,0x4f }, - { 0x68,0x34,0x34,0x5c }, { 0x51,0xa5,0xa5,0xf4 }, - { 0xd1,0xe5,0xe5,0x34 }, { 0xf9,0xf1,0xf1,0x08 }, + { 0xf5,0xf7,0xf7,0x02 }, { 0x83,0xcc,0xcc,0x4f }, + { 0x68,0x34,0x34,0x5c }, { 0x51,0xa5,0xa5,0xf4 }, + { 0xd1,0xe5,0xe5,0x34 }, { 0xf9,0xf1,0xf1,0x08 }, { 0xe2,0x71,0x71,0x93 }, { 0xab,0xd8,0xd8,0x73 }, - { 0x62,0x31,0x31,0x53 }, { 0x2a,0x15,0x15,0x3f }, + { 0x62,0x31,0x31,0x53 }, { 0x2a,0x15,0x15,0x3f }, { 0x08,0x04,0x04,0x0c }, { 0x95,0xc7,0xc7,0x52 }, - { 0x46,0x23,0x23,0x65 }, { 0x9d,0xc3,0xc3,0x5e }, + { 0x46,0x23,0x23,0x65 }, { 0x9d,0xc3,0xc3,0x5e }, { 0x30,0x18,0x18,0x28 }, { 0x37,0x96,0x96,0xa1 }, - { 0x0a,0x05,0x05,0x0f }, { 0x2f,0x9a,0x9a,0xb5 }, + { 0x0a,0x05,0x05,0x0f }, { 0x2f,0x9a,0x9a,0xb5 }, { 0x0e,0x07,0x07,0x09 }, { 0x24,0x12,0x12,0x36 }, - { 0x1b,0x80,0x80,0x9b }, { 0xdf,0xe2,0xe2,0x3d }, + { 0x1b,0x80,0x80,0x9b }, { 0xdf,0xe2,0xe2,0x3d }, { 0xcd,0xeb,0xeb,0x26 }, { 0x4e,0x27,0x27,0x69 }, - { 0x7f,0xb2,0xb2,0xcd }, { 0xea,0x75,0x75,0x9f }, + { 0x7f,0xb2,0xb2,0xcd }, { 0xea,0x75,0x75,0x9f }, { 0x12,0x09,0x09,0x1b }, { 0x1d,0x83,0x83,0x9e }, - { 0x58,0x2c,0x2c,0x74 }, { 0x34,0x1a,0x1a,0x2e }, - { 0x36,0x1b,0x1b,0x2d }, { 0xdc,0x6e,0x6e,0xb2 }, - { 0xb4,0x5a,0x5a,0xee }, { 0x5b,0xa0,0xa0,0xfb }, + { 0x58,0x2c,0x2c,0x74 }, { 0x34,0x1a,0x1a,0x2e }, + { 0x36,0x1b,0x1b,0x2d }, { 0xdc,0x6e,0x6e,0xb2 }, + { 0xb4,0x5a,0x5a,0xee }, { 0x5b,0xa0,0xa0,0xfb }, { 0xa4,0x52,0x52,0xf6 }, { 0x76,0x3b,0x3b,0x4d }, - { 0xb7,0xd6,0xd6,0x61 }, { 0x7d,0xb3,0xb3,0xce }, - { 0x52,0x29,0x29,0x7b }, { 0xdd,0xe3,0xe3,0x3e }, - { 0x5e,0x2f,0x2f,0x71 }, { 0x13,0x84,0x84,0x97 }, - { 0xa6,0x53,0x53,0xf5 }, { 0xb9,0xd1,0xd1,0x68 }, - { 0x00,0x00,0x00,0x00 }, { 0xc1,0xed,0xed,0x2c }, + { 0xb7,0xd6,0xd6,0x61 }, { 0x7d,0xb3,0xb3,0xce }, + { 0x52,0x29,0x29,0x7b }, { 0xdd,0xe3,0xe3,0x3e }, + { 0x5e,0x2f,0x2f,0x71 }, { 0x13,0x84,0x84,0x97 }, + { 0xa6,0x53,0x53,0xf5 }, { 0xb9,0xd1,0xd1,0x68 }, + { 0x00,0x00,0x00,0x00 }, { 0xc1,0xed,0xed,0x2c }, { 0x40,0x20,0x20,0x60 }, { 0xe3,0xfc,0xfc,0x1f }, - { 0x79,0xb1,0xb1,0xc8 }, { 0xb6,0x5b,0x5b,0xed }, + { 0x79,0xb1,0xb1,0xc8 }, { 0xb6,0x5b,0x5b,0xed }, { 0xd4,0x6a,0x6a,0xbe }, { 0x8d,0xcb,0xcb,0x46 }, - { 0x67,0xbe,0xbe,0xd9 }, { 0x72,0x39,0x39,0x4b }, + { 0x67,0xbe,0xbe,0xd9 }, { 0x72,0x39,0x39,0x4b }, { 0x94,0x4a,0x4a,0xde }, { 0x98,0x4c,0x4c,0xd4 }, - { 0xb0,0x58,0x58,0xe8 }, { 0x85,0xcf,0xcf,0x4a }, + { 0xb0,0x58,0x58,0xe8 }, { 0x85,0xcf,0xcf,0x4a }, { 0xbb,0xd0,0xd0,0x6b }, { 0xc5,0xef,0xef,0x2a }, - { 0x4f,0xaa,0xaa,0xe5 }, { 0xed,0xfb,0xfb,0x16 }, + { 0x4f,0xaa,0xaa,0xe5 }, { 0xed,0xfb,0xfb,0x16 }, { 0x86,0x43,0x43,0xc5 }, { 0x9a,0x4d,0x4d,0xd7 }, - { 0x66,0x33,0x33,0x55 }, { 0x11,0x85,0x85,0x94 }, + { 0x66,0x33,0x33,0x55 }, { 0x11,0x85,0x85,0x94 }, { 0x8a,0x45,0x45,0xcf }, { 0xe9,0xf9,0xf9,0x10 }, - { 0x04,0x02,0x02,0x06 }, { 0xfe,0x7f,0x7f,0x81 }, + { 0x04,0x02,0x02,0x06 }, { 0xfe,0x7f,0x7f,0x81 }, { 0xa0,0x50,0x50,0xf0 }, { 0x78,0x3c,0x3c,0x44 }, - { 0x25,0x9f,0x9f,0xba }, { 0x4b,0xa8,0xa8,0xe3 }, + { 0x25,0x9f,0x9f,0xba }, { 0x4b,0xa8,0xa8,0xe3 }, { 0xa2,0x51,0x51,0xf3 }, { 0x5d,0xa3,0xa3,0xfe }, - { 0x80,0x40,0x40,0xc0 }, { 0x05,0x8f,0x8f,0x8a }, + { 0x80,0x40,0x40,0xc0 }, { 0x05,0x8f,0x8f,0x8a }, { 0x3f,0x92,0x92,0xad }, { 0x21,0x9d,0x9d,0xbc }, - { 0x70,0x38,0x38,0x48 }, { 0xf1,0xf5,0xf5,0x04 }, + { 0x70,0x38,0x38,0x48 }, { 0xf1,0xf5,0xf5,0x04 }, { 0x63,0xbc,0xbc,0xdf }, { 0x77,0xb6,0xb6,0xc1 }, - { 0xaf,0xda,0xda,0x75 }, { 0x42,0x21,0x21,0x63 }, + { 0xaf,0xda,0xda,0x75 }, { 0x42,0x21,0x21,0x63 }, { 0x20,0x10,0x10,0x30 }, { 0xe5,0xff,0xff,0x1a }, - { 0xfd,0xf3,0xf3,0x0e }, { 0xbf,0xd2,0xd2,0x6d }, + { 0xfd,0xf3,0xf3,0x0e }, { 0xbf,0xd2,0xd2,0x6d }, { 0x81,0xcd,0xcd,0x4c }, { 0x18,0x0c,0x0c,0x14 }, - { 0x26,0x13,0x13,0x35 }, { 0xc3,0xec,0xec,0x2f }, + { 0x26,0x13,0x13,0x35 }, { 0xc3,0xec,0xec,0x2f }, { 0xbe,0x5f,0x5f,0xe1 }, { 0x35,0x97,0x97,0xa2 }, - { 0x88,0x44,0x44,0xcc }, { 0x2e,0x17,0x17,0x39 }, + { 0x88,0x44,0x44,0xcc }, { 0x2e,0x17,0x17,0x39 }, { 0x93,0xc4,0xc4,0x57 }, { 0x55,0xa7,0xa7,0xf2 }, - { 0xfc,0x7e,0x7e,0x82 }, { 0x7a,0x3d,0x3d,0x47 }, + { 0xfc,0x7e,0x7e,0x82 }, { 0x7a,0x3d,0x3d,0x47 }, { 0xc8,0x64,0x64,0xac }, { 0xba,0x5d,0x5d,0xe7 }, - { 0x32,0x19,0x19,0x2b }, { 0xe6,0x73,0x73,0x95 }, + { 0x32,0x19,0x19,0x2b }, { 0xe6,0x73,0x73,0x95 }, { 0xc0,0x60,0x60,0xa0 }, { 0x19,0x81,0x81,0x98 }, - { 0x9e,0x4f,0x4f,0xd1 }, { 0xa3,0xdc,0xdc,0x7f }, + { 0x9e,0x4f,0x4f,0xd1 }, { 0xa3,0xdc,0xdc,0x7f }, { 0x44,0x22,0x22,0x66 }, { 0x54,0x2a,0x2a,0x7e }, - { 0x3b,0x90,0x90,0xab }, { 0x0b,0x88,0x88,0x83 }, + { 0x3b,0x90,0x90,0xab }, { 0x0b,0x88,0x88,0x83 }, { 0x8c,0x46,0x46,0xca }, { 0xc7,0xee,0xee,0x29 }, - { 0x6b,0xb8,0xb8,0xd3 }, { 0x28,0x14,0x14,0x3c }, + { 0x6b,0xb8,0xb8,0xd3 }, { 0x28,0x14,0x14,0x3c }, { 0xa7,0xde,0xde,0x79 }, { 0xbc,0x5e,0x5e,0xe2 }, - { 0x16,0x0b,0x0b,0x1d }, { 0xad,0xdb,0xdb,0x76 }, + { 0x16,0x0b,0x0b,0x1d }, { 0xad,0xdb,0xdb,0x76 }, { 0xdb,0xe0,0xe0,0x3b }, { 0x64,0x32,0x32,0x56 }, - { 0x74,0x3a,0x3a,0x4e }, { 0x14,0x0a,0x0a,0x1e }, + { 0x74,0x3a,0x3a,0x4e }, { 0x14,0x0a,0x0a,0x1e }, { 0x92,0x49,0x49,0xdb }, { 0x0c,0x06,0x06,0x0a }, - { 0x48,0x24,0x24,0x6c }, { 0xb8,0x5c,0x5c,0xe4 }, + { 0x48,0x24,0x24,0x6c }, { 0xb8,0x5c,0x5c,0xe4 }, { 0x9f,0xc2,0xc2,0x5d }, { 0xbd,0xd3,0xd3,0x6e }, - { 0x43,0xac,0xac,0xef }, { 0xc4,0x62,0x62,0xa6 }, + { 0x43,0xac,0xac,0xef }, { 0xc4,0x62,0x62,0xa6 }, { 0x39,0x91,0x91,0xa8 }, { 0x31,0x95,0x95,0xa4 }, - { 0xd3,0xe4,0xe4,0x37 }, { 0xf2,0x79,0x79,0x8b }, + { 0xd3,0xe4,0xe4,0x37 }, { 0xf2,0x79,0x79,0x8b }, { 0xd5,0xe7,0xe7,0x32 }, { 0x8b,0xc8,0xc8,0x43 }, - { 0x6e,0x37,0x37,0x59 }, { 0xda,0x6d,0x6d,0xb7 }, + { 0x6e,0x37,0x37,0x59 }, { 0xda,0x6d,0x6d,0xb7 }, { 0x01,0x8d,0x8d,0x8c }, { 0xb1,0xd5,0xd5,0x64 }, - { 0x9c,0x4e,0x4e,0xd2 }, { 0x49,0xa9,0xa9,0xe0 }, + { 0x9c,0x4e,0x4e,0xd2 }, { 0x49,0xa9,0xa9,0xe0 }, { 0xd8,0x6c,0x6c,0xb4 }, { 0xac,0x56,0x56,0xfa }, - { 0xf3,0xf4,0xf4,0x07 }, { 0xcf,0xea,0xea,0x25 }, + { 0xf3,0xf4,0xf4,0x07 }, { 0xcf,0xea,0xea,0x25 }, { 0xca,0x65,0x65,0xaf }, { 0xf4,0x7a,0x7a,0x8e }, - { 0x47,0xae,0xae,0xe9 }, { 0x10,0x08,0x08,0x18 }, + { 0x47,0xae,0xae,0xe9 }, { 0x10,0x08,0x08,0x18 }, { 0x6f,0xba,0xba,0xd5 }, { 0xf0,0x78,0x78,0x88 }, - { 0x4a,0x25,0x25,0x6f }, { 0x5c,0x2e,0x2e,0x72 }, + { 0x4a,0x25,0x25,0x6f }, { 0x5c,0x2e,0x2e,0x72 }, { 0x38,0x1c,0x1c,0x24 }, { 0x57,0xa6,0xa6,0xf1 }, - { 0x73,0xb4,0xb4,0xc7 }, { 0x97,0xc6,0xc6,0x51 }, + { 0x73,0xb4,0xb4,0xc7 }, { 0x97,0xc6,0xc6,0x51 }, { 0xcb,0xe8,0xe8,0x23 }, { 0xa1,0xdd,0xdd,0x7c }, - { 0xe8,0x74,0x74,0x9c }, { 0x3e,0x1f,0x1f,0x21 }, - { 0x96,0x4b,0x4b,0xdd }, { 0x61,0xbd,0xbd,0xdc }, - { 0x0d,0x8b,0x8b,0x86 }, { 0x0f,0x8a,0x8a,0x85 }, + { 0xe8,0x74,0x74,0x9c }, { 0x3e,0x1f,0x1f,0x21 }, + { 0x96,0x4b,0x4b,0xdd }, { 0x61,0xbd,0xbd,0xdc }, + { 0x0d,0x8b,0x8b,0x86 }, { 0x0f,0x8a,0x8a,0x85 }, { 0xe0,0x70,0x70,0x90 }, { 0x7c,0x3e,0x3e,0x42 }, - { 0x71,0xb5,0xb5,0xc4 }, { 0xcc,0x66,0x66,0xaa }, + { 0x71,0xb5,0xb5,0xc4 }, { 0xcc,0x66,0x66,0xaa }, { 0x90,0x48,0x48,0xd8 }, { 0x06,0x03,0x03,0x05 }, - { 0xf7,0xf6,0xf6,0x01 }, { 0x1c,0x0e,0x0e,0x12 }, + { 0xf7,0xf6,0xf6,0x01 }, { 0x1c,0x0e,0x0e,0x12 }, { 0xc2,0x61,0x61,0xa3 }, { 0x6a,0x35,0x35,0x5f }, - { 0xae,0x57,0x57,0xf9 }, { 0x69,0xb9,0xb9,0xd0 }, + { 0xae,0x57,0x57,0xf9 }, { 0x69,0xb9,0xb9,0xd0 }, { 0x17,0x86,0x86,0x91 }, { 0x99,0xc1,0xc1,0x58 }, - { 0x3a,0x1d,0x1d,0x27 }, { 0x27,0x9e,0x9e,0xb9 }, + { 0x3a,0x1d,0x1d,0x27 }, { 0x27,0x9e,0x9e,0xb9 }, { 0xd9,0xe1,0xe1,0x38 }, { 0xeb,0xf8,0xf8,0x13 }, - { 0x2b,0x98,0x98,0xb3 }, { 0x22,0x11,0x11,0x33 }, + { 0x2b,0x98,0x98,0xb3 }, { 0x22,0x11,0x11,0x33 }, { 0xd2,0x69,0x69,0xbb }, { 0xa9,0xd9,0xd9,0x70 }, - { 0x07,0x8e,0x8e,0x89 }, { 0x33,0x94,0x94,0xa7 }, + { 0x07,0x8e,0x8e,0x89 }, { 0x33,0x94,0x94,0xa7 }, { 0x2d,0x9b,0x9b,0xb6 }, { 0x3c,0x1e,0x1e,0x22 }, - { 0x15,0x87,0x87,0x92 }, { 0xc9,0xe9,0xe9,0x20 }, + { 0x15,0x87,0x87,0x92 }, { 0xc9,0xe9,0xe9,0x20 }, { 0x87,0xce,0xce,0x49 }, { 0xaa,0x55,0x55,0xff }, - { 0x50,0x28,0x28,0x78 }, { 0xa5,0xdf,0xdf,0x7a }, + { 0x50,0x28,0x28,0x78 }, { 0xa5,0xdf,0xdf,0x7a }, { 0x03,0x8c,0x8c,0x8f }, { 0x59,0xa1,0xa1,0xf8 }, - { 0x09,0x89,0x89,0x80 }, { 0x1a,0x0d,0x0d,0x17 }, + { 0x09,0x89,0x89,0x80 }, { 0x1a,0x0d,0x0d,0x17 }, { 0x65,0xbf,0xbf,0xda }, { 0xd7,0xe6,0xe6,0x31 }, - { 0x84,0x42,0x42,0xc6 }, { 0xd0,0x68,0x68,0xb8 }, + { 0x84,0x42,0x42,0xc6 }, { 0xd0,0x68,0x68,0xb8 }, { 0x82,0x41,0x41,0xc3 }, { 0x29,0x99,0x99,0xb0 }, - { 0x5a,0x2d,0x2d,0x77 }, { 0x1e,0x0f,0x0f,0x11 }, + { 0x5a,0x2d,0x2d,0x77 }, { 0x1e,0x0f,0x0f,0x11 }, { 0x7b,0xb0,0xb0,0xcb }, { 0xa8,0x54,0x54,0xfc }, { 0x6d,0xbb,0xbb,0xd6 }, { 0x2c,0x16,0x16,0x3a } }; -static const unsigned char T2[256][4] = +static const unsigned char T2[256][4] = { { 0xa5,0xc6,0x63,0x63 }, { 0x84,0xf8,0x7c,0x7c }, - { 0x99,0xee,0x77,0x77 }, { 0x8d,0xf6,0x7b,0x7b }, + { 0x99,0xee,0x77,0x77 }, { 0x8d,0xf6,0x7b,0x7b }, { 0x0d,0xff,0xf2,0xf2 }, { 0xbd,0xd6,0x6b,0x6b }, - { 0xb1,0xde,0x6f,0x6f }, { 0x54,0x91,0xc5,0xc5 }, + { 0xb1,0xde,0x6f,0x6f }, { 0x54,0x91,0xc5,0xc5 }, { 0x50,0x60,0x30,0x30 }, { 0x03,0x02,0x01,0x01 }, - { 0xa9,0xce,0x67,0x67 }, { 0x7d,0x56,0x2b,0x2b }, - { 0x19,0xe7,0xfe,0xfe }, { 0x62,0xb5,0xd7,0xd7 }, - { 0xe6,0x4d,0xab,0xab }, { 0x9a,0xec,0x76,0x76 }, - { 0x45,0x8f,0xca,0xca }, { 0x9d,0x1f,0x82,0x82 }, - { 0x40,0x89,0xc9,0xc9 }, { 0x87,0xfa,0x7d,0x7d }, - { 0x15,0xef,0xfa,0xfa }, { 0xeb,0xb2,0x59,0x59 }, - { 0xc9,0x8e,0x47,0x47 }, { 0x0b,0xfb,0xf0,0xf0 }, - { 0xec,0x41,0xad,0xad }, { 0x67,0xb3,0xd4,0xd4 }, - { 0xfd,0x5f,0xa2,0xa2 }, { 0xea,0x45,0xaf,0xaf }, - { 0xbf,0x23,0x9c,0x9c }, { 0xf7,0x53,0xa4,0xa4 }, - { 0x96,0xe4,0x72,0x72 }, { 0x5b,0x9b,0xc0,0xc0 }, - { 0xc2,0x75,0xb7,0xb7 }, { 0x1c,0xe1,0xfd,0xfd }, - { 0xae,0x3d,0x93,0x93 }, { 0x6a,0x4c,0x26,0x26 }, + { 0xa9,0xce,0x67,0x67 }, { 0x7d,0x56,0x2b,0x2b }, + { 0x19,0xe7,0xfe,0xfe }, { 0x62,0xb5,0xd7,0xd7 }, + { 0xe6,0x4d,0xab,0xab }, { 0x9a,0xec,0x76,0x76 }, + { 0x45,0x8f,0xca,0xca }, { 0x9d,0x1f,0x82,0x82 }, + { 0x40,0x89,0xc9,0xc9 }, { 0x87,0xfa,0x7d,0x7d }, + { 0x15,0xef,0xfa,0xfa }, { 0xeb,0xb2,0x59,0x59 }, + { 0xc9,0x8e,0x47,0x47 }, { 0x0b,0xfb,0xf0,0xf0 }, + { 0xec,0x41,0xad,0xad }, { 0x67,0xb3,0xd4,0xd4 }, + { 0xfd,0x5f,0xa2,0xa2 }, { 0xea,0x45,0xaf,0xaf }, + { 0xbf,0x23,0x9c,0x9c }, { 0xf7,0x53,0xa4,0xa4 }, + { 0x96,0xe4,0x72,0x72 }, { 0x5b,0x9b,0xc0,0xc0 }, + { 0xc2,0x75,0xb7,0xb7 }, { 0x1c,0xe1,0xfd,0xfd }, + { 0xae,0x3d,0x93,0x93 }, { 0x6a,0x4c,0x26,0x26 }, { 0x5a,0x6c,0x36,0x36 }, { 0x41,0x7e,0x3f,0x3f }, - { 0x02,0xf5,0xf7,0xf7 }, { 0x4f,0x83,0xcc,0xcc }, + { 0x02,0xf5,0xf7,0xf7 }, { 0x4f,0x83,0xcc,0xcc }, { 0x5c,0x68,0x34,0x34 }, { 0xf4,0x51,0xa5,0xa5 }, - { 0x34,0xd1,0xe5,0xe5 }, { 0x08,0xf9,0xf1,0xf1 }, + { 0x34,0xd1,0xe5,0xe5 }, { 0x08,0xf9,0xf1,0xf1 }, { 0x93,0xe2,0x71,0x71 }, { 0x73,0xab,0xd8,0xd8 }, - { 0x53,0x62,0x31,0x31 }, { 0x3f,0x2a,0x15,0x15 }, - { 0x0c,0x08,0x04,0x04 }, { 0x52,0x95,0xc7,0xc7 }, - { 0x65,0x46,0x23,0x23 }, { 0x5e,0x9d,0xc3,0xc3 }, - { 0x28,0x30,0x18,0x18 }, { 0xa1,0x37,0x96,0x96 }, - { 0x0f,0x0a,0x05,0x05 }, { 0xb5,0x2f,0x9a,0x9a }, + { 0x53,0x62,0x31,0x31 }, { 0x3f,0x2a,0x15,0x15 }, + { 0x0c,0x08,0x04,0x04 }, { 0x52,0x95,0xc7,0xc7 }, + { 0x65,0x46,0x23,0x23 }, { 0x5e,0x9d,0xc3,0xc3 }, + { 0x28,0x30,0x18,0x18 }, { 0xa1,0x37,0x96,0x96 }, + { 0x0f,0x0a,0x05,0x05 }, { 0xb5,0x2f,0x9a,0x9a }, { 0x09,0x0e,0x07,0x07 }, { 0x36,0x24,0x12,0x12 }, - { 0x9b,0x1b,0x80,0x80 }, { 0x3d,0xdf,0xe2,0xe2 }, - { 0x26,0xcd,0xeb,0xeb }, { 0x69,0x4e,0x27,0x27 }, - { 0xcd,0x7f,0xb2,0xb2 }, { 0x9f,0xea,0x75,0x75 }, + { 0x9b,0x1b,0x80,0x80 }, { 0x3d,0xdf,0xe2,0xe2 }, + { 0x26,0xcd,0xeb,0xeb }, { 0x69,0x4e,0x27,0x27 }, + { 0xcd,0x7f,0xb2,0xb2 }, { 0x9f,0xea,0x75,0x75 }, { 0x1b,0x12,0x09,0x09 }, { 0x9e,0x1d,0x83,0x83 }, - { 0x74,0x58,0x2c,0x2c }, { 0x2e,0x34,0x1a,0x1a }, + { 0x74,0x58,0x2c,0x2c }, { 0x2e,0x34,0x1a,0x1a }, { 0x2d,0x36,0x1b,0x1b }, { 0xb2,0xdc,0x6e,0x6e }, - { 0xee,0xb4,0x5a,0x5a }, { 0xfb,0x5b,0xa0,0xa0 }, + { 0xee,0xb4,0x5a,0x5a }, { 0xfb,0x5b,0xa0,0xa0 }, { 0xf6,0xa4,0x52,0x52 }, { 0x4d,0x76,0x3b,0x3b }, - { 0x61,0xb7,0xd6,0xd6 }, { 0xce,0x7d,0xb3,0xb3 }, - { 0x7b,0x52,0x29,0x29 }, { 0x3e,0xdd,0xe3,0xe3 }, - { 0x71,0x5e,0x2f,0x2f }, { 0x97,0x13,0x84,0x84 }, - { 0xf5,0xa6,0x53,0x53 }, { 0x68,0xb9,0xd1,0xd1 }, - { 0x00,0x00,0x00,0x00 }, { 0x2c,0xc1,0xed,0xed }, - { 0x60,0x40,0x20,0x20 }, { 0x1f,0xe3,0xfc,0xfc }, - { 0xc8,0x79,0xb1,0xb1 }, { 0xed,0xb6,0x5b,0x5b }, - { 0xbe,0xd4,0x6a,0x6a }, { 0x46,0x8d,0xcb,0xcb }, - { 0xd9,0x67,0xbe,0xbe }, { 0x4b,0x72,0x39,0x39 }, - { 0xde,0x94,0x4a,0x4a }, { 0xd4,0x98,0x4c,0x4c }, - { 0xe8,0xb0,0x58,0x58 }, { 0x4a,0x85,0xcf,0xcf }, + { 0x61,0xb7,0xd6,0xd6 }, { 0xce,0x7d,0xb3,0xb3 }, + { 0x7b,0x52,0x29,0x29 }, { 0x3e,0xdd,0xe3,0xe3 }, + { 0x71,0x5e,0x2f,0x2f }, { 0x97,0x13,0x84,0x84 }, + { 0xf5,0xa6,0x53,0x53 }, { 0x68,0xb9,0xd1,0xd1 }, + { 0x00,0x00,0x00,0x00 }, { 0x2c,0xc1,0xed,0xed }, + { 0x60,0x40,0x20,0x20 }, { 0x1f,0xe3,0xfc,0xfc }, + { 0xc8,0x79,0xb1,0xb1 }, { 0xed,0xb6,0x5b,0x5b }, + { 0xbe,0xd4,0x6a,0x6a }, { 0x46,0x8d,0xcb,0xcb }, + { 0xd9,0x67,0xbe,0xbe }, { 0x4b,0x72,0x39,0x39 }, + { 0xde,0x94,0x4a,0x4a }, { 0xd4,0x98,0x4c,0x4c }, + { 0xe8,0xb0,0x58,0x58 }, { 0x4a,0x85,0xcf,0xcf }, { 0x6b,0xbb,0xd0,0xd0 }, { 0x2a,0xc5,0xef,0xef }, - { 0xe5,0x4f,0xaa,0xaa }, { 0x16,0xed,0xfb,0xfb }, - { 0xc5,0x86,0x43,0x43 }, { 0xd7,0x9a,0x4d,0x4d }, - { 0x55,0x66,0x33,0x33 }, { 0x94,0x11,0x85,0x85 }, - { 0xcf,0x8a,0x45,0x45 }, { 0x10,0xe9,0xf9,0xf9 }, - { 0x06,0x04,0x02,0x02 }, { 0x81,0xfe,0x7f,0x7f }, + { 0xe5,0x4f,0xaa,0xaa }, { 0x16,0xed,0xfb,0xfb }, + { 0xc5,0x86,0x43,0x43 }, { 0xd7,0x9a,0x4d,0x4d }, + { 0x55,0x66,0x33,0x33 }, { 0x94,0x11,0x85,0x85 }, + { 0xcf,0x8a,0x45,0x45 }, { 0x10,0xe9,0xf9,0xf9 }, + { 0x06,0x04,0x02,0x02 }, { 0x81,0xfe,0x7f,0x7f }, { 0xf0,0xa0,0x50,0x50 }, { 0x44,0x78,0x3c,0x3c }, - { 0xba,0x25,0x9f,0x9f }, { 0xe3,0x4b,0xa8,0xa8 }, + { 0xba,0x25,0x9f,0x9f }, { 0xe3,0x4b,0xa8,0xa8 }, { 0xf3,0xa2,0x51,0x51 }, { 0xfe,0x5d,0xa3,0xa3 }, - { 0xc0,0x80,0x40,0x40 }, { 0x8a,0x05,0x8f,0x8f }, + { 0xc0,0x80,0x40,0x40 }, { 0x8a,0x05,0x8f,0x8f }, { 0xad,0x3f,0x92,0x92 }, { 0xbc,0x21,0x9d,0x9d }, - { 0x48,0x70,0x38,0x38 }, { 0x04,0xf1,0xf5,0xf5 }, + { 0x48,0x70,0x38,0x38 }, { 0x04,0xf1,0xf5,0xf5 }, { 0xdf,0x63,0xbc,0xbc }, { 0xc1,0x77,0xb6,0xb6 }, - { 0x75,0xaf,0xda,0xda }, { 0x63,0x42,0x21,0x21 }, + { 0x75,0xaf,0xda,0xda }, { 0x63,0x42,0x21,0x21 }, { 0x30,0x20,0x10,0x10 }, { 0x1a,0xe5,0xff,0xff }, - { 0x0e,0xfd,0xf3,0xf3 }, { 0x6d,0xbf,0xd2,0xd2 }, + { 0x0e,0xfd,0xf3,0xf3 }, { 0x6d,0xbf,0xd2,0xd2 }, { 0x4c,0x81,0xcd,0xcd }, { 0x14,0x18,0x0c,0x0c }, - { 0x35,0x26,0x13,0x13 }, { 0x2f,0xc3,0xec,0xec }, + { 0x35,0x26,0x13,0x13 }, { 0x2f,0xc3,0xec,0xec }, { 0xe1,0xbe,0x5f,0x5f }, { 0xa2,0x35,0x97,0x97 }, - { 0xcc,0x88,0x44,0x44 }, { 0x39,0x2e,0x17,0x17 }, + { 0xcc,0x88,0x44,0x44 }, { 0x39,0x2e,0x17,0x17 }, { 0x57,0x93,0xc4,0xc4 }, { 0xf2,0x55,0xa7,0xa7 }, - { 0x82,0xfc,0x7e,0x7e }, { 0x47,0x7a,0x3d,0x3d }, + { 0x82,0xfc,0x7e,0x7e }, { 0x47,0x7a,0x3d,0x3d }, { 0xac,0xc8,0x64,0x64 }, { 0xe7,0xba,0x5d,0x5d }, - { 0x2b,0x32,0x19,0x19 }, { 0x95,0xe6,0x73,0x73 }, - { 0xa0,0xc0,0x60,0x60 }, { 0x98,0x19,0x81,0x81 }, - { 0xd1,0x9e,0x4f,0x4f }, { 0x7f,0xa3,0xdc,0xdc }, - { 0x66,0x44,0x22,0x22 }, { 0x7e,0x54,0x2a,0x2a }, - { 0xab,0x3b,0x90,0x90 }, { 0x83,0x0b,0x88,0x88 }, + { 0x2b,0x32,0x19,0x19 }, { 0x95,0xe6,0x73,0x73 }, + { 0xa0,0xc0,0x60,0x60 }, { 0x98,0x19,0x81,0x81 }, + { 0xd1,0x9e,0x4f,0x4f }, { 0x7f,0xa3,0xdc,0xdc }, + { 0x66,0x44,0x22,0x22 }, { 0x7e,0x54,0x2a,0x2a }, + { 0xab,0x3b,0x90,0x90 }, { 0x83,0x0b,0x88,0x88 }, { 0xca,0x8c,0x46,0x46 }, { 0x29,0xc7,0xee,0xee }, - { 0xd3,0x6b,0xb8,0xb8 }, { 0x3c,0x28,0x14,0x14 }, + { 0xd3,0x6b,0xb8,0xb8 }, { 0x3c,0x28,0x14,0x14 }, { 0x79,0xa7,0xde,0xde }, { 0xe2,0xbc,0x5e,0x5e }, - { 0x1d,0x16,0x0b,0x0b }, { 0x76,0xad,0xdb,0xdb }, + { 0x1d,0x16,0x0b,0x0b }, { 0x76,0xad,0xdb,0xdb }, { 0x3b,0xdb,0xe0,0xe0 }, { 0x56,0x64,0x32,0x32 }, - { 0x4e,0x74,0x3a,0x3a }, { 0x1e,0x14,0x0a,0x0a }, + { 0x4e,0x74,0x3a,0x3a }, { 0x1e,0x14,0x0a,0x0a }, { 0xdb,0x92,0x49,0x49 }, { 0x0a,0x0c,0x06,0x06 }, - { 0x6c,0x48,0x24,0x24 }, { 0xe4,0xb8,0x5c,0x5c }, - { 0x5d,0x9f,0xc2,0xc2 }, { 0x6e,0xbd,0xd3,0xd3 }, - { 0xef,0x43,0xac,0xac }, { 0xa6,0xc4,0x62,0x62 }, + { 0x6c,0x48,0x24,0x24 }, { 0xe4,0xb8,0x5c,0x5c }, + { 0x5d,0x9f,0xc2,0xc2 }, { 0x6e,0xbd,0xd3,0xd3 }, + { 0xef,0x43,0xac,0xac }, { 0xa6,0xc4,0x62,0x62 }, { 0xa8,0x39,0x91,0x91 }, { 0xa4,0x31,0x95,0x95 }, - { 0x37,0xd3,0xe4,0xe4 }, { 0x8b,0xf2,0x79,0x79 }, + { 0x37,0xd3,0xe4,0xe4 }, { 0x8b,0xf2,0x79,0x79 }, { 0x32,0xd5,0xe7,0xe7 }, { 0x43,0x8b,0xc8,0xc8 }, - { 0x59,0x6e,0x37,0x37 }, { 0xb7,0xda,0x6d,0x6d }, + { 0x59,0x6e,0x37,0x37 }, { 0xb7,0xda,0x6d,0x6d }, { 0x8c,0x01,0x8d,0x8d }, { 0x64,0xb1,0xd5,0xd5 }, - { 0xd2,0x9c,0x4e,0x4e }, { 0xe0,0x49,0xa9,0xa9 }, + { 0xd2,0x9c,0x4e,0x4e }, { 0xe0,0x49,0xa9,0xa9 }, { 0xb4,0xd8,0x6c,0x6c }, { 0xfa,0xac,0x56,0x56 }, - { 0x07,0xf3,0xf4,0xf4 }, { 0x25,0xcf,0xea,0xea }, + { 0x07,0xf3,0xf4,0xf4 }, { 0x25,0xcf,0xea,0xea }, { 0xaf,0xca,0x65,0x65 }, { 0x8e,0xf4,0x7a,0x7a }, - { 0xe9,0x47,0xae,0xae }, { 0x18,0x10,0x08,0x08 }, - { 0xd5,0x6f,0xba,0xba }, { 0x88,0xf0,0x78,0x78 }, - { 0x6f,0x4a,0x25,0x25 }, { 0x72,0x5c,0x2e,0x2e }, - { 0x24,0x38,0x1c,0x1c }, { 0xf1,0x57,0xa6,0xa6 }, - { 0xc7,0x73,0xb4,0xb4 }, { 0x51,0x97,0xc6,0xc6 }, + { 0xe9,0x47,0xae,0xae }, { 0x18,0x10,0x08,0x08 }, + { 0xd5,0x6f,0xba,0xba }, { 0x88,0xf0,0x78,0x78 }, + { 0x6f,0x4a,0x25,0x25 }, { 0x72,0x5c,0x2e,0x2e }, + { 0x24,0x38,0x1c,0x1c }, { 0xf1,0x57,0xa6,0xa6 }, + { 0xc7,0x73,0xb4,0xb4 }, { 0x51,0x97,0xc6,0xc6 }, { 0x23,0xcb,0xe8,0xe8 }, { 0x7c,0xa1,0xdd,0xdd }, - { 0x9c,0xe8,0x74,0x74 }, { 0x21,0x3e,0x1f,0x1f }, + { 0x9c,0xe8,0x74,0x74 }, { 0x21,0x3e,0x1f,0x1f }, { 0xdd,0x96,0x4b,0x4b }, { 0xdc,0x61,0xbd,0xbd }, - { 0x86,0x0d,0x8b,0x8b }, { 0x85,0x0f,0x8a,0x8a }, - { 0x90,0xe0,0x70,0x70 }, { 0x42,0x7c,0x3e,0x3e }, - { 0xc4,0x71,0xb5,0xb5 }, { 0xaa,0xcc,0x66,0x66 }, + { 0x86,0x0d,0x8b,0x8b }, { 0x85,0x0f,0x8a,0x8a }, + { 0x90,0xe0,0x70,0x70 }, { 0x42,0x7c,0x3e,0x3e }, + { 0xc4,0x71,0xb5,0xb5 }, { 0xaa,0xcc,0x66,0x66 }, { 0xd8,0x90,0x48,0x48 }, { 0x05,0x06,0x03,0x03 }, - { 0x01,0xf7,0xf6,0xf6 }, { 0x12,0x1c,0x0e,0x0e }, + { 0x01,0xf7,0xf6,0xf6 }, { 0x12,0x1c,0x0e,0x0e }, { 0xa3,0xc2,0x61,0x61 }, { 0x5f,0x6a,0x35,0x35 }, - { 0xf9,0xae,0x57,0x57 }, { 0xd0,0x69,0xb9,0xb9 }, - { 0x91,0x17,0x86,0x86 }, { 0x58,0x99,0xc1,0xc1 }, - { 0x27,0x3a,0x1d,0x1d }, { 0xb9,0x27,0x9e,0x9e }, + { 0xf9,0xae,0x57,0x57 }, { 0xd0,0x69,0xb9,0xb9 }, + { 0x91,0x17,0x86,0x86 }, { 0x58,0x99,0xc1,0xc1 }, + { 0x27,0x3a,0x1d,0x1d }, { 0xb9,0x27,0x9e,0x9e }, { 0x38,0xd9,0xe1,0xe1 }, { 0x13,0xeb,0xf8,0xf8 }, - { 0xb3,0x2b,0x98,0x98 }, { 0x33,0x22,0x11,0x11 }, + { 0xb3,0x2b,0x98,0x98 }, { 0x33,0x22,0x11,0x11 }, { 0xbb,0xd2,0x69,0x69 }, { 0x70,0xa9,0xd9,0xd9 }, - { 0x89,0x07,0x8e,0x8e }, { 0xa7,0x33,0x94,0x94 }, + { 0x89,0x07,0x8e,0x8e }, { 0xa7,0x33,0x94,0x94 }, { 0xb6,0x2d,0x9b,0x9b }, { 0x22,0x3c,0x1e,0x1e }, - { 0x92,0x15,0x87,0x87 }, { 0x20,0xc9,0xe9,0xe9 }, + { 0x92,0x15,0x87,0x87 }, { 0x20,0xc9,0xe9,0xe9 }, { 0x49,0x87,0xce,0xce }, { 0xff,0xaa,0x55,0x55 }, - { 0x78,0x50,0x28,0x28 }, { 0x7a,0xa5,0xdf,0xdf }, - { 0x8f,0x03,0x8c,0x8c }, { 0xf8,0x59,0xa1,0xa1 }, - { 0x80,0x09,0x89,0x89 }, { 0x17,0x1a,0x0d,0x0d }, + { 0x78,0x50,0x28,0x28 }, { 0x7a,0xa5,0xdf,0xdf }, + { 0x8f,0x03,0x8c,0x8c }, { 0xf8,0x59,0xa1,0xa1 }, + { 0x80,0x09,0x89,0x89 }, { 0x17,0x1a,0x0d,0x0d }, { 0xda,0x65,0xbf,0xbf }, { 0x31,0xd7,0xe6,0xe6 }, - { 0xc6,0x84,0x42,0x42 }, { 0xb8,0xd0,0x68,0x68 }, - { 0xc3,0x82,0x41,0x41 }, { 0xb0,0x29,0x99,0x99 }, - { 0x77,0x5a,0x2d,0x2d }, { 0x11,0x1e,0x0f,0x0f }, - { 0xcb,0x7b,0xb0,0xb0 }, { 0xfc,0xa8,0x54,0x54 }, + { 0xc6,0x84,0x42,0x42 }, { 0xb8,0xd0,0x68,0x68 }, + { 0xc3,0x82,0x41,0x41 }, { 0xb0,0x29,0x99,0x99 }, + { 0x77,0x5a,0x2d,0x2d }, { 0x11,0x1e,0x0f,0x0f }, + { 0xcb,0x7b,0xb0,0xb0 }, { 0xfc,0xa8,0x54,0x54 }, { 0xd6,0x6d,0xbb,0xbb }, { 0x3a,0x2c,0x16,0x16 } }; -static const unsigned char T3[256][4] = +static const unsigned char T3[256][4] = { { 0x63,0xa5,0xc6,0x63 }, { 0x7c,0x84,0xf8,0x7c }, - { 0x77,0x99,0xee,0x77 }, { 0x7b,0x8d,0xf6,0x7b }, + { 0x77,0x99,0xee,0x77 }, { 0x7b,0x8d,0xf6,0x7b }, { 0xf2,0x0d,0xff,0xf2 }, { 0x6b,0xbd,0xd6,0x6b }, - { 0x6f,0xb1,0xde,0x6f }, { 0xc5,0x54,0x91,0xc5 }, + { 0x6f,0xb1,0xde,0x6f }, { 0xc5,0x54,0x91,0xc5 }, { 0x30,0x50,0x60,0x30 }, { 0x01,0x03,0x02,0x01 }, - { 0x67,0xa9,0xce,0x67 }, { 0x2b,0x7d,0x56,0x2b }, - { 0xfe,0x19,0xe7,0xfe }, { 0xd7,0x62,0xb5,0xd7 }, - { 0xab,0xe6,0x4d,0xab }, { 0x76,0x9a,0xec,0x76 }, + { 0x67,0xa9,0xce,0x67 }, { 0x2b,0x7d,0x56,0x2b }, + { 0xfe,0x19,0xe7,0xfe }, { 0xd7,0x62,0xb5,0xd7 }, + { 0xab,0xe6,0x4d,0xab }, { 0x76,0x9a,0xec,0x76 }, { 0xca,0x45,0x8f,0xca }, { 0x82,0x9d,0x1f,0x82 }, - { 0xc9,0x40,0x89,0xc9 }, { 0x7d,0x87,0xfa,0x7d }, - { 0xfa,0x15,0xef,0xfa }, { 0x59,0xeb,0xb2,0x59 }, - { 0x47,0xc9,0x8e,0x47 }, { 0xf0,0x0b,0xfb,0xf0 }, - { 0xad,0xec,0x41,0xad }, { 0xd4,0x67,0xb3,0xd4 }, - { 0xa2,0xfd,0x5f,0xa2 }, { 0xaf,0xea,0x45,0xaf }, + { 0xc9,0x40,0x89,0xc9 }, { 0x7d,0x87,0xfa,0x7d }, + { 0xfa,0x15,0xef,0xfa }, { 0x59,0xeb,0xb2,0x59 }, + { 0x47,0xc9,0x8e,0x47 }, { 0xf0,0x0b,0xfb,0xf0 }, + { 0xad,0xec,0x41,0xad }, { 0xd4,0x67,0xb3,0xd4 }, + { 0xa2,0xfd,0x5f,0xa2 }, { 0xaf,0xea,0x45,0xaf }, { 0x9c,0xbf,0x23,0x9c }, { 0xa4,0xf7,0x53,0xa4 }, - { 0x72,0x96,0xe4,0x72 }, { 0xc0,0x5b,0x9b,0xc0 }, - { 0xb7,0xc2,0x75,0xb7 }, { 0xfd,0x1c,0xe1,0xfd }, - { 0x93,0xae,0x3d,0x93 }, { 0x26,0x6a,0x4c,0x26 }, + { 0x72,0x96,0xe4,0x72 }, { 0xc0,0x5b,0x9b,0xc0 }, + { 0xb7,0xc2,0x75,0xb7 }, { 0xfd,0x1c,0xe1,0xfd }, + { 0x93,0xae,0x3d,0x93 }, { 0x26,0x6a,0x4c,0x26 }, { 0x36,0x5a,0x6c,0x36 }, { 0x3f,0x41,0x7e,0x3f }, - { 0xf7,0x02,0xf5,0xf7 }, { 0xcc,0x4f,0x83,0xcc }, + { 0xf7,0x02,0xf5,0xf7 }, { 0xcc,0x4f,0x83,0xcc }, { 0x34,0x5c,0x68,0x34 }, { 0xa5,0xf4,0x51,0xa5 }, - { 0xe5,0x34,0xd1,0xe5 }, { 0xf1,0x08,0xf9,0xf1 }, + { 0xe5,0x34,0xd1,0xe5 }, { 0xf1,0x08,0xf9,0xf1 }, { 0x71,0x93,0xe2,0x71 }, { 0xd8,0x73,0xab,0xd8 }, - { 0x31,0x53,0x62,0x31 }, { 0x15,0x3f,0x2a,0x15 }, - { 0x04,0x0c,0x08,0x04 }, { 0xc7,0x52,0x95,0xc7 }, - { 0x23,0x65,0x46,0x23 }, { 0xc3,0x5e,0x9d,0xc3 }, + { 0x31,0x53,0x62,0x31 }, { 0x15,0x3f,0x2a,0x15 }, + { 0x04,0x0c,0x08,0x04 }, { 0xc7,0x52,0x95,0xc7 }, + { 0x23,0x65,0x46,0x23 }, { 0xc3,0x5e,0x9d,0xc3 }, { 0x18,0x28,0x30,0x18 }, { 0x96,0xa1,0x37,0x96 }, - { 0x05,0x0f,0x0a,0x05 }, { 0x9a,0xb5,0x2f,0x9a }, - { 0x07,0x09,0x0e,0x07 }, { 0x12,0x36,0x24,0x12 }, - { 0x80,0x9b,0x1b,0x80 }, { 0xe2,0x3d,0xdf,0xe2 }, + { 0x05,0x0f,0x0a,0x05 }, { 0x9a,0xb5,0x2f,0x9a }, + { 0x07,0x09,0x0e,0x07 }, { 0x12,0x36,0x24,0x12 }, + { 0x80,0x9b,0x1b,0x80 }, { 0xe2,0x3d,0xdf,0xe2 }, { 0xeb,0x26,0xcd,0xeb }, { 0x27,0x69,0x4e,0x27 }, - { 0xb2,0xcd,0x7f,0xb2 }, { 0x75,0x9f,0xea,0x75 }, + { 0xb2,0xcd,0x7f,0xb2 }, { 0x75,0x9f,0xea,0x75 }, { 0x09,0x1b,0x12,0x09 }, { 0x83,0x9e,0x1d,0x83 }, - { 0x2c,0x74,0x58,0x2c }, { 0x1a,0x2e,0x34,0x1a }, + { 0x2c,0x74,0x58,0x2c }, { 0x1a,0x2e,0x34,0x1a }, { 0x1b,0x2d,0x36,0x1b }, { 0x6e,0xb2,0xdc,0x6e }, - { 0x5a,0xee,0xb4,0x5a }, { 0xa0,0xfb,0x5b,0xa0 }, + { 0x5a,0xee,0xb4,0x5a }, { 0xa0,0xfb,0x5b,0xa0 }, { 0x52,0xf6,0xa4,0x52 }, { 0x3b,0x4d,0x76,0x3b }, - { 0xd6,0x61,0xb7,0xd6 }, { 0xb3,0xce,0x7d,0xb3 }, - { 0x29,0x7b,0x52,0x29 }, { 0xe3,0x3e,0xdd,0xe3 }, - { 0x2f,0x71,0x5e,0x2f }, { 0x84,0x97,0x13,0x84 }, + { 0xd6,0x61,0xb7,0xd6 }, { 0xb3,0xce,0x7d,0xb3 }, + { 0x29,0x7b,0x52,0x29 }, { 0xe3,0x3e,0xdd,0xe3 }, + { 0x2f,0x71,0x5e,0x2f }, { 0x84,0x97,0x13,0x84 }, { 0x53,0xf5,0xa6,0x53 }, { 0xd1,0x68,0xb9,0xd1 }, - { 0x00,0x00,0x00,0x00 }, { 0xed,0x2c,0xc1,0xed }, + { 0x00,0x00,0x00,0x00 }, { 0xed,0x2c,0xc1,0xed }, { 0x20,0x60,0x40,0x20 }, { 0xfc,0x1f,0xe3,0xfc }, - { 0xb1,0xc8,0x79,0xb1 }, { 0x5b,0xed,0xb6,0x5b }, + { 0xb1,0xc8,0x79,0xb1 }, { 0x5b,0xed,0xb6,0x5b }, { 0x6a,0xbe,0xd4,0x6a }, { 0xcb,0x46,0x8d,0xcb }, - { 0xbe,0xd9,0x67,0xbe }, { 0x39,0x4b,0x72,0x39 }, + { 0xbe,0xd9,0x67,0xbe }, { 0x39,0x4b,0x72,0x39 }, { 0x4a,0xde,0x94,0x4a }, { 0x4c,0xd4,0x98,0x4c }, - { 0x58,0xe8,0xb0,0x58 }, { 0xcf,0x4a,0x85,0xcf }, + { 0x58,0xe8,0xb0,0x58 }, { 0xcf,0x4a,0x85,0xcf }, { 0xd0,0x6b,0xbb,0xd0 }, { 0xef,0x2a,0xc5,0xef }, - { 0xaa,0xe5,0x4f,0xaa }, { 0xfb,0x16,0xed,0xfb }, + { 0xaa,0xe5,0x4f,0xaa }, { 0xfb,0x16,0xed,0xfb }, { 0x43,0xc5,0x86,0x43 }, { 0x4d,0xd7,0x9a,0x4d }, - { 0x33,0x55,0x66,0x33 }, { 0x85,0x94,0x11,0x85 }, + { 0x33,0x55,0x66,0x33 }, { 0x85,0x94,0x11,0x85 }, { 0x45,0xcf,0x8a,0x45 }, { 0xf9,0x10,0xe9,0xf9 }, - { 0x02,0x06,0x04,0x02 }, { 0x7f,0x81,0xfe,0x7f }, + { 0x02,0x06,0x04,0x02 }, { 0x7f,0x81,0xfe,0x7f }, { 0x50,0xf0,0xa0,0x50 }, { 0x3c,0x44,0x78,0x3c }, - { 0x9f,0xba,0x25,0x9f }, { 0xa8,0xe3,0x4b,0xa8 }, + { 0x9f,0xba,0x25,0x9f }, { 0xa8,0xe3,0x4b,0xa8 }, { 0x51,0xf3,0xa2,0x51 }, { 0xa3,0xfe,0x5d,0xa3 }, - { 0x40,0xc0,0x80,0x40 }, { 0x8f,0x8a,0x05,0x8f }, + { 0x40,0xc0,0x80,0x40 }, { 0x8f,0x8a,0x05,0x8f }, { 0x92,0xad,0x3f,0x92 }, { 0x9d,0xbc,0x21,0x9d }, - { 0x38,0x48,0x70,0x38 }, { 0xf5,0x04,0xf1,0xf5 }, + { 0x38,0x48,0x70,0x38 }, { 0xf5,0x04,0xf1,0xf5 }, { 0xbc,0xdf,0x63,0xbc }, { 0xb6,0xc1,0x77,0xb6 }, - { 0xda,0x75,0xaf,0xda }, { 0x21,0x63,0x42,0x21 }, + { 0xda,0x75,0xaf,0xda }, { 0x21,0x63,0x42,0x21 }, { 0x10,0x30,0x20,0x10 }, { 0xff,0x1a,0xe5,0xff }, - { 0xf3,0x0e,0xfd,0xf3 }, { 0xd2,0x6d,0xbf,0xd2 }, - { 0xcd,0x4c,0x81,0xcd }, { 0x0c,0x14,0x18,0x0c }, - { 0x13,0x35,0x26,0x13 }, { 0xec,0x2f,0xc3,0xec }, + { 0xf3,0x0e,0xfd,0xf3 }, { 0xd2,0x6d,0xbf,0xd2 }, + { 0xcd,0x4c,0x81,0xcd }, { 0x0c,0x14,0x18,0x0c }, + { 0x13,0x35,0x26,0x13 }, { 0xec,0x2f,0xc3,0xec }, { 0x5f,0xe1,0xbe,0x5f }, { 0x97,0xa2,0x35,0x97 }, - { 0x44,0xcc,0x88,0x44 }, { 0x17,0x39,0x2e,0x17 }, + { 0x44,0xcc,0x88,0x44 }, { 0x17,0x39,0x2e,0x17 }, { 0xc4,0x57,0x93,0xc4 }, { 0xa7,0xf2,0x55,0xa7 }, - { 0x7e,0x82,0xfc,0x7e }, { 0x3d,0x47,0x7a,0x3d }, + { 0x7e,0x82,0xfc,0x7e }, { 0x3d,0x47,0x7a,0x3d }, { 0x64,0xac,0xc8,0x64 }, { 0x5d,0xe7,0xba,0x5d }, - { 0x19,0x2b,0x32,0x19 }, { 0x73,0x95,0xe6,0x73 }, + { 0x19,0x2b,0x32,0x19 }, { 0x73,0x95,0xe6,0x73 }, { 0x60,0xa0,0xc0,0x60 }, { 0x81,0x98,0x19,0x81 }, - { 0x4f,0xd1,0x9e,0x4f }, { 0xdc,0x7f,0xa3,0xdc }, + { 0x4f,0xd1,0x9e,0x4f }, { 0xdc,0x7f,0xa3,0xdc }, { 0x22,0x66,0x44,0x22 }, { 0x2a,0x7e,0x54,0x2a }, - { 0x90,0xab,0x3b,0x90 }, { 0x88,0x83,0x0b,0x88 }, + { 0x90,0xab,0x3b,0x90 }, { 0x88,0x83,0x0b,0x88 }, { 0x46,0xca,0x8c,0x46 }, { 0xee,0x29,0xc7,0xee }, - { 0xb8,0xd3,0x6b,0xb8 }, { 0x14,0x3c,0x28,0x14 }, - { 0xde,0x79,0xa7,0xde }, { 0x5e,0xe2,0xbc,0x5e }, - { 0x0b,0x1d,0x16,0x0b }, { 0xdb,0x76,0xad,0xdb }, + { 0xb8,0xd3,0x6b,0xb8 }, { 0x14,0x3c,0x28,0x14 }, + { 0xde,0x79,0xa7,0xde }, { 0x5e,0xe2,0xbc,0x5e }, + { 0x0b,0x1d,0x16,0x0b }, { 0xdb,0x76,0xad,0xdb }, { 0xe0,0x3b,0xdb,0xe0 }, { 0x32,0x56,0x64,0x32 }, - { 0x3a,0x4e,0x74,0x3a }, { 0x0a,0x1e,0x14,0x0a }, + { 0x3a,0x4e,0x74,0x3a }, { 0x0a,0x1e,0x14,0x0a }, { 0x49,0xdb,0x92,0x49 }, { 0x06,0x0a,0x0c,0x06 }, - { 0x24,0x6c,0x48,0x24 }, { 0x5c,0xe4,0xb8,0x5c }, + { 0x24,0x6c,0x48,0x24 }, { 0x5c,0xe4,0xb8,0x5c }, { 0xc2,0x5d,0x9f,0xc2 }, { 0xd3,0x6e,0xbd,0xd3 }, - { 0xac,0xef,0x43,0xac }, { 0x62,0xa6,0xc4,0x62 }, + { 0xac,0xef,0x43,0xac }, { 0x62,0xa6,0xc4,0x62 }, { 0x91,0xa8,0x39,0x91 }, { 0x95,0xa4,0x31,0x95 }, - { 0xe4,0x37,0xd3,0xe4 }, { 0x79,0x8b,0xf2,0x79 }, - { 0xe7,0x32,0xd5,0xe7 }, { 0xc8,0x43,0x8b,0xc8 }, - { 0x37,0x59,0x6e,0x37 }, { 0x6d,0xb7,0xda,0x6d }, - { 0x8d,0x8c,0x01,0x8d }, { 0xd5,0x64,0xb1,0xd5 }, - { 0x4e,0xd2,0x9c,0x4e }, { 0xa9,0xe0,0x49,0xa9 }, + { 0xe4,0x37,0xd3,0xe4 }, { 0x79,0x8b,0xf2,0x79 }, + { 0xe7,0x32,0xd5,0xe7 }, { 0xc8,0x43,0x8b,0xc8 }, + { 0x37,0x59,0x6e,0x37 }, { 0x6d,0xb7,0xda,0x6d }, + { 0x8d,0x8c,0x01,0x8d }, { 0xd5,0x64,0xb1,0xd5 }, + { 0x4e,0xd2,0x9c,0x4e }, { 0xa9,0xe0,0x49,0xa9 }, { 0x6c,0xb4,0xd8,0x6c }, { 0x56,0xfa,0xac,0x56 }, - { 0xf4,0x07,0xf3,0xf4 }, { 0xea,0x25,0xcf,0xea }, - { 0x65,0xaf,0xca,0x65 }, { 0x7a,0x8e,0xf4,0x7a }, - { 0xae,0xe9,0x47,0xae }, { 0x08,0x18,0x10,0x08 }, - { 0xba,0xd5,0x6f,0xba }, { 0x78,0x88,0xf0,0x78 }, - { 0x25,0x6f,0x4a,0x25 }, { 0x2e,0x72,0x5c,0x2e }, - { 0x1c,0x24,0x38,0x1c }, { 0xa6,0xf1,0x57,0xa6 }, - { 0xb4,0xc7,0x73,0xb4 }, { 0xc6,0x51,0x97,0xc6 }, + { 0xf4,0x07,0xf3,0xf4 }, { 0xea,0x25,0xcf,0xea }, + { 0x65,0xaf,0xca,0x65 }, { 0x7a,0x8e,0xf4,0x7a }, + { 0xae,0xe9,0x47,0xae }, { 0x08,0x18,0x10,0x08 }, + { 0xba,0xd5,0x6f,0xba }, { 0x78,0x88,0xf0,0x78 }, + { 0x25,0x6f,0x4a,0x25 }, { 0x2e,0x72,0x5c,0x2e }, + { 0x1c,0x24,0x38,0x1c }, { 0xa6,0xf1,0x57,0xa6 }, + { 0xb4,0xc7,0x73,0xb4 }, { 0xc6,0x51,0x97,0xc6 }, { 0xe8,0x23,0xcb,0xe8 }, { 0xdd,0x7c,0xa1,0xdd }, - { 0x74,0x9c,0xe8,0x74 }, { 0x1f,0x21,0x3e,0x1f }, + { 0x74,0x9c,0xe8,0x74 }, { 0x1f,0x21,0x3e,0x1f }, { 0x4b,0xdd,0x96,0x4b }, { 0xbd,0xdc,0x61,0xbd }, - { 0x8b,0x86,0x0d,0x8b }, { 0x8a,0x85,0x0f,0x8a }, + { 0x8b,0x86,0x0d,0x8b }, { 0x8a,0x85,0x0f,0x8a }, { 0x70,0x90,0xe0,0x70 }, { 0x3e,0x42,0x7c,0x3e }, - { 0xb5,0xc4,0x71,0xb5 }, { 0x66,0xaa,0xcc,0x66 }, + { 0xb5,0xc4,0x71,0xb5 }, { 0x66,0xaa,0xcc,0x66 }, { 0x48,0xd8,0x90,0x48 }, { 0x03,0x05,0x06,0x03 }, - { 0xf6,0x01,0xf7,0xf6 }, { 0x0e,0x12,0x1c,0x0e }, + { 0xf6,0x01,0xf7,0xf6 }, { 0x0e,0x12,0x1c,0x0e }, { 0x61,0xa3,0xc2,0x61 }, { 0x35,0x5f,0x6a,0x35 }, - { 0x57,0xf9,0xae,0x57 }, { 0xb9,0xd0,0x69,0xb9 }, - { 0x86,0x91,0x17,0x86 }, { 0xc1,0x58,0x99,0xc1 }, - { 0x1d,0x27,0x3a,0x1d }, { 0x9e,0xb9,0x27,0x9e }, + { 0x57,0xf9,0xae,0x57 }, { 0xb9,0xd0,0x69,0xb9 }, + { 0x86,0x91,0x17,0x86 }, { 0xc1,0x58,0x99,0xc1 }, + { 0x1d,0x27,0x3a,0x1d }, { 0x9e,0xb9,0x27,0x9e }, { 0xe1,0x38,0xd9,0xe1 }, { 0xf8,0x13,0xeb,0xf8 }, - { 0x98,0xb3,0x2b,0x98 }, { 0x11,0x33,0x22,0x11 }, + { 0x98,0xb3,0x2b,0x98 }, { 0x11,0x33,0x22,0x11 }, { 0x69,0xbb,0xd2,0x69 }, { 0xd9,0x70,0xa9,0xd9 }, - { 0x8e,0x89,0x07,0x8e }, { 0x94,0xa7,0x33,0x94 }, + { 0x8e,0x89,0x07,0x8e }, { 0x94,0xa7,0x33,0x94 }, { 0x9b,0xb6,0x2d,0x9b }, { 0x1e,0x22,0x3c,0x1e }, - { 0x87,0x92,0x15,0x87 }, { 0xe9,0x20,0xc9,0xe9 }, + { 0x87,0x92,0x15,0x87 }, { 0xe9,0x20,0xc9,0xe9 }, { 0xce,0x49,0x87,0xce }, { 0x55,0xff,0xaa,0x55 }, - { 0x28,0x78,0x50,0x28 }, { 0xdf,0x7a,0xa5,0xdf }, + { 0x28,0x78,0x50,0x28 }, { 0xdf,0x7a,0xa5,0xdf }, { 0x8c,0x8f,0x03,0x8c }, { 0xa1,0xf8,0x59,0xa1 }, - { 0x89,0x80,0x09,0x89 }, { 0x0d,0x17,0x1a,0x0d }, + { 0x89,0x80,0x09,0x89 }, { 0x0d,0x17,0x1a,0x0d }, { 0xbf,0xda,0x65,0xbf }, { 0xe6,0x31,0xd7,0xe6 }, - { 0x42,0xc6,0x84,0x42 }, { 0x68,0xb8,0xd0,0x68 }, + { 0x42,0xc6,0x84,0x42 }, { 0x68,0xb8,0xd0,0x68 }, { 0x41,0xc3,0x82,0x41 }, { 0x99,0xb0,0x29,0x99 }, - { 0x2d,0x77,0x5a,0x2d }, { 0x0f,0x11,0x1e,0x0f }, + { 0x2d,0x77,0x5a,0x2d }, { 0x0f,0x11,0x1e,0x0f }, { 0xb0,0xcb,0x7b,0xb0 }, { 0x54,0xfc,0xa8,0x54 }, { 0xbb,0xd6,0x6d,0xbb }, { 0x16,0x3a,0x2c,0x16 } }; -static const unsigned char T4[256][4] = +static const unsigned char T4[256][4] = { { 0x63,0x63,0xa5,0xc6 }, { 0x7c,0x7c,0x84,0xf8 }, - { 0x77,0x77,0x99,0xee }, { 0x7b,0x7b,0x8d,0xf6 }, - { 0xf2,0xf2,0x0d,0xff }, { 0x6b,0x6b,0xbd,0xd6 }, - { 0x6f,0x6f,0xb1,0xde }, { 0xc5,0xc5,0x54,0x91 }, + { 0x77,0x77,0x99,0xee }, { 0x7b,0x7b,0x8d,0xf6 }, + { 0xf2,0xf2,0x0d,0xff }, { 0x6b,0x6b,0xbd,0xd6 }, + { 0x6f,0x6f,0xb1,0xde }, { 0xc5,0xc5,0x54,0x91 }, { 0x30,0x30,0x50,0x60 }, { 0x01,0x01,0x03,0x02 }, - { 0x67,0x67,0xa9,0xce }, { 0x2b,0x2b,0x7d,0x56 }, + { 0x67,0x67,0xa9,0xce }, { 0x2b,0x2b,0x7d,0x56 }, { 0xfe,0xfe,0x19,0xe7 }, { 0xd7,0xd7,0x62,0xb5 }, - { 0xab,0xab,0xe6,0x4d }, { 0x76,0x76,0x9a,0xec }, + { 0xab,0xab,0xe6,0x4d }, { 0x76,0x76,0x9a,0xec }, { 0xca,0xca,0x45,0x8f }, { 0x82,0x82,0x9d,0x1f }, - { 0xc9,0xc9,0x40,0x89 }, { 0x7d,0x7d,0x87,0xfa }, + { 0xc9,0xc9,0x40,0x89 }, { 0x7d,0x7d,0x87,0xfa }, { 0xfa,0xfa,0x15,0xef }, { 0x59,0x59,0xeb,0xb2 }, - { 0x47,0x47,0xc9,0x8e }, { 0xf0,0xf0,0x0b,0xfb }, + { 0x47,0x47,0xc9,0x8e }, { 0xf0,0xf0,0x0b,0xfb }, { 0xad,0xad,0xec,0x41 }, { 0xd4,0xd4,0x67,0xb3 }, - { 0xa2,0xa2,0xfd,0x5f }, { 0xaf,0xaf,0xea,0x45 }, + { 0xa2,0xa2,0xfd,0x5f }, { 0xaf,0xaf,0xea,0x45 }, { 0x9c,0x9c,0xbf,0x23 }, { 0xa4,0xa4,0xf7,0x53 }, - { 0x72,0x72,0x96,0xe4 }, { 0xc0,0xc0,0x5b,0x9b }, + { 0x72,0x72,0x96,0xe4 }, { 0xc0,0xc0,0x5b,0x9b }, { 0xb7,0xb7,0xc2,0x75 }, { 0xfd,0xfd,0x1c,0xe1 }, - { 0x93,0x93,0xae,0x3d }, { 0x26,0x26,0x6a,0x4c }, + { 0x93,0x93,0xae,0x3d }, { 0x26,0x26,0x6a,0x4c }, { 0x36,0x36,0x5a,0x6c }, { 0x3f,0x3f,0x41,0x7e }, - { 0xf7,0xf7,0x02,0xf5 }, { 0xcc,0xcc,0x4f,0x83 }, + { 0xf7,0xf7,0x02,0xf5 }, { 0xcc,0xcc,0x4f,0x83 }, { 0x34,0x34,0x5c,0x68 }, { 0xa5,0xa5,0xf4,0x51 }, - { 0xe5,0xe5,0x34,0xd1 }, { 0xf1,0xf1,0x08,0xf9 }, + { 0xe5,0xe5,0x34,0xd1 }, { 0xf1,0xf1,0x08,0xf9 }, { 0x71,0x71,0x93,0xe2 }, { 0xd8,0xd8,0x73,0xab }, - { 0x31,0x31,0x53,0x62 }, { 0x15,0x15,0x3f,0x2a }, + { 0x31,0x31,0x53,0x62 }, { 0x15,0x15,0x3f,0x2a }, { 0x04,0x04,0x0c,0x08 }, { 0xc7,0xc7,0x52,0x95 }, - { 0x23,0x23,0x65,0x46 }, { 0xc3,0xc3,0x5e,0x9d }, + { 0x23,0x23,0x65,0x46 }, { 0xc3,0xc3,0x5e,0x9d }, { 0x18,0x18,0x28,0x30 }, { 0x96,0x96,0xa1,0x37 }, - { 0x05,0x05,0x0f,0x0a }, { 0x9a,0x9a,0xb5,0x2f }, + { 0x05,0x05,0x0f,0x0a }, { 0x9a,0x9a,0xb5,0x2f }, { 0x07,0x07,0x09,0x0e }, { 0x12,0x12,0x36,0x24 }, - { 0x80,0x80,0x9b,0x1b }, { 0xe2,0xe2,0x3d,0xdf }, + { 0x80,0x80,0x9b,0x1b }, { 0xe2,0xe2,0x3d,0xdf }, { 0xeb,0xeb,0x26,0xcd }, { 0x27,0x27,0x69,0x4e }, - { 0xb2,0xb2,0xcd,0x7f }, { 0x75,0x75,0x9f,0xea }, + { 0xb2,0xb2,0xcd,0x7f }, { 0x75,0x75,0x9f,0xea }, { 0x09,0x09,0x1b,0x12 }, { 0x83,0x83,0x9e,0x1d }, - { 0x2c,0x2c,0x74,0x58 }, { 0x1a,0x1a,0x2e,0x34 }, + { 0x2c,0x2c,0x74,0x58 }, { 0x1a,0x1a,0x2e,0x34 }, { 0x1b,0x1b,0x2d,0x36 }, { 0x6e,0x6e,0xb2,0xdc }, - { 0x5a,0x5a,0xee,0xb4 }, { 0xa0,0xa0,0xfb,0x5b }, + { 0x5a,0x5a,0xee,0xb4 }, { 0xa0,0xa0,0xfb,0x5b }, { 0x52,0x52,0xf6,0xa4 }, { 0x3b,0x3b,0x4d,0x76 }, - { 0xd6,0xd6,0x61,0xb7 }, { 0xb3,0xb3,0xce,0x7d }, + { 0xd6,0xd6,0x61,0xb7 }, { 0xb3,0xb3,0xce,0x7d }, { 0x29,0x29,0x7b,0x52 }, { 0xe3,0xe3,0x3e,0xdd }, - { 0x2f,0x2f,0x71,0x5e }, { 0x84,0x84,0x97,0x13 }, + { 0x2f,0x2f,0x71,0x5e }, { 0x84,0x84,0x97,0x13 }, { 0x53,0x53,0xf5,0xa6 }, { 0xd1,0xd1,0x68,0xb9 }, - { 0x00,0x00,0x00,0x00 }, { 0xed,0xed,0x2c,0xc1 }, + { 0x00,0x00,0x00,0x00 }, { 0xed,0xed,0x2c,0xc1 }, { 0x20,0x20,0x60,0x40 }, { 0xfc,0xfc,0x1f,0xe3 }, - { 0xb1,0xb1,0xc8,0x79 }, { 0x5b,0x5b,0xed,0xb6 }, + { 0xb1,0xb1,0xc8,0x79 }, { 0x5b,0x5b,0xed,0xb6 }, { 0x6a,0x6a,0xbe,0xd4 }, { 0xcb,0xcb,0x46,0x8d }, - { 0xbe,0xbe,0xd9,0x67 }, { 0x39,0x39,0x4b,0x72 }, + { 0xbe,0xbe,0xd9,0x67 }, { 0x39,0x39,0x4b,0x72 }, { 0x4a,0x4a,0xde,0x94 }, { 0x4c,0x4c,0xd4,0x98 }, - { 0x58,0x58,0xe8,0xb0 }, { 0xcf,0xcf,0x4a,0x85 }, + { 0x58,0x58,0xe8,0xb0 }, { 0xcf,0xcf,0x4a,0x85 }, { 0xd0,0xd0,0x6b,0xbb }, { 0xef,0xef,0x2a,0xc5 }, - { 0xaa,0xaa,0xe5,0x4f }, { 0xfb,0xfb,0x16,0xed }, + { 0xaa,0xaa,0xe5,0x4f }, { 0xfb,0xfb,0x16,0xed }, { 0x43,0x43,0xc5,0x86 }, { 0x4d,0x4d,0xd7,0x9a }, - { 0x33,0x33,0x55,0x66 }, { 0x85,0x85,0x94,0x11 }, + { 0x33,0x33,0x55,0x66 }, { 0x85,0x85,0x94,0x11 }, { 0x45,0x45,0xcf,0x8a }, { 0xf9,0xf9,0x10,0xe9 }, - { 0x02,0x02,0x06,0x04 }, { 0x7f,0x7f,0x81,0xfe }, + { 0x02,0x02,0x06,0x04 }, { 0x7f,0x7f,0x81,0xfe }, { 0x50,0x50,0xf0,0xa0 }, { 0x3c,0x3c,0x44,0x78 }, - { 0x9f,0x9f,0xba,0x25 }, { 0xa8,0xa8,0xe3,0x4b }, + { 0x9f,0x9f,0xba,0x25 }, { 0xa8,0xa8,0xe3,0x4b }, { 0x51,0x51,0xf3,0xa2 }, { 0xa3,0xa3,0xfe,0x5d }, - { 0x40,0x40,0xc0,0x80 }, { 0x8f,0x8f,0x8a,0x05 }, + { 0x40,0x40,0xc0,0x80 }, { 0x8f,0x8f,0x8a,0x05 }, { 0x92,0x92,0xad,0x3f }, { 0x9d,0x9d,0xbc,0x21 }, - { 0x38,0x38,0x48,0x70 }, { 0xf5,0xf5,0x04,0xf1 }, + { 0x38,0x38,0x48,0x70 }, { 0xf5,0xf5,0x04,0xf1 }, { 0xbc,0xbc,0xdf,0x63 }, { 0xb6,0xb6,0xc1,0x77 }, - { 0xda,0xda,0x75,0xaf }, { 0x21,0x21,0x63,0x42 }, + { 0xda,0xda,0x75,0xaf }, { 0x21,0x21,0x63,0x42 }, { 0x10,0x10,0x30,0x20 }, { 0xff,0xff,0x1a,0xe5 }, - { 0xf3,0xf3,0x0e,0xfd }, { 0xd2,0xd2,0x6d,0xbf }, + { 0xf3,0xf3,0x0e,0xfd }, { 0xd2,0xd2,0x6d,0xbf }, { 0xcd,0xcd,0x4c,0x81 }, { 0x0c,0x0c,0x14,0x18 }, - { 0x13,0x13,0x35,0x26 }, { 0xec,0xec,0x2f,0xc3 }, + { 0x13,0x13,0x35,0x26 }, { 0xec,0xec,0x2f,0xc3 }, { 0x5f,0x5f,0xe1,0xbe }, { 0x97,0x97,0xa2,0x35 }, - { 0x44,0x44,0xcc,0x88 }, { 0x17,0x17,0x39,0x2e }, + { 0x44,0x44,0xcc,0x88 }, { 0x17,0x17,0x39,0x2e }, { 0xc4,0xc4,0x57,0x93 }, { 0xa7,0xa7,0xf2,0x55 }, - { 0x7e,0x7e,0x82,0xfc }, { 0x3d,0x3d,0x47,0x7a }, + { 0x7e,0x7e,0x82,0xfc }, { 0x3d,0x3d,0x47,0x7a }, { 0x64,0x64,0xac,0xc8 }, { 0x5d,0x5d,0xe7,0xba }, - { 0x19,0x19,0x2b,0x32 }, { 0x73,0x73,0x95,0xe6 }, + { 0x19,0x19,0x2b,0x32 }, { 0x73,0x73,0x95,0xe6 }, { 0x60,0x60,0xa0,0xc0 }, { 0x81,0x81,0x98,0x19 }, - { 0x4f,0x4f,0xd1,0x9e }, { 0xdc,0xdc,0x7f,0xa3 }, + { 0x4f,0x4f,0xd1,0x9e }, { 0xdc,0xdc,0x7f,0xa3 }, { 0x22,0x22,0x66,0x44 }, { 0x2a,0x2a,0x7e,0x54 }, - { 0x90,0x90,0xab,0x3b }, { 0x88,0x88,0x83,0x0b }, + { 0x90,0x90,0xab,0x3b }, { 0x88,0x88,0x83,0x0b }, { 0x46,0x46,0xca,0x8c }, { 0xee,0xee,0x29,0xc7 }, - { 0xb8,0xb8,0xd3,0x6b }, { 0x14,0x14,0x3c,0x28 }, + { 0xb8,0xb8,0xd3,0x6b }, { 0x14,0x14,0x3c,0x28 }, { 0xde,0xde,0x79,0xa7 }, { 0x5e,0x5e,0xe2,0xbc }, - { 0x0b,0x0b,0x1d,0x16 }, { 0xdb,0xdb,0x76,0xad }, + { 0x0b,0x0b,0x1d,0x16 }, { 0xdb,0xdb,0x76,0xad }, { 0xe0,0xe0,0x3b,0xdb }, { 0x32,0x32,0x56,0x64 }, - { 0x3a,0x3a,0x4e,0x74 }, { 0x0a,0x0a,0x1e,0x14 }, + { 0x3a,0x3a,0x4e,0x74 }, { 0x0a,0x0a,0x1e,0x14 }, { 0x49,0x49,0xdb,0x92 }, { 0x06,0x06,0x0a,0x0c }, - { 0x24,0x24,0x6c,0x48 }, { 0x5c,0x5c,0xe4,0xb8 }, + { 0x24,0x24,0x6c,0x48 }, { 0x5c,0x5c,0xe4,0xb8 }, { 0xc2,0xc2,0x5d,0x9f }, { 0xd3,0xd3,0x6e,0xbd }, - { 0xac,0xac,0xef,0x43 }, { 0x62,0x62,0xa6,0xc4 }, + { 0xac,0xac,0xef,0x43 }, { 0x62,0x62,0xa6,0xc4 }, { 0x91,0x91,0xa8,0x39 }, { 0x95,0x95,0xa4,0x31 }, - { 0xe4,0xe4,0x37,0xd3 }, { 0x79,0x79,0x8b,0xf2 }, + { 0xe4,0xe4,0x37,0xd3 }, { 0x79,0x79,0x8b,0xf2 }, { 0xe7,0xe7,0x32,0xd5 }, { 0xc8,0xc8,0x43,0x8b }, - { 0x37,0x37,0x59,0x6e }, { 0x6d,0x6d,0xb7,0xda }, - { 0x8d,0x8d,0x8c,0x01 }, { 0xd5,0xd5,0x64,0xb1 }, - { 0x4e,0x4e,0xd2,0x9c }, { 0xa9,0xa9,0xe0,0x49 }, - { 0x6c,0x6c,0xb4,0xd8 }, { 0x56,0x56,0xfa,0xac }, - { 0xf4,0xf4,0x07,0xf3 }, { 0xea,0xea,0x25,0xcf }, - { 0x65,0x65,0xaf,0xca }, { 0x7a,0x7a,0x8e,0xf4 }, - { 0xae,0xae,0xe9,0x47 }, { 0x08,0x08,0x18,0x10 }, - { 0xba,0xba,0xd5,0x6f }, { 0x78,0x78,0x88,0xf0 }, - { 0x25,0x25,0x6f,0x4a }, { 0x2e,0x2e,0x72,0x5c }, + { 0x37,0x37,0x59,0x6e }, { 0x6d,0x6d,0xb7,0xda }, + { 0x8d,0x8d,0x8c,0x01 }, { 0xd5,0xd5,0x64,0xb1 }, + { 0x4e,0x4e,0xd2,0x9c }, { 0xa9,0xa9,0xe0,0x49 }, + { 0x6c,0x6c,0xb4,0xd8 }, { 0x56,0x56,0xfa,0xac }, + { 0xf4,0xf4,0x07,0xf3 }, { 0xea,0xea,0x25,0xcf }, + { 0x65,0x65,0xaf,0xca }, { 0x7a,0x7a,0x8e,0xf4 }, + { 0xae,0xae,0xe9,0x47 }, { 0x08,0x08,0x18,0x10 }, + { 0xba,0xba,0xd5,0x6f }, { 0x78,0x78,0x88,0xf0 }, + { 0x25,0x25,0x6f,0x4a }, { 0x2e,0x2e,0x72,0x5c }, { 0x1c,0x1c,0x24,0x38 }, { 0xa6,0xa6,0xf1,0x57 }, - { 0xb4,0xb4,0xc7,0x73 }, { 0xc6,0xc6,0x51,0x97 }, + { 0xb4,0xb4,0xc7,0x73 }, { 0xc6,0xc6,0x51,0x97 }, { 0xe8,0xe8,0x23,0xcb }, { 0xdd,0xdd,0x7c,0xa1 }, - { 0x74,0x74,0x9c,0xe8 }, { 0x1f,0x1f,0x21,0x3e }, + { 0x74,0x74,0x9c,0xe8 }, { 0x1f,0x1f,0x21,0x3e }, { 0x4b,0x4b,0xdd,0x96 }, { 0xbd,0xbd,0xdc,0x61 }, - { 0x8b,0x8b,0x86,0x0d }, { 0x8a,0x8a,0x85,0x0f }, + { 0x8b,0x8b,0x86,0x0d }, { 0x8a,0x8a,0x85,0x0f }, { 0x70,0x70,0x90,0xe0 }, { 0x3e,0x3e,0x42,0x7c }, - { 0xb5,0xb5,0xc4,0x71 }, { 0x66,0x66,0xaa,0xcc }, + { 0xb5,0xb5,0xc4,0x71 }, { 0x66,0x66,0xaa,0xcc }, { 0x48,0x48,0xd8,0x90 }, { 0x03,0x03,0x05,0x06 }, - { 0xf6,0xf6,0x01,0xf7 }, { 0x0e,0x0e,0x12,0x1c }, + { 0xf6,0xf6,0x01,0xf7 }, { 0x0e,0x0e,0x12,0x1c }, { 0x61,0x61,0xa3,0xc2 }, { 0x35,0x35,0x5f,0x6a }, - { 0x57,0x57,0xf9,0xae }, { 0xb9,0xb9,0xd0,0x69 }, + { 0x57,0x57,0xf9,0xae }, { 0xb9,0xb9,0xd0,0x69 }, { 0x86,0x86,0x91,0x17 }, { 0xc1,0xc1,0x58,0x99 }, - { 0x1d,0x1d,0x27,0x3a }, { 0x9e,0x9e,0xb9,0x27 }, + { 0x1d,0x1d,0x27,0x3a }, { 0x9e,0x9e,0xb9,0x27 }, { 0xe1,0xe1,0x38,0xd9 }, { 0xf8,0xf8,0x13,0xeb }, - { 0x98,0x98,0xb3,0x2b }, { 0x11,0x11,0x33,0x22 }, + { 0x98,0x98,0xb3,0x2b }, { 0x11,0x11,0x33,0x22 }, { 0x69,0x69,0xbb,0xd2 }, { 0xd9,0xd9,0x70,0xa9 }, - { 0x8e,0x8e,0x89,0x07 }, { 0x94,0x94,0xa7,0x33 }, + { 0x8e,0x8e,0x89,0x07 }, { 0x94,0x94,0xa7,0x33 }, { 0x9b,0x9b,0xb6,0x2d }, { 0x1e,0x1e,0x22,0x3c }, - { 0x87,0x87,0x92,0x15 }, { 0xe9,0xe9,0x20,0xc9 }, + { 0x87,0x87,0x92,0x15 }, { 0xe9,0xe9,0x20,0xc9 }, { 0xce,0xce,0x49,0x87 }, { 0x55,0x55,0xff,0xaa }, - { 0x28,0x28,0x78,0x50 }, { 0xdf,0xdf,0x7a,0xa5 }, + { 0x28,0x28,0x78,0x50 }, { 0xdf,0xdf,0x7a,0xa5 }, { 0x8c,0x8c,0x8f,0x03 }, { 0xa1,0xa1,0xf8,0x59 }, - { 0x89,0x89,0x80,0x09 }, { 0x0d,0x0d,0x17,0x1a }, - { 0xbf,0xbf,0xda,0x65 }, { 0xe6,0xe6,0x31,0xd7 }, - { 0x42,0x42,0xc6,0x84 }, { 0x68,0x68,0xb8,0xd0 }, + { 0x89,0x89,0x80,0x09 }, { 0x0d,0x0d,0x17,0x1a }, + { 0xbf,0xbf,0xda,0x65 }, { 0xe6,0xe6,0x31,0xd7 }, + { 0x42,0x42,0xc6,0x84 }, { 0x68,0x68,0xb8,0xd0 }, { 0x41,0x41,0xc3,0x82 }, { 0x99,0x99,0xb0,0x29 }, - { 0x2d,0x2d,0x77,0x5a }, { 0x0f,0x0f,0x11,0x1e }, + { 0x2d,0x2d,0x77,0x5a }, { 0x0f,0x0f,0x11,0x1e }, { 0xb0,0xb0,0xcb,0x7b }, { 0x54,0x54,0xfc,0xa8 }, { 0xbb,0xbb,0xd6,0x6d }, { 0x16,0x16,0x3a,0x2c } }; -static const unsigned char T5[256][4] = +static const unsigned char T5[256][4] = { - { 0x51,0xf4,0xa7,0x50 }, { 0x7e,0x41,0x65,0x53 }, - { 0x1a,0x17,0xa4,0xc3 }, { 0x3a,0x27,0x5e,0x96 }, + { 0x51,0xf4,0xa7,0x50 }, { 0x7e,0x41,0x65,0x53 }, + { 0x1a,0x17,0xa4,0xc3 }, { 0x3a,0x27,0x5e,0x96 }, { 0x3b,0xab,0x6b,0xcb }, { 0x1f,0x9d,0x45,0xf1 }, - { 0xac,0xfa,0x58,0xab }, { 0x4b,0xe3,0x03,0x93 }, + { 0xac,0xfa,0x58,0xab }, { 0x4b,0xe3,0x03,0x93 }, { 0x20,0x30,0xfa,0x55 }, { 0xad,0x76,0x6d,0xf6 }, - { 0x88,0xcc,0x76,0x91 }, { 0xf5,0x02,0x4c,0x25 }, + { 0x88,0xcc,0x76,0x91 }, { 0xf5,0x02,0x4c,0x25 }, { 0x4f,0xe5,0xd7,0xfc }, { 0xc5,0x2a,0xcb,0xd7 }, - { 0x26,0x35,0x44,0x80 }, { 0xb5,0x62,0xa3,0x8f }, + { 0x26,0x35,0x44,0x80 }, { 0xb5,0x62,0xa3,0x8f }, { 0xde,0xb1,0x5a,0x49 }, { 0x25,0xba,0x1b,0x67 }, - { 0x45,0xea,0x0e,0x98 }, { 0x5d,0xfe,0xc0,0xe1 }, + { 0x45,0xea,0x0e,0x98 }, { 0x5d,0xfe,0xc0,0xe1 }, { 0xc3,0x2f,0x75,0x02 }, { 0x81,0x4c,0xf0,0x12 }, - { 0x8d,0x46,0x97,0xa3 }, { 0x6b,0xd3,0xf9,0xc6 }, + { 0x8d,0x46,0x97,0xa3 }, { 0x6b,0xd3,0xf9,0xc6 }, { 0x03,0x8f,0x5f,0xe7 }, { 0x15,0x92,0x9c,0x95 }, - { 0xbf,0x6d,0x7a,0xeb }, { 0x95,0x52,0x59,0xda }, + { 0xbf,0x6d,0x7a,0xeb }, { 0x95,0x52,0x59,0xda }, { 0xd4,0xbe,0x83,0x2d }, { 0x58,0x74,0x21,0xd3 }, - { 0x49,0xe0,0x69,0x29 }, { 0x8e,0xc9,0xc8,0x44 }, + { 0x49,0xe0,0x69,0x29 }, { 0x8e,0xc9,0xc8,0x44 }, { 0x75,0xc2,0x89,0x6a }, { 0xf4,0x8e,0x79,0x78 }, - { 0x99,0x58,0x3e,0x6b }, { 0x27,0xb9,0x71,0xdd }, + { 0x99,0x58,0x3e,0x6b }, { 0x27,0xb9,0x71,0xdd }, { 0xbe,0xe1,0x4f,0xb6 }, { 0xf0,0x88,0xad,0x17 }, - { 0xc9,0x20,0xac,0x66 }, { 0x7d,0xce,0x3a,0xb4 }, + { 0xc9,0x20,0xac,0x66 }, { 0x7d,0xce,0x3a,0xb4 }, { 0x63,0xdf,0x4a,0x18 }, { 0xe5,0x1a,0x31,0x82 }, - { 0x97,0x51,0x33,0x60 }, { 0x62,0x53,0x7f,0x45 }, - { 0xb1,0x64,0x77,0xe0 }, { 0xbb,0x6b,0xae,0x84 }, - { 0xfe,0x81,0xa0,0x1c }, { 0xf9,0x08,0x2b,0x94 }, - { 0x70,0x48,0x68,0x58 }, { 0x8f,0x45,0xfd,0x19 }, - { 0x94,0xde,0x6c,0x87 }, { 0x52,0x7b,0xf8,0xb7 }, + { 0x97,0x51,0x33,0x60 }, { 0x62,0x53,0x7f,0x45 }, + { 0xb1,0x64,0x77,0xe0 }, { 0xbb,0x6b,0xae,0x84 }, + { 0xfe,0x81,0xa0,0x1c }, { 0xf9,0x08,0x2b,0x94 }, + { 0x70,0x48,0x68,0x58 }, { 0x8f,0x45,0xfd,0x19 }, + { 0x94,0xde,0x6c,0x87 }, { 0x52,0x7b,0xf8,0xb7 }, { 0xab,0x73,0xd3,0x23 }, { 0x72,0x4b,0x02,0xe2 }, - { 0xe3,0x1f,0x8f,0x57 }, { 0x66,0x55,0xab,0x2a }, + { 0xe3,0x1f,0x8f,0x57 }, { 0x66,0x55,0xab,0x2a }, { 0xb2,0xeb,0x28,0x07 }, { 0x2f,0xb5,0xc2,0x03 }, - { 0x86,0xc5,0x7b,0x9a }, { 0xd3,0x37,0x08,0xa5 }, + { 0x86,0xc5,0x7b,0x9a }, { 0xd3,0x37,0x08,0xa5 }, { 0x30,0x28,0x87,0xf2 }, { 0x23,0xbf,0xa5,0xb2 }, - { 0x02,0x03,0x6a,0xba }, { 0xed,0x16,0x82,0x5c }, + { 0x02,0x03,0x6a,0xba }, { 0xed,0x16,0x82,0x5c }, { 0x8a,0xcf,0x1c,0x2b }, { 0xa7,0x79,0xb4,0x92 }, - { 0xf3,0x07,0xf2,0xf0 }, { 0x4e,0x69,0xe2,0xa1 }, + { 0xf3,0x07,0xf2,0xf0 }, { 0x4e,0x69,0xe2,0xa1 }, { 0x65,0xda,0xf4,0xcd }, { 0x06,0x05,0xbe,0xd5 }, - { 0xd1,0x34,0x62,0x1f }, { 0xc4,0xa6,0xfe,0x8a }, + { 0xd1,0x34,0x62,0x1f }, { 0xc4,0xa6,0xfe,0x8a }, { 0x34,0x2e,0x53,0x9d }, { 0xa2,0xf3,0x55,0xa0 }, - { 0x05,0x8a,0xe1,0x32 }, { 0xa4,0xf6,0xeb,0x75 }, + { 0x05,0x8a,0xe1,0x32 }, { 0xa4,0xf6,0xeb,0x75 }, { 0x0b,0x83,0xec,0x39 }, { 0x40,0x60,0xef,0xaa }, - { 0x5e,0x71,0x9f,0x06 }, { 0xbd,0x6e,0x10,0x51 }, - { 0x3e,0x21,0x8a,0xf9 }, { 0x96,0xdd,0x06,0x3d }, - { 0xdd,0x3e,0x05,0xae }, { 0x4d,0xe6,0xbd,0x46 }, - { 0x91,0x54,0x8d,0xb5 }, { 0x71,0xc4,0x5d,0x05 }, - { 0x04,0x06,0xd4,0x6f }, { 0x60,0x50,0x15,0xff }, + { 0x5e,0x71,0x9f,0x06 }, { 0xbd,0x6e,0x10,0x51 }, + { 0x3e,0x21,0x8a,0xf9 }, { 0x96,0xdd,0x06,0x3d }, + { 0xdd,0x3e,0x05,0xae }, { 0x4d,0xe6,0xbd,0x46 }, + { 0x91,0x54,0x8d,0xb5 }, { 0x71,0xc4,0x5d,0x05 }, + { 0x04,0x06,0xd4,0x6f }, { 0x60,0x50,0x15,0xff }, { 0x19,0x98,0xfb,0x24 }, { 0xd6,0xbd,0xe9,0x97 }, - { 0x89,0x40,0x43,0xcc }, { 0x67,0xd9,0x9e,0x77 }, + { 0x89,0x40,0x43,0xcc }, { 0x67,0xd9,0x9e,0x77 }, { 0xb0,0xe8,0x42,0xbd }, { 0x07,0x89,0x8b,0x88 }, - { 0xe7,0x19,0x5b,0x38 }, { 0x79,0xc8,0xee,0xdb }, + { 0xe7,0x19,0x5b,0x38 }, { 0x79,0xc8,0xee,0xdb }, { 0xa1,0x7c,0x0a,0x47 }, { 0x7c,0x42,0x0f,0xe9 }, - { 0xf8,0x84,0x1e,0xc9 }, { 0x00,0x00,0x00,0x00 }, + { 0xf8,0x84,0x1e,0xc9 }, { 0x00,0x00,0x00,0x00 }, { 0x09,0x80,0x86,0x83 }, { 0x32,0x2b,0xed,0x48 }, - { 0x1e,0x11,0x70,0xac }, { 0x6c,0x5a,0x72,0x4e }, + { 0x1e,0x11,0x70,0xac }, { 0x6c,0x5a,0x72,0x4e }, { 0xfd,0x0e,0xff,0xfb }, { 0x0f,0x85,0x38,0x56 }, - { 0x3d,0xae,0xd5,0x1e }, { 0x36,0x2d,0x39,0x27 }, + { 0x3d,0xae,0xd5,0x1e }, { 0x36,0x2d,0x39,0x27 }, { 0x0a,0x0f,0xd9,0x64 }, { 0x68,0x5c,0xa6,0x21 }, - { 0x9b,0x5b,0x54,0xd1 }, { 0x24,0x36,0x2e,0x3a }, + { 0x9b,0x5b,0x54,0xd1 }, { 0x24,0x36,0x2e,0x3a }, { 0x0c,0x0a,0x67,0xb1 }, { 0x93,0x57,0xe7,0x0f }, - { 0xb4,0xee,0x96,0xd2 }, { 0x1b,0x9b,0x91,0x9e }, + { 0xb4,0xee,0x96,0xd2 }, { 0x1b,0x9b,0x91,0x9e }, { 0x80,0xc0,0xc5,0x4f }, { 0x61,0xdc,0x20,0xa2 }, - { 0x5a,0x77,0x4b,0x69 }, { 0x1c,0x12,0x1a,0x16 }, - { 0xe2,0x93,0xba,0x0a }, { 0xc0,0xa0,0x2a,0xe5 }, - { 0x3c,0x22,0xe0,0x43 }, { 0x12,0x1b,0x17,0x1d }, - { 0x0e,0x09,0x0d,0x0b }, { 0xf2,0x8b,0xc7,0xad }, - { 0x2d,0xb6,0xa8,0xb9 }, { 0x14,0x1e,0xa9,0xc8 }, - { 0x57,0xf1,0x19,0x85 }, { 0xaf,0x75,0x07,0x4c }, - { 0xee,0x99,0xdd,0xbb }, { 0xa3,0x7f,0x60,0xfd }, + { 0x5a,0x77,0x4b,0x69 }, { 0x1c,0x12,0x1a,0x16 }, + { 0xe2,0x93,0xba,0x0a }, { 0xc0,0xa0,0x2a,0xe5 }, + { 0x3c,0x22,0xe0,0x43 }, { 0x12,0x1b,0x17,0x1d }, + { 0x0e,0x09,0x0d,0x0b }, { 0xf2,0x8b,0xc7,0xad }, + { 0x2d,0xb6,0xa8,0xb9 }, { 0x14,0x1e,0xa9,0xc8 }, + { 0x57,0xf1,0x19,0x85 }, { 0xaf,0x75,0x07,0x4c }, + { 0xee,0x99,0xdd,0xbb }, { 0xa3,0x7f,0x60,0xfd }, { 0xf7,0x01,0x26,0x9f }, { 0x5c,0x72,0xf5,0xbc }, - { 0x44,0x66,0x3b,0xc5 }, { 0x5b,0xfb,0x7e,0x34 }, + { 0x44,0x66,0x3b,0xc5 }, { 0x5b,0xfb,0x7e,0x34 }, { 0x8b,0x43,0x29,0x76 }, { 0xcb,0x23,0xc6,0xdc }, - { 0xb6,0xed,0xfc,0x68 }, { 0xb8,0xe4,0xf1,0x63 }, + { 0xb6,0xed,0xfc,0x68 }, { 0xb8,0xe4,0xf1,0x63 }, { 0xd7,0x31,0xdc,0xca }, { 0x42,0x63,0x85,0x10 }, - { 0x13,0x97,0x22,0x40 }, { 0x84,0xc6,0x11,0x20 }, - { 0x85,0x4a,0x24,0x7d }, { 0xd2,0xbb,0x3d,0xf8 }, - { 0xae,0xf9,0x32,0x11 }, { 0xc7,0x29,0xa1,0x6d }, + { 0x13,0x97,0x22,0x40 }, { 0x84,0xc6,0x11,0x20 }, + { 0x85,0x4a,0x24,0x7d }, { 0xd2,0xbb,0x3d,0xf8 }, + { 0xae,0xf9,0x32,0x11 }, { 0xc7,0x29,0xa1,0x6d }, { 0x1d,0x9e,0x2f,0x4b }, { 0xdc,0xb2,0x30,0xf3 }, - { 0x0d,0x86,0x52,0xec }, { 0x77,0xc1,0xe3,0xd0 }, + { 0x0d,0x86,0x52,0xec }, { 0x77,0xc1,0xe3,0xd0 }, { 0x2b,0xb3,0x16,0x6c }, { 0xa9,0x70,0xb9,0x99 }, - { 0x11,0x94,0x48,0xfa }, { 0x47,0xe9,0x64,0x22 }, + { 0x11,0x94,0x48,0xfa }, { 0x47,0xe9,0x64,0x22 }, { 0xa8,0xfc,0x8c,0xc4 }, { 0xa0,0xf0,0x3f,0x1a }, - { 0x56,0x7d,0x2c,0xd8 }, { 0x22,0x33,0x90,0xef }, - { 0x87,0x49,0x4e,0xc7 }, { 0xd9,0x38,0xd1,0xc1 }, - { 0x8c,0xca,0xa2,0xfe }, { 0x98,0xd4,0x0b,0x36 }, - { 0xa6,0xf5,0x81,0xcf }, { 0xa5,0x7a,0xde,0x28 }, - { 0xda,0xb7,0x8e,0x26 }, { 0x3f,0xad,0xbf,0xa4 }, - { 0x2c,0x3a,0x9d,0xe4 }, { 0x50,0x78,0x92,0x0d }, - { 0x6a,0x5f,0xcc,0x9b }, { 0x54,0x7e,0x46,0x62 }, - { 0xf6,0x8d,0x13,0xc2 }, { 0x90,0xd8,0xb8,0xe8 }, - { 0x2e,0x39,0xf7,0x5e }, { 0x82,0xc3,0xaf,0xf5 }, + { 0x56,0x7d,0x2c,0xd8 }, { 0x22,0x33,0x90,0xef }, + { 0x87,0x49,0x4e,0xc7 }, { 0xd9,0x38,0xd1,0xc1 }, + { 0x8c,0xca,0xa2,0xfe }, { 0x98,0xd4,0x0b,0x36 }, + { 0xa6,0xf5,0x81,0xcf }, { 0xa5,0x7a,0xde,0x28 }, + { 0xda,0xb7,0x8e,0x26 }, { 0x3f,0xad,0xbf,0xa4 }, + { 0x2c,0x3a,0x9d,0xe4 }, { 0x50,0x78,0x92,0x0d }, + { 0x6a,0x5f,0xcc,0x9b }, { 0x54,0x7e,0x46,0x62 }, + { 0xf6,0x8d,0x13,0xc2 }, { 0x90,0xd8,0xb8,0xe8 }, + { 0x2e,0x39,0xf7,0x5e }, { 0x82,0xc3,0xaf,0xf5 }, { 0x9f,0x5d,0x80,0xbe }, { 0x69,0xd0,0x93,0x7c }, - { 0x6f,0xd5,0x2d,0xa9 }, { 0xcf,0x25,0x12,0xb3 }, + { 0x6f,0xd5,0x2d,0xa9 }, { 0xcf,0x25,0x12,0xb3 }, { 0xc8,0xac,0x99,0x3b }, { 0x10,0x18,0x7d,0xa7 }, - { 0xe8,0x9c,0x63,0x6e }, { 0xdb,0x3b,0xbb,0x7b }, + { 0xe8,0x9c,0x63,0x6e }, { 0xdb,0x3b,0xbb,0x7b }, { 0xcd,0x26,0x78,0x09 }, { 0x6e,0x59,0x18,0xf4 }, - { 0xec,0x9a,0xb7,0x01 }, { 0x83,0x4f,0x9a,0xa8 }, - { 0xe6,0x95,0x6e,0x65 }, { 0xaa,0xff,0xe6,0x7e }, - { 0x21,0xbc,0xcf,0x08 }, { 0xef,0x15,0xe8,0xe6 }, - { 0xba,0xe7,0x9b,0xd9 }, { 0x4a,0x6f,0x36,0xce }, - { 0xea,0x9f,0x09,0xd4 }, { 0x29,0xb0,0x7c,0xd6 }, - { 0x31,0xa4,0xb2,0xaf }, { 0x2a,0x3f,0x23,0x31 }, - { 0xc6,0xa5,0x94,0x30 }, { 0x35,0xa2,0x66,0xc0 }, - { 0x74,0x4e,0xbc,0x37 }, { 0xfc,0x82,0xca,0xa6 }, - { 0xe0,0x90,0xd0,0xb0 }, { 0x33,0xa7,0xd8,0x15 }, + { 0xec,0x9a,0xb7,0x01 }, { 0x83,0x4f,0x9a,0xa8 }, + { 0xe6,0x95,0x6e,0x65 }, { 0xaa,0xff,0xe6,0x7e }, + { 0x21,0xbc,0xcf,0x08 }, { 0xef,0x15,0xe8,0xe6 }, + { 0xba,0xe7,0x9b,0xd9 }, { 0x4a,0x6f,0x36,0xce }, + { 0xea,0x9f,0x09,0xd4 }, { 0x29,0xb0,0x7c,0xd6 }, + { 0x31,0xa4,0xb2,0xaf }, { 0x2a,0x3f,0x23,0x31 }, + { 0xc6,0xa5,0x94,0x30 }, { 0x35,0xa2,0x66,0xc0 }, + { 0x74,0x4e,0xbc,0x37 }, { 0xfc,0x82,0xca,0xa6 }, + { 0xe0,0x90,0xd0,0xb0 }, { 0x33,0xa7,0xd8,0x15 }, { 0xf1,0x04,0x98,0x4a }, { 0x41,0xec,0xda,0xf7 }, - { 0x7f,0xcd,0x50,0x0e }, { 0x17,0x91,0xf6,0x2f }, + { 0x7f,0xcd,0x50,0x0e }, { 0x17,0x91,0xf6,0x2f }, { 0x76,0x4d,0xd6,0x8d }, { 0x43,0xef,0xb0,0x4d }, - { 0xcc,0xaa,0x4d,0x54 }, { 0xe4,0x96,0x04,0xdf }, + { 0xcc,0xaa,0x4d,0x54 }, { 0xe4,0x96,0x04,0xdf }, { 0x9e,0xd1,0xb5,0xe3 }, { 0x4c,0x6a,0x88,0x1b }, - { 0xc1,0x2c,0x1f,0xb8 }, { 0x46,0x65,0x51,0x7f }, + { 0xc1,0x2c,0x1f,0xb8 }, { 0x46,0x65,0x51,0x7f }, { 0x9d,0x5e,0xea,0x04 }, { 0x01,0x8c,0x35,0x5d }, - { 0xfa,0x87,0x74,0x73 }, { 0xfb,0x0b,0x41,0x2e }, + { 0xfa,0x87,0x74,0x73 }, { 0xfb,0x0b,0x41,0x2e }, { 0xb3,0x67,0x1d,0x5a }, { 0x92,0xdb,0xd2,0x52 }, - { 0xe9,0x10,0x56,0x33 }, { 0x6d,0xd6,0x47,0x13 }, + { 0xe9,0x10,0x56,0x33 }, { 0x6d,0xd6,0x47,0x13 }, { 0x9a,0xd7,0x61,0x8c }, { 0x37,0xa1,0x0c,0x7a }, - { 0x59,0xf8,0x14,0x8e }, { 0xeb,0x13,0x3c,0x89 }, + { 0x59,0xf8,0x14,0x8e }, { 0xeb,0x13,0x3c,0x89 }, { 0xce,0xa9,0x27,0xee }, { 0xb7,0x61,0xc9,0x35 }, - { 0xe1,0x1c,0xe5,0xed }, { 0x7a,0x47,0xb1,0x3c }, - { 0x9c,0xd2,0xdf,0x59 }, { 0x55,0xf2,0x73,0x3f }, - { 0x18,0x14,0xce,0x79 }, { 0x73,0xc7,0x37,0xbf }, + { 0xe1,0x1c,0xe5,0xed }, { 0x7a,0x47,0xb1,0x3c }, + { 0x9c,0xd2,0xdf,0x59 }, { 0x55,0xf2,0x73,0x3f }, + { 0x18,0x14,0xce,0x79 }, { 0x73,0xc7,0x37,0xbf }, { 0x53,0xf7,0xcd,0xea }, { 0x5f,0xfd,0xaa,0x5b }, - { 0xdf,0x3d,0x6f,0x14 }, { 0x78,0x44,0xdb,0x86 }, - { 0xca,0xaf,0xf3,0x81 }, { 0xb9,0x68,0xc4,0x3e }, - { 0x38,0x24,0x34,0x2c }, { 0xc2,0xa3,0x40,0x5f }, - { 0x16,0x1d,0xc3,0x72 }, { 0xbc,0xe2,0x25,0x0c }, - { 0x28,0x3c,0x49,0x8b }, { 0xff,0x0d,0x95,0x41 }, - { 0x39,0xa8,0x01,0x71 }, { 0x08,0x0c,0xb3,0xde }, - { 0xd8,0xb4,0xe4,0x9c }, { 0x64,0x56,0xc1,0x90 }, + { 0xdf,0x3d,0x6f,0x14 }, { 0x78,0x44,0xdb,0x86 }, + { 0xca,0xaf,0xf3,0x81 }, { 0xb9,0x68,0xc4,0x3e }, + { 0x38,0x24,0x34,0x2c }, { 0xc2,0xa3,0x40,0x5f }, + { 0x16,0x1d,0xc3,0x72 }, { 0xbc,0xe2,0x25,0x0c }, + { 0x28,0x3c,0x49,0x8b }, { 0xff,0x0d,0x95,0x41 }, + { 0x39,0xa8,0x01,0x71 }, { 0x08,0x0c,0xb3,0xde }, + { 0xd8,0xb4,0xe4,0x9c }, { 0x64,0x56,0xc1,0x90 }, { 0x7b,0xcb,0x84,0x61 }, { 0xd5,0x32,0xb6,0x70 }, { 0x48,0x6c,0x5c,0x74 }, { 0xd0,0xb8,0x57,0x42 } }; -static const unsigned char T6[256][4] = +static const unsigned char T6[256][4] = { - { 0x50,0x51,0xf4,0xa7 }, { 0x53,0x7e,0x41,0x65 }, - { 0xc3,0x1a,0x17,0xa4 }, { 0x96,0x3a,0x27,0x5e }, + { 0x50,0x51,0xf4,0xa7 }, { 0x53,0x7e,0x41,0x65 }, + { 0xc3,0x1a,0x17,0xa4 }, { 0x96,0x3a,0x27,0x5e }, { 0xcb,0x3b,0xab,0x6b }, { 0xf1,0x1f,0x9d,0x45 }, - { 0xab,0xac,0xfa,0x58 }, { 0x93,0x4b,0xe3,0x03 }, + { 0xab,0xac,0xfa,0x58 }, { 0x93,0x4b,0xe3,0x03 }, { 0x55,0x20,0x30,0xfa }, { 0xf6,0xad,0x76,0x6d }, - { 0x91,0x88,0xcc,0x76 }, { 0x25,0xf5,0x02,0x4c }, + { 0x91,0x88,0xcc,0x76 }, { 0x25,0xf5,0x02,0x4c }, { 0xfc,0x4f,0xe5,0xd7 }, { 0xd7,0xc5,0x2a,0xcb }, - { 0x80,0x26,0x35,0x44 }, { 0x8f,0xb5,0x62,0xa3 }, - { 0x49,0xde,0xb1,0x5a }, { 0x67,0x25,0xba,0x1b }, - { 0x98,0x45,0xea,0x0e }, { 0xe1,0x5d,0xfe,0xc0 }, + { 0x80,0x26,0x35,0x44 }, { 0x8f,0xb5,0x62,0xa3 }, + { 0x49,0xde,0xb1,0x5a }, { 0x67,0x25,0xba,0x1b }, + { 0x98,0x45,0xea,0x0e }, { 0xe1,0x5d,0xfe,0xc0 }, { 0x02,0xc3,0x2f,0x75 }, { 0x12,0x81,0x4c,0xf0 }, - { 0xa3,0x8d,0x46,0x97 }, { 0xc6,0x6b,0xd3,0xf9 }, + { 0xa3,0x8d,0x46,0x97 }, { 0xc6,0x6b,0xd3,0xf9 }, { 0xe7,0x03,0x8f,0x5f }, { 0x95,0x15,0x92,0x9c }, - { 0xeb,0xbf,0x6d,0x7a }, { 0xda,0x95,0x52,0x59 }, + { 0xeb,0xbf,0x6d,0x7a }, { 0xda,0x95,0x52,0x59 }, { 0x2d,0xd4,0xbe,0x83 }, { 0xd3,0x58,0x74,0x21 }, - { 0x29,0x49,0xe0,0x69 }, { 0x44,0x8e,0xc9,0xc8 }, + { 0x29,0x49,0xe0,0x69 }, { 0x44,0x8e,0xc9,0xc8 }, { 0x6a,0x75,0xc2,0x89 }, { 0x78,0xf4,0x8e,0x79 }, - { 0x6b,0x99,0x58,0x3e }, { 0xdd,0x27,0xb9,0x71 }, + { 0x6b,0x99,0x58,0x3e }, { 0xdd,0x27,0xb9,0x71 }, { 0xb6,0xbe,0xe1,0x4f }, { 0x17,0xf0,0x88,0xad }, - { 0x66,0xc9,0x20,0xac }, { 0xb4,0x7d,0xce,0x3a }, + { 0x66,0xc9,0x20,0xac }, { 0xb4,0x7d,0xce,0x3a }, { 0x18,0x63,0xdf,0x4a }, { 0x82,0xe5,0x1a,0x31 }, - { 0x60,0x97,0x51,0x33 }, { 0x45,0x62,0x53,0x7f }, + { 0x60,0x97,0x51,0x33 }, { 0x45,0x62,0x53,0x7f }, { 0xe0,0xb1,0x64,0x77 }, { 0x84,0xbb,0x6b,0xae }, - { 0x1c,0xfe,0x81,0xa0 }, { 0x94,0xf9,0x08,0x2b }, + { 0x1c,0xfe,0x81,0xa0 }, { 0x94,0xf9,0x08,0x2b }, { 0x58,0x70,0x48,0x68 }, { 0x19,0x8f,0x45,0xfd }, - { 0x87,0x94,0xde,0x6c }, { 0xb7,0x52,0x7b,0xf8 }, + { 0x87,0x94,0xde,0x6c }, { 0xb7,0x52,0x7b,0xf8 }, { 0x23,0xab,0x73,0xd3 }, { 0xe2,0x72,0x4b,0x02 }, - { 0x57,0xe3,0x1f,0x8f }, { 0x2a,0x66,0x55,0xab }, + { 0x57,0xe3,0x1f,0x8f }, { 0x2a,0x66,0x55,0xab }, { 0x07,0xb2,0xeb,0x28 }, { 0x03,0x2f,0xb5,0xc2 }, - { 0x9a,0x86,0xc5,0x7b }, { 0xa5,0xd3,0x37,0x08 }, + { 0x9a,0x86,0xc5,0x7b }, { 0xa5,0xd3,0x37,0x08 }, { 0xf2,0x30,0x28,0x87 }, { 0xb2,0x23,0xbf,0xa5 }, - { 0xba,0x02,0x03,0x6a }, { 0x5c,0xed,0x16,0x82 }, + { 0xba,0x02,0x03,0x6a }, { 0x5c,0xed,0x16,0x82 }, { 0x2b,0x8a,0xcf,0x1c }, { 0x92,0xa7,0x79,0xb4 }, - { 0xf0,0xf3,0x07,0xf2 }, { 0xa1,0x4e,0x69,0xe2 }, + { 0xf0,0xf3,0x07,0xf2 }, { 0xa1,0x4e,0x69,0xe2 }, { 0xcd,0x65,0xda,0xf4 }, { 0xd5,0x06,0x05,0xbe }, - { 0x1f,0xd1,0x34,0x62 }, { 0x8a,0xc4,0xa6,0xfe }, + { 0x1f,0xd1,0x34,0x62 }, { 0x8a,0xc4,0xa6,0xfe }, { 0x9d,0x34,0x2e,0x53 }, { 0xa0,0xa2,0xf3,0x55 }, - { 0x32,0x05,0x8a,0xe1 }, { 0x75,0xa4,0xf6,0xeb }, + { 0x32,0x05,0x8a,0xe1 }, { 0x75,0xa4,0xf6,0xeb }, { 0x39,0x0b,0x83,0xec }, { 0xaa,0x40,0x60,0xef }, - { 0x06,0x5e,0x71,0x9f }, { 0x51,0xbd,0x6e,0x10 }, + { 0x06,0x5e,0x71,0x9f }, { 0x51,0xbd,0x6e,0x10 }, { 0xf9,0x3e,0x21,0x8a }, { 0x3d,0x96,0xdd,0x06 }, - { 0xae,0xdd,0x3e,0x05 }, { 0x46,0x4d,0xe6,0xbd }, + { 0xae,0xdd,0x3e,0x05 }, { 0x46,0x4d,0xe6,0xbd }, { 0xb5,0x91,0x54,0x8d }, { 0x05,0x71,0xc4,0x5d }, - { 0x6f,0x04,0x06,0xd4 }, { 0xff,0x60,0x50,0x15 }, + { 0x6f,0x04,0x06,0xd4 }, { 0xff,0x60,0x50,0x15 }, { 0x24,0x19,0x98,0xfb }, { 0x97,0xd6,0xbd,0xe9 }, - { 0xcc,0x89,0x40,0x43 }, { 0x77,0x67,0xd9,0x9e }, + { 0xcc,0x89,0x40,0x43 }, { 0x77,0x67,0xd9,0x9e }, { 0xbd,0xb0,0xe8,0x42 }, { 0x88,0x07,0x89,0x8b }, - { 0x38,0xe7,0x19,0x5b }, { 0xdb,0x79,0xc8,0xee }, + { 0x38,0xe7,0x19,0x5b }, { 0xdb,0x79,0xc8,0xee }, { 0x47,0xa1,0x7c,0x0a }, { 0xe9,0x7c,0x42,0x0f }, - { 0xc9,0xf8,0x84,0x1e }, { 0x00,0x00,0x00,0x00 }, + { 0xc9,0xf8,0x84,0x1e }, { 0x00,0x00,0x00,0x00 }, { 0x83,0x09,0x80,0x86 }, { 0x48,0x32,0x2b,0xed }, - { 0xac,0x1e,0x11,0x70 }, { 0x4e,0x6c,0x5a,0x72 }, + { 0xac,0x1e,0x11,0x70 }, { 0x4e,0x6c,0x5a,0x72 }, { 0xfb,0xfd,0x0e,0xff }, { 0x56,0x0f,0x85,0x38 }, - { 0x1e,0x3d,0xae,0xd5 }, { 0x27,0x36,0x2d,0x39 }, + { 0x1e,0x3d,0xae,0xd5 }, { 0x27,0x36,0x2d,0x39 }, { 0x64,0x0a,0x0f,0xd9 }, { 0x21,0x68,0x5c,0xa6 }, - { 0xd1,0x9b,0x5b,0x54 }, { 0x3a,0x24,0x36,0x2e }, + { 0xd1,0x9b,0x5b,0x54 }, { 0x3a,0x24,0x36,0x2e }, { 0xb1,0x0c,0x0a,0x67 }, { 0x0f,0x93,0x57,0xe7 }, - { 0xd2,0xb4,0xee,0x96 }, { 0x9e,0x1b,0x9b,0x91 }, - { 0x4f,0x80,0xc0,0xc5 }, { 0xa2,0x61,0xdc,0x20 }, - { 0x69,0x5a,0x77,0x4b }, { 0x16,0x1c,0x12,0x1a }, + { 0xd2,0xb4,0xee,0x96 }, { 0x9e,0x1b,0x9b,0x91 }, + { 0x4f,0x80,0xc0,0xc5 }, { 0xa2,0x61,0xdc,0x20 }, + { 0x69,0x5a,0x77,0x4b }, { 0x16,0x1c,0x12,0x1a }, { 0x0a,0xe2,0x93,0xba }, { 0xe5,0xc0,0xa0,0x2a }, - { 0x43,0x3c,0x22,0xe0 }, { 0x1d,0x12,0x1b,0x17 }, + { 0x43,0x3c,0x22,0xe0 }, { 0x1d,0x12,0x1b,0x17 }, { 0x0b,0x0e,0x09,0x0d }, { 0xad,0xf2,0x8b,0xc7 }, - { 0xb9,0x2d,0xb6,0xa8 }, { 0xc8,0x14,0x1e,0xa9 }, + { 0xb9,0x2d,0xb6,0xa8 }, { 0xc8,0x14,0x1e,0xa9 }, { 0x85,0x57,0xf1,0x19 }, { 0x4c,0xaf,0x75,0x07 }, - { 0xbb,0xee,0x99,0xdd }, { 0xfd,0xa3,0x7f,0x60 }, + { 0xbb,0xee,0x99,0xdd }, { 0xfd,0xa3,0x7f,0x60 }, { 0x9f,0xf7,0x01,0x26 }, { 0xbc,0x5c,0x72,0xf5 }, - { 0xc5,0x44,0x66,0x3b }, { 0x34,0x5b,0xfb,0x7e }, + { 0xc5,0x44,0x66,0x3b }, { 0x34,0x5b,0xfb,0x7e }, { 0x76,0x8b,0x43,0x29 }, { 0xdc,0xcb,0x23,0xc6 }, - { 0x68,0xb6,0xed,0xfc }, { 0x63,0xb8,0xe4,0xf1 }, + { 0x68,0xb6,0xed,0xfc }, { 0x63,0xb8,0xe4,0xf1 }, { 0xca,0xd7,0x31,0xdc }, { 0x10,0x42,0x63,0x85 }, - { 0x40,0x13,0x97,0x22 }, { 0x20,0x84,0xc6,0x11 }, + { 0x40,0x13,0x97,0x22 }, { 0x20,0x84,0xc6,0x11 }, { 0x7d,0x85,0x4a,0x24 }, { 0xf8,0xd2,0xbb,0x3d }, - { 0x11,0xae,0xf9,0x32 }, { 0x6d,0xc7,0x29,0xa1 }, + { 0x11,0xae,0xf9,0x32 }, { 0x6d,0xc7,0x29,0xa1 }, { 0x4b,0x1d,0x9e,0x2f }, { 0xf3,0xdc,0xb2,0x30 }, - { 0xec,0x0d,0x86,0x52 }, { 0xd0,0x77,0xc1,0xe3 }, - { 0x6c,0x2b,0xb3,0x16 }, { 0x99,0xa9,0x70,0xb9 }, - { 0xfa,0x11,0x94,0x48 }, { 0x22,0x47,0xe9,0x64 }, - { 0xc4,0xa8,0xfc,0x8c }, { 0x1a,0xa0,0xf0,0x3f }, - { 0xd8,0x56,0x7d,0x2c }, { 0xef,0x22,0x33,0x90 }, + { 0xec,0x0d,0x86,0x52 }, { 0xd0,0x77,0xc1,0xe3 }, + { 0x6c,0x2b,0xb3,0x16 }, { 0x99,0xa9,0x70,0xb9 }, + { 0xfa,0x11,0x94,0x48 }, { 0x22,0x47,0xe9,0x64 }, + { 0xc4,0xa8,0xfc,0x8c }, { 0x1a,0xa0,0xf0,0x3f }, + { 0xd8,0x56,0x7d,0x2c }, { 0xef,0x22,0x33,0x90 }, { 0xc7,0x87,0x49,0x4e }, { 0xc1,0xd9,0x38,0xd1 }, - { 0xfe,0x8c,0xca,0xa2 }, { 0x36,0x98,0xd4,0x0b }, - { 0xcf,0xa6,0xf5,0x81 }, { 0x28,0xa5,0x7a,0xde }, - { 0x26,0xda,0xb7,0x8e }, { 0xa4,0x3f,0xad,0xbf }, - { 0xe4,0x2c,0x3a,0x9d }, { 0x0d,0x50,0x78,0x92 }, - { 0x9b,0x6a,0x5f,0xcc }, { 0x62,0x54,0x7e,0x46 }, - { 0xc2,0xf6,0x8d,0x13 }, { 0xe8,0x90,0xd8,0xb8 }, - { 0x5e,0x2e,0x39,0xf7 }, { 0xf5,0x82,0xc3,0xaf }, + { 0xfe,0x8c,0xca,0xa2 }, { 0x36,0x98,0xd4,0x0b }, + { 0xcf,0xa6,0xf5,0x81 }, { 0x28,0xa5,0x7a,0xde }, + { 0x26,0xda,0xb7,0x8e }, { 0xa4,0x3f,0xad,0xbf }, + { 0xe4,0x2c,0x3a,0x9d }, { 0x0d,0x50,0x78,0x92 }, + { 0x9b,0x6a,0x5f,0xcc }, { 0x62,0x54,0x7e,0x46 }, + { 0xc2,0xf6,0x8d,0x13 }, { 0xe8,0x90,0xd8,0xb8 }, + { 0x5e,0x2e,0x39,0xf7 }, { 0xf5,0x82,0xc3,0xaf }, { 0xbe,0x9f,0x5d,0x80 }, { 0x7c,0x69,0xd0,0x93 }, - { 0xa9,0x6f,0xd5,0x2d }, { 0xb3,0xcf,0x25,0x12 }, - { 0x3b,0xc8,0xac,0x99 }, { 0xa7,0x10,0x18,0x7d }, - { 0x6e,0xe8,0x9c,0x63 }, { 0x7b,0xdb,0x3b,0xbb }, + { 0xa9,0x6f,0xd5,0x2d }, { 0xb3,0xcf,0x25,0x12 }, + { 0x3b,0xc8,0xac,0x99 }, { 0xa7,0x10,0x18,0x7d }, + { 0x6e,0xe8,0x9c,0x63 }, { 0x7b,0xdb,0x3b,0xbb }, { 0x09,0xcd,0x26,0x78 }, { 0xf4,0x6e,0x59,0x18 }, - { 0x01,0xec,0x9a,0xb7 }, { 0xa8,0x83,0x4f,0x9a }, - { 0x65,0xe6,0x95,0x6e }, { 0x7e,0xaa,0xff,0xe6 }, - { 0x08,0x21,0xbc,0xcf }, { 0xe6,0xef,0x15,0xe8 }, + { 0x01,0xec,0x9a,0xb7 }, { 0xa8,0x83,0x4f,0x9a }, + { 0x65,0xe6,0x95,0x6e }, { 0x7e,0xaa,0xff,0xe6 }, + { 0x08,0x21,0xbc,0xcf }, { 0xe6,0xef,0x15,0xe8 }, { 0xd9,0xba,0xe7,0x9b }, { 0xce,0x4a,0x6f,0x36 }, - { 0xd4,0xea,0x9f,0x09 }, { 0xd6,0x29,0xb0,0x7c }, + { 0xd4,0xea,0x9f,0x09 }, { 0xd6,0x29,0xb0,0x7c }, { 0xaf,0x31,0xa4,0xb2 }, { 0x31,0x2a,0x3f,0x23 }, - { 0x30,0xc6,0xa5,0x94 }, { 0xc0,0x35,0xa2,0x66 }, - { 0x37,0x74,0x4e,0xbc }, { 0xa6,0xfc,0x82,0xca }, - { 0xb0,0xe0,0x90,0xd0 }, { 0x15,0x33,0xa7,0xd8 }, + { 0x30,0xc6,0xa5,0x94 }, { 0xc0,0x35,0xa2,0x66 }, + { 0x37,0x74,0x4e,0xbc }, { 0xa6,0xfc,0x82,0xca }, + { 0xb0,0xe0,0x90,0xd0 }, { 0x15,0x33,0xa7,0xd8 }, { 0x4a,0xf1,0x04,0x98 }, { 0xf7,0x41,0xec,0xda }, - { 0x0e,0x7f,0xcd,0x50 }, { 0x2f,0x17,0x91,0xf6 }, + { 0x0e,0x7f,0xcd,0x50 }, { 0x2f,0x17,0x91,0xf6 }, { 0x8d,0x76,0x4d,0xd6 }, { 0x4d,0x43,0xef,0xb0 }, - { 0x54,0xcc,0xaa,0x4d }, { 0xdf,0xe4,0x96,0x04 }, + { 0x54,0xcc,0xaa,0x4d }, { 0xdf,0xe4,0x96,0x04 }, { 0xe3,0x9e,0xd1,0xb5 }, { 0x1b,0x4c,0x6a,0x88 }, - { 0xb8,0xc1,0x2c,0x1f }, { 0x7f,0x46,0x65,0x51 }, + { 0xb8,0xc1,0x2c,0x1f }, { 0x7f,0x46,0x65,0x51 }, { 0x04,0x9d,0x5e,0xea }, { 0x5d,0x01,0x8c,0x35 }, - { 0x73,0xfa,0x87,0x74 }, { 0x2e,0xfb,0x0b,0x41 }, + { 0x73,0xfa,0x87,0x74 }, { 0x2e,0xfb,0x0b,0x41 }, { 0x5a,0xb3,0x67,0x1d }, { 0x52,0x92,0xdb,0xd2 }, - { 0x33,0xe9,0x10,0x56 }, { 0x13,0x6d,0xd6,0x47 }, - { 0x8c,0x9a,0xd7,0x61 }, { 0x7a,0x37,0xa1,0x0c }, - { 0x8e,0x59,0xf8,0x14 }, { 0x89,0xeb,0x13,0x3c }, + { 0x33,0xe9,0x10,0x56 }, { 0x13,0x6d,0xd6,0x47 }, + { 0x8c,0x9a,0xd7,0x61 }, { 0x7a,0x37,0xa1,0x0c }, + { 0x8e,0x59,0xf8,0x14 }, { 0x89,0xeb,0x13,0x3c }, { 0xee,0xce,0xa9,0x27 }, { 0x35,0xb7,0x61,0xc9 }, - { 0xed,0xe1,0x1c,0xe5 }, { 0x3c,0x7a,0x47,0xb1 }, + { 0xed,0xe1,0x1c,0xe5 }, { 0x3c,0x7a,0x47,0xb1 }, { 0x59,0x9c,0xd2,0xdf }, { 0x3f,0x55,0xf2,0x73 }, - { 0x79,0x18,0x14,0xce }, { 0xbf,0x73,0xc7,0x37 }, + { 0x79,0x18,0x14,0xce }, { 0xbf,0x73,0xc7,0x37 }, { 0xea,0x53,0xf7,0xcd }, { 0x5b,0x5f,0xfd,0xaa }, - { 0x14,0xdf,0x3d,0x6f }, { 0x86,0x78,0x44,0xdb }, + { 0x14,0xdf,0x3d,0x6f }, { 0x86,0x78,0x44,0xdb }, { 0x81,0xca,0xaf,0xf3 }, { 0x3e,0xb9,0x68,0xc4 }, - { 0x2c,0x38,0x24,0x34 }, { 0x5f,0xc2,0xa3,0x40 }, + { 0x2c,0x38,0x24,0x34 }, { 0x5f,0xc2,0xa3,0x40 }, { 0x72,0x16,0x1d,0xc3 }, { 0x0c,0xbc,0xe2,0x25 }, - { 0x8b,0x28,0x3c,0x49 }, { 0x41,0xff,0x0d,0x95 }, + { 0x8b,0x28,0x3c,0x49 }, { 0x41,0xff,0x0d,0x95 }, { 0x71,0x39,0xa8,0x01 }, { 0xde,0x08,0x0c,0xb3 }, - { 0x9c,0xd8,0xb4,0xe4 }, { 0x90,0x64,0x56,0xc1 }, + { 0x9c,0xd8,0xb4,0xe4 }, { 0x90,0x64,0x56,0xc1 }, { 0x61,0x7b,0xcb,0x84 }, { 0x70,0xd5,0x32,0xb6 }, { 0x74,0x48,0x6c,0x5c }, { 0x42,0xd0,0xb8,0x57 } }; -static const unsigned char T7[256][4] = +static const unsigned char T7[256][4] = { { 0xa7,0x50,0x51,0xf4 }, { 0x65,0x53,0x7e,0x41 }, - { 0xa4,0xc3,0x1a,0x17 }, { 0x5e,0x96,0x3a,0x27 }, + { 0xa4,0xc3,0x1a,0x17 }, { 0x5e,0x96,0x3a,0x27 }, { 0x6b,0xcb,0x3b,0xab }, { 0x45,0xf1,0x1f,0x9d }, - { 0x58,0xab,0xac,0xfa }, { 0x03,0x93,0x4b,0xe3 }, + { 0x58,0xab,0xac,0xfa }, { 0x03,0x93,0x4b,0xe3 }, { 0xfa,0x55,0x20,0x30 }, { 0x6d,0xf6,0xad,0x76 }, - { 0x76,0x91,0x88,0xcc }, { 0x4c,0x25,0xf5,0x02 }, + { 0x76,0x91,0x88,0xcc }, { 0x4c,0x25,0xf5,0x02 }, { 0xd7,0xfc,0x4f,0xe5 }, { 0xcb,0xd7,0xc5,0x2a }, - { 0x44,0x80,0x26,0x35 }, { 0xa3,0x8f,0xb5,0x62 }, - { 0x5a,0x49,0xde,0xb1 }, { 0x1b,0x67,0x25,0xba }, - { 0x0e,0x98,0x45,0xea }, { 0xc0,0xe1,0x5d,0xfe }, + { 0x44,0x80,0x26,0x35 }, { 0xa3,0x8f,0xb5,0x62 }, + { 0x5a,0x49,0xde,0xb1 }, { 0x1b,0x67,0x25,0xba }, + { 0x0e,0x98,0x45,0xea }, { 0xc0,0xe1,0x5d,0xfe }, { 0x75,0x02,0xc3,0x2f }, { 0xf0,0x12,0x81,0x4c }, - { 0x97,0xa3,0x8d,0x46 }, { 0xf9,0xc6,0x6b,0xd3 }, + { 0x97,0xa3,0x8d,0x46 }, { 0xf9,0xc6,0x6b,0xd3 }, { 0x5f,0xe7,0x03,0x8f }, { 0x9c,0x95,0x15,0x92 }, - { 0x7a,0xeb,0xbf,0x6d }, { 0x59,0xda,0x95,0x52 }, + { 0x7a,0xeb,0xbf,0x6d }, { 0x59,0xda,0x95,0x52 }, { 0x83,0x2d,0xd4,0xbe }, { 0x21,0xd3,0x58,0x74 }, - { 0x69,0x29,0x49,0xe0 }, { 0xc8,0x44,0x8e,0xc9 }, - { 0x89,0x6a,0x75,0xc2 }, { 0x79,0x78,0xf4,0x8e }, - { 0x3e,0x6b,0x99,0x58 }, { 0x71,0xdd,0x27,0xb9 }, + { 0x69,0x29,0x49,0xe0 }, { 0xc8,0x44,0x8e,0xc9 }, + { 0x89,0x6a,0x75,0xc2 }, { 0x79,0x78,0xf4,0x8e }, + { 0x3e,0x6b,0x99,0x58 }, { 0x71,0xdd,0x27,0xb9 }, { 0x4f,0xb6,0xbe,0xe1 }, { 0xad,0x17,0xf0,0x88 }, - { 0xac,0x66,0xc9,0x20 }, { 0x3a,0xb4,0x7d,0xce }, + { 0xac,0x66,0xc9,0x20 }, { 0x3a,0xb4,0x7d,0xce }, { 0x4a,0x18,0x63,0xdf }, { 0x31,0x82,0xe5,0x1a }, - { 0x33,0x60,0x97,0x51 }, { 0x7f,0x45,0x62,0x53 }, + { 0x33,0x60,0x97,0x51 }, { 0x7f,0x45,0x62,0x53 }, { 0x77,0xe0,0xb1,0x64 }, { 0xae,0x84,0xbb,0x6b }, - { 0xa0,0x1c,0xfe,0x81 }, { 0x2b,0x94,0xf9,0x08 }, + { 0xa0,0x1c,0xfe,0x81 }, { 0x2b,0x94,0xf9,0x08 }, { 0x68,0x58,0x70,0x48 }, { 0xfd,0x19,0x8f,0x45 }, - { 0x6c,0x87,0x94,0xde }, { 0xf8,0xb7,0x52,0x7b }, + { 0x6c,0x87,0x94,0xde }, { 0xf8,0xb7,0x52,0x7b }, { 0xd3,0x23,0xab,0x73 }, { 0x02,0xe2,0x72,0x4b }, - { 0x8f,0x57,0xe3,0x1f }, { 0xab,0x2a,0x66,0x55 }, + { 0x8f,0x57,0xe3,0x1f }, { 0xab,0x2a,0x66,0x55 }, { 0x28,0x07,0xb2,0xeb }, { 0xc2,0x03,0x2f,0xb5 }, - { 0x7b,0x9a,0x86,0xc5 }, { 0x08,0xa5,0xd3,0x37 }, + { 0x7b,0x9a,0x86,0xc5 }, { 0x08,0xa5,0xd3,0x37 }, { 0x87,0xf2,0x30,0x28 }, { 0xa5,0xb2,0x23,0xbf }, - { 0x6a,0xba,0x02,0x03 }, { 0x82,0x5c,0xed,0x16 }, - { 0x1c,0x2b,0x8a,0xcf }, { 0xb4,0x92,0xa7,0x79 }, - { 0xf2,0xf0,0xf3,0x07 }, { 0xe2,0xa1,0x4e,0x69 }, + { 0x6a,0xba,0x02,0x03 }, { 0x82,0x5c,0xed,0x16 }, + { 0x1c,0x2b,0x8a,0xcf }, { 0xb4,0x92,0xa7,0x79 }, + { 0xf2,0xf0,0xf3,0x07 }, { 0xe2,0xa1,0x4e,0x69 }, { 0xf4,0xcd,0x65,0xda }, { 0xbe,0xd5,0x06,0x05 }, - { 0x62,0x1f,0xd1,0x34 }, { 0xfe,0x8a,0xc4,0xa6 }, + { 0x62,0x1f,0xd1,0x34 }, { 0xfe,0x8a,0xc4,0xa6 }, { 0x53,0x9d,0x34,0x2e }, { 0x55,0xa0,0xa2,0xf3 }, - { 0xe1,0x32,0x05,0x8a }, { 0xeb,0x75,0xa4,0xf6 }, + { 0xe1,0x32,0x05,0x8a }, { 0xeb,0x75,0xa4,0xf6 }, { 0xec,0x39,0x0b,0x83 }, { 0xef,0xaa,0x40,0x60 }, - { 0x9f,0x06,0x5e,0x71 }, { 0x10,0x51,0xbd,0x6e }, + { 0x9f,0x06,0x5e,0x71 }, { 0x10,0x51,0xbd,0x6e }, { 0x8a,0xf9,0x3e,0x21 }, { 0x06,0x3d,0x96,0xdd }, - { 0x05,0xae,0xdd,0x3e }, { 0xbd,0x46,0x4d,0xe6 }, + { 0x05,0xae,0xdd,0x3e }, { 0xbd,0x46,0x4d,0xe6 }, { 0x8d,0xb5,0x91,0x54 }, { 0x5d,0x05,0x71,0xc4 }, - { 0xd4,0x6f,0x04,0x06 }, { 0x15,0xff,0x60,0x50 }, - { 0xfb,0x24,0x19,0x98 }, { 0xe9,0x97,0xd6,0xbd }, - { 0x43,0xcc,0x89,0x40 }, { 0x9e,0x77,0x67,0xd9 }, + { 0xd4,0x6f,0x04,0x06 }, { 0x15,0xff,0x60,0x50 }, + { 0xfb,0x24,0x19,0x98 }, { 0xe9,0x97,0xd6,0xbd }, + { 0x43,0xcc,0x89,0x40 }, { 0x9e,0x77,0x67,0xd9 }, { 0x42,0xbd,0xb0,0xe8 }, { 0x8b,0x88,0x07,0x89 }, - { 0x5b,0x38,0xe7,0x19 }, { 0xee,0xdb,0x79,0xc8 }, + { 0x5b,0x38,0xe7,0x19 }, { 0xee,0xdb,0x79,0xc8 }, { 0x0a,0x47,0xa1,0x7c }, { 0x0f,0xe9,0x7c,0x42 }, - { 0x1e,0xc9,0xf8,0x84 }, { 0x00,0x00,0x00,0x00 }, + { 0x1e,0xc9,0xf8,0x84 }, { 0x00,0x00,0x00,0x00 }, { 0x86,0x83,0x09,0x80 }, { 0xed,0x48,0x32,0x2b }, - { 0x70,0xac,0x1e,0x11 }, { 0x72,0x4e,0x6c,0x5a }, + { 0x70,0xac,0x1e,0x11 }, { 0x72,0x4e,0x6c,0x5a }, { 0xff,0xfb,0xfd,0x0e }, { 0x38,0x56,0x0f,0x85 }, - { 0xd5,0x1e,0x3d,0xae }, { 0x39,0x27,0x36,0x2d }, + { 0xd5,0x1e,0x3d,0xae }, { 0x39,0x27,0x36,0x2d }, { 0xd9,0x64,0x0a,0x0f }, { 0xa6,0x21,0x68,0x5c }, - { 0x54,0xd1,0x9b,0x5b }, { 0x2e,0x3a,0x24,0x36 }, + { 0x54,0xd1,0x9b,0x5b }, { 0x2e,0x3a,0x24,0x36 }, { 0x67,0xb1,0x0c,0x0a }, { 0xe7,0x0f,0x93,0x57 }, - { 0x96,0xd2,0xb4,0xee }, { 0x91,0x9e,0x1b,0x9b }, + { 0x96,0xd2,0xb4,0xee }, { 0x91,0x9e,0x1b,0x9b }, { 0xc5,0x4f,0x80,0xc0 }, { 0x20,0xa2,0x61,0xdc }, - { 0x4b,0x69,0x5a,0x77 }, { 0x1a,0x16,0x1c,0x12 }, + { 0x4b,0x69,0x5a,0x77 }, { 0x1a,0x16,0x1c,0x12 }, { 0xba,0x0a,0xe2,0x93 }, { 0x2a,0xe5,0xc0,0xa0 }, - { 0xe0,0x43,0x3c,0x22 }, { 0x17,0x1d,0x12,0x1b }, + { 0xe0,0x43,0x3c,0x22 }, { 0x17,0x1d,0x12,0x1b }, { 0x0d,0x0b,0x0e,0x09 }, { 0xc7,0xad,0xf2,0x8b }, - { 0xa8,0xb9,0x2d,0xb6 }, { 0xa9,0xc8,0x14,0x1e }, + { 0xa8,0xb9,0x2d,0xb6 }, { 0xa9,0xc8,0x14,0x1e }, { 0x19,0x85,0x57,0xf1 }, { 0x07,0x4c,0xaf,0x75 }, - { 0xdd,0xbb,0xee,0x99 }, { 0x60,0xfd,0xa3,0x7f }, + { 0xdd,0xbb,0xee,0x99 }, { 0x60,0xfd,0xa3,0x7f }, { 0x26,0x9f,0xf7,0x01 }, { 0xf5,0xbc,0x5c,0x72 }, - { 0x3b,0xc5,0x44,0x66 }, { 0x7e,0x34,0x5b,0xfb }, + { 0x3b,0xc5,0x44,0x66 }, { 0x7e,0x34,0x5b,0xfb }, { 0x29,0x76,0x8b,0x43 }, { 0xc6,0xdc,0xcb,0x23 }, - { 0xfc,0x68,0xb6,0xed }, { 0xf1,0x63,0xb8,0xe4 }, + { 0xfc,0x68,0xb6,0xed }, { 0xf1,0x63,0xb8,0xe4 }, { 0xdc,0xca,0xd7,0x31 }, { 0x85,0x10,0x42,0x63 }, - { 0x22,0x40,0x13,0x97 }, { 0x11,0x20,0x84,0xc6 }, + { 0x22,0x40,0x13,0x97 }, { 0x11,0x20,0x84,0xc6 }, { 0x24,0x7d,0x85,0x4a }, { 0x3d,0xf8,0xd2,0xbb }, - { 0x32,0x11,0xae,0xf9 }, { 0xa1,0x6d,0xc7,0x29 }, + { 0x32,0x11,0xae,0xf9 }, { 0xa1,0x6d,0xc7,0x29 }, { 0x2f,0x4b,0x1d,0x9e }, { 0x30,0xf3,0xdc,0xb2 }, - { 0x52,0xec,0x0d,0x86 }, { 0xe3,0xd0,0x77,0xc1 }, + { 0x52,0xec,0x0d,0x86 }, { 0xe3,0xd0,0x77,0xc1 }, { 0x16,0x6c,0x2b,0xb3 }, { 0xb9,0x99,0xa9,0x70 }, - { 0x48,0xfa,0x11,0x94 }, { 0x64,0x22,0x47,0xe9 }, + { 0x48,0xfa,0x11,0x94 }, { 0x64,0x22,0x47,0xe9 }, { 0x8c,0xc4,0xa8,0xfc }, { 0x3f,0x1a,0xa0,0xf0 }, - { 0x2c,0xd8,0x56,0x7d }, { 0x90,0xef,0x22,0x33 }, + { 0x2c,0xd8,0x56,0x7d }, { 0x90,0xef,0x22,0x33 }, { 0x4e,0xc7,0x87,0x49 }, { 0xd1,0xc1,0xd9,0x38 }, - { 0xa2,0xfe,0x8c,0xca }, { 0x0b,0x36,0x98,0xd4 }, + { 0xa2,0xfe,0x8c,0xca }, { 0x0b,0x36,0x98,0xd4 }, { 0x81,0xcf,0xa6,0xf5 }, { 0xde,0x28,0xa5,0x7a }, - { 0x8e,0x26,0xda,0xb7 }, { 0xbf,0xa4,0x3f,0xad }, + { 0x8e,0x26,0xda,0xb7 }, { 0xbf,0xa4,0x3f,0xad }, { 0x9d,0xe4,0x2c,0x3a }, { 0x92,0x0d,0x50,0x78 }, - { 0xcc,0x9b,0x6a,0x5f }, { 0x46,0x62,0x54,0x7e }, + { 0xcc,0x9b,0x6a,0x5f }, { 0x46,0x62,0x54,0x7e }, { 0x13,0xc2,0xf6,0x8d }, { 0xb8,0xe8,0x90,0xd8 }, - { 0xf7,0x5e,0x2e,0x39 }, { 0xaf,0xf5,0x82,0xc3 }, + { 0xf7,0x5e,0x2e,0x39 }, { 0xaf,0xf5,0x82,0xc3 }, { 0x80,0xbe,0x9f,0x5d }, { 0x93,0x7c,0x69,0xd0 }, - { 0x2d,0xa9,0x6f,0xd5 }, { 0x12,0xb3,0xcf,0x25 }, + { 0x2d,0xa9,0x6f,0xd5 }, { 0x12,0xb3,0xcf,0x25 }, { 0x99,0x3b,0xc8,0xac }, { 0x7d,0xa7,0x10,0x18 }, - { 0x63,0x6e,0xe8,0x9c }, { 0xbb,0x7b,0xdb,0x3b }, - { 0x78,0x09,0xcd,0x26 }, { 0x18,0xf4,0x6e,0x59 }, - { 0xb7,0x01,0xec,0x9a }, { 0x9a,0xa8,0x83,0x4f }, + { 0x63,0x6e,0xe8,0x9c }, { 0xbb,0x7b,0xdb,0x3b }, + { 0x78,0x09,0xcd,0x26 }, { 0x18,0xf4,0x6e,0x59 }, + { 0xb7,0x01,0xec,0x9a }, { 0x9a,0xa8,0x83,0x4f }, { 0x6e,0x65,0xe6,0x95 }, { 0xe6,0x7e,0xaa,0xff }, - { 0xcf,0x08,0x21,0xbc }, { 0xe8,0xe6,0xef,0x15 }, + { 0xcf,0x08,0x21,0xbc }, { 0xe8,0xe6,0xef,0x15 }, { 0x9b,0xd9,0xba,0xe7 }, { 0x36,0xce,0x4a,0x6f }, - { 0x09,0xd4,0xea,0x9f }, { 0x7c,0xd6,0x29,0xb0 }, + { 0x09,0xd4,0xea,0x9f }, { 0x7c,0xd6,0x29,0xb0 }, { 0xb2,0xaf,0x31,0xa4 }, { 0x23,0x31,0x2a,0x3f }, - { 0x94,0x30,0xc6,0xa5 }, { 0x66,0xc0,0x35,0xa2 }, + { 0x94,0x30,0xc6,0xa5 }, { 0x66,0xc0,0x35,0xa2 }, { 0xbc,0x37,0x74,0x4e }, { 0xca,0xa6,0xfc,0x82 }, - { 0xd0,0xb0,0xe0,0x90 }, { 0xd8,0x15,0x33,0xa7 }, + { 0xd0,0xb0,0xe0,0x90 }, { 0xd8,0x15,0x33,0xa7 }, { 0x98,0x4a,0xf1,0x04 }, { 0xda,0xf7,0x41,0xec }, - { 0x50,0x0e,0x7f,0xcd }, { 0xf6,0x2f,0x17,0x91 }, - { 0xd6,0x8d,0x76,0x4d }, { 0xb0,0x4d,0x43,0xef }, - { 0x4d,0x54,0xcc,0xaa }, { 0x04,0xdf,0xe4,0x96 }, + { 0x50,0x0e,0x7f,0xcd }, { 0xf6,0x2f,0x17,0x91 }, + { 0xd6,0x8d,0x76,0x4d }, { 0xb0,0x4d,0x43,0xef }, + { 0x4d,0x54,0xcc,0xaa }, { 0x04,0xdf,0xe4,0x96 }, { 0xb5,0xe3,0x9e,0xd1 }, { 0x88,0x1b,0x4c,0x6a }, - { 0x1f,0xb8,0xc1,0x2c }, { 0x51,0x7f,0x46,0x65 }, + { 0x1f,0xb8,0xc1,0x2c }, { 0x51,0x7f,0x46,0x65 }, { 0xea,0x04,0x9d,0x5e }, { 0x35,0x5d,0x01,0x8c }, - { 0x74,0x73,0xfa,0x87 }, { 0x41,0x2e,0xfb,0x0b }, + { 0x74,0x73,0xfa,0x87 }, { 0x41,0x2e,0xfb,0x0b }, { 0x1d,0x5a,0xb3,0x67 }, { 0xd2,0x52,0x92,0xdb }, - { 0x56,0x33,0xe9,0x10 }, { 0x47,0x13,0x6d,0xd6 }, + { 0x56,0x33,0xe9,0x10 }, { 0x47,0x13,0x6d,0xd6 }, { 0x61,0x8c,0x9a,0xd7 }, { 0x0c,0x7a,0x37,0xa1 }, - { 0x14,0x8e,0x59,0xf8 }, { 0x3c,0x89,0xeb,0x13 }, + { 0x14,0x8e,0x59,0xf8 }, { 0x3c,0x89,0xeb,0x13 }, { 0x27,0xee,0xce,0xa9 }, { 0xc9,0x35,0xb7,0x61 }, - { 0xe5,0xed,0xe1,0x1c }, { 0xb1,0x3c,0x7a,0x47 }, + { 0xe5,0xed,0xe1,0x1c }, { 0xb1,0x3c,0x7a,0x47 }, { 0xdf,0x59,0x9c,0xd2 }, { 0x73,0x3f,0x55,0xf2 }, - { 0xce,0x79,0x18,0x14 }, { 0x37,0xbf,0x73,0xc7 }, + { 0xce,0x79,0x18,0x14 }, { 0x37,0xbf,0x73,0xc7 }, { 0xcd,0xea,0x53,0xf7 }, { 0xaa,0x5b,0x5f,0xfd }, - { 0x6f,0x14,0xdf,0x3d }, { 0xdb,0x86,0x78,0x44 }, + { 0x6f,0x14,0xdf,0x3d }, { 0xdb,0x86,0x78,0x44 }, { 0xf3,0x81,0xca,0xaf }, { 0xc4,0x3e,0xb9,0x68 }, - { 0x34,0x2c,0x38,0x24 }, { 0x40,0x5f,0xc2,0xa3 }, + { 0x34,0x2c,0x38,0x24 }, { 0x40,0x5f,0xc2,0xa3 }, { 0xc3,0x72,0x16,0x1d }, { 0x25,0x0c,0xbc,0xe2 }, - { 0x49,0x8b,0x28,0x3c }, { 0x95,0x41,0xff,0x0d }, + { 0x49,0x8b,0x28,0x3c }, { 0x95,0x41,0xff,0x0d }, { 0x01,0x71,0x39,0xa8 }, { 0xb3,0xde,0x08,0x0c }, - { 0xe4,0x9c,0xd8,0xb4 }, { 0xc1,0x90,0x64,0x56 }, + { 0xe4,0x9c,0xd8,0xb4 }, { 0xc1,0x90,0x64,0x56 }, { 0x84,0x61,0x7b,0xcb }, { 0xb6,0x70,0xd5,0x32 }, { 0x5c,0x74,0x48,0x6c }, { 0x57,0x42,0xd0,0xb8 } }; -static const unsigned char T8[256][4] = +static const unsigned char T8[256][4] = { { 0xf4,0xa7,0x50,0x51 }, { 0x41,0x65,0x53,0x7e }, - { 0x17,0xa4,0xc3,0x1a }, { 0x27,0x5e,0x96,0x3a }, + { 0x17,0xa4,0xc3,0x1a }, { 0x27,0x5e,0x96,0x3a }, { 0xab,0x6b,0xcb,0x3b }, { 0x9d,0x45,0xf1,0x1f }, - { 0xfa,0x58,0xab,0xac }, { 0xe3,0x03,0x93,0x4b }, + { 0xfa,0x58,0xab,0xac }, { 0xe3,0x03,0x93,0x4b }, { 0x30,0xfa,0x55,0x20 }, { 0x76,0x6d,0xf6,0xad }, - { 0xcc,0x76,0x91,0x88 }, { 0x02,0x4c,0x25,0xf5 }, + { 0xcc,0x76,0x91,0x88 }, { 0x02,0x4c,0x25,0xf5 }, { 0xe5,0xd7,0xfc,0x4f }, { 0x2a,0xcb,0xd7,0xc5 }, - { 0x35,0x44,0x80,0x26 }, { 0x62,0xa3,0x8f,0xb5 }, + { 0x35,0x44,0x80,0x26 }, { 0x62,0xa3,0x8f,0xb5 }, { 0xb1,0x5a,0x49,0xde }, { 0xba,0x1b,0x67,0x25 }, - { 0xea,0x0e,0x98,0x45 }, { 0xfe,0xc0,0xe1,0x5d }, + { 0xea,0x0e,0x98,0x45 }, { 0xfe,0xc0,0xe1,0x5d }, { 0x2f,0x75,0x02,0xc3 }, { 0x4c,0xf0,0x12,0x81 }, - { 0x46,0x97,0xa3,0x8d }, { 0xd3,0xf9,0xc6,0x6b }, + { 0x46,0x97,0xa3,0x8d }, { 0xd3,0xf9,0xc6,0x6b }, { 0x8f,0x5f,0xe7,0x03 }, { 0x92,0x9c,0x95,0x15 }, - { 0x6d,0x7a,0xeb,0xbf }, { 0x52,0x59,0xda,0x95 }, + { 0x6d,0x7a,0xeb,0xbf }, { 0x52,0x59,0xda,0x95 }, { 0xbe,0x83,0x2d,0xd4 }, { 0x74,0x21,0xd3,0x58 }, - { 0xe0,0x69,0x29,0x49 }, { 0xc9,0xc8,0x44,0x8e }, + { 0xe0,0x69,0x29,0x49 }, { 0xc9,0xc8,0x44,0x8e }, { 0xc2,0x89,0x6a,0x75 }, { 0x8e,0x79,0x78,0xf4 }, - { 0x58,0x3e,0x6b,0x99 }, { 0xb9,0x71,0xdd,0x27 }, + { 0x58,0x3e,0x6b,0x99 }, { 0xb9,0x71,0xdd,0x27 }, { 0xe1,0x4f,0xb6,0xbe }, { 0x88,0xad,0x17,0xf0 }, - { 0x20,0xac,0x66,0xc9 }, { 0xce,0x3a,0xb4,0x7d }, + { 0x20,0xac,0x66,0xc9 }, { 0xce,0x3a,0xb4,0x7d }, { 0xdf,0x4a,0x18,0x63 }, { 0x1a,0x31,0x82,0xe5 }, - { 0x51,0x33,0x60,0x97 }, { 0x53,0x7f,0x45,0x62 }, + { 0x51,0x33,0x60,0x97 }, { 0x53,0x7f,0x45,0x62 }, { 0x64,0x77,0xe0,0xb1 }, { 0x6b,0xae,0x84,0xbb }, - { 0x81,0xa0,0x1c,0xfe }, { 0x08,0x2b,0x94,0xf9 }, + { 0x81,0xa0,0x1c,0xfe }, { 0x08,0x2b,0x94,0xf9 }, { 0x48,0x68,0x58,0x70 }, { 0x45,0xfd,0x19,0x8f }, - { 0xde,0x6c,0x87,0x94 }, { 0x7b,0xf8,0xb7,0x52 }, + { 0xde,0x6c,0x87,0x94 }, { 0x7b,0xf8,0xb7,0x52 }, { 0x73,0xd3,0x23,0xab }, { 0x4b,0x02,0xe2,0x72 }, - { 0x1f,0x8f,0x57,0xe3 }, { 0x55,0xab,0x2a,0x66 }, + { 0x1f,0x8f,0x57,0xe3 }, { 0x55,0xab,0x2a,0x66 }, { 0xeb,0x28,0x07,0xb2 }, { 0xb5,0xc2,0x03,0x2f }, - { 0xc5,0x7b,0x9a,0x86 }, { 0x37,0x08,0xa5,0xd3 }, + { 0xc5,0x7b,0x9a,0x86 }, { 0x37,0x08,0xa5,0xd3 }, { 0x28,0x87,0xf2,0x30 }, { 0xbf,0xa5,0xb2,0x23 }, - { 0x03,0x6a,0xba,0x02 }, { 0x16,0x82,0x5c,0xed }, + { 0x03,0x6a,0xba,0x02 }, { 0x16,0x82,0x5c,0xed }, { 0xcf,0x1c,0x2b,0x8a }, { 0x79,0xb4,0x92,0xa7 }, - { 0x07,0xf2,0xf0,0xf3 }, { 0x69,0xe2,0xa1,0x4e }, + { 0x07,0xf2,0xf0,0xf3 }, { 0x69,0xe2,0xa1,0x4e }, { 0xda,0xf4,0xcd,0x65 }, { 0x05,0xbe,0xd5,0x06 }, - { 0x34,0x62,0x1f,0xd1 }, { 0xa6,0xfe,0x8a,0xc4 }, + { 0x34,0x62,0x1f,0xd1 }, { 0xa6,0xfe,0x8a,0xc4 }, { 0x2e,0x53,0x9d,0x34 }, { 0xf3,0x55,0xa0,0xa2 }, - { 0x8a,0xe1,0x32,0x05 }, { 0xf6,0xeb,0x75,0xa4 }, + { 0x8a,0xe1,0x32,0x05 }, { 0xf6,0xeb,0x75,0xa4 }, { 0x83,0xec,0x39,0x0b }, { 0x60,0xef,0xaa,0x40 }, - { 0x71,0x9f,0x06,0x5e }, { 0x6e,0x10,0x51,0xbd }, + { 0x71,0x9f,0x06,0x5e }, { 0x6e,0x10,0x51,0xbd }, { 0x21,0x8a,0xf9,0x3e }, { 0xdd,0x06,0x3d,0x96 }, - { 0x3e,0x05,0xae,0xdd }, { 0xe6,0xbd,0x46,0x4d }, + { 0x3e,0x05,0xae,0xdd }, { 0xe6,0xbd,0x46,0x4d }, { 0x54,0x8d,0xb5,0x91 }, { 0xc4,0x5d,0x05,0x71 }, - { 0x06,0xd4,0x6f,0x04 }, { 0x50,0x15,0xff,0x60 }, + { 0x06,0xd4,0x6f,0x04 }, { 0x50,0x15,0xff,0x60 }, { 0x98,0xfb,0x24,0x19 }, { 0xbd,0xe9,0x97,0xd6 }, - { 0x40,0x43,0xcc,0x89 }, { 0xd9,0x9e,0x77,0x67 }, + { 0x40,0x43,0xcc,0x89 }, { 0xd9,0x9e,0x77,0x67 }, { 0xe8,0x42,0xbd,0xb0 }, { 0x89,0x8b,0x88,0x07 }, - { 0x19,0x5b,0x38,0xe7 }, { 0xc8,0xee,0xdb,0x79 }, + { 0x19,0x5b,0x38,0xe7 }, { 0xc8,0xee,0xdb,0x79 }, { 0x7c,0x0a,0x47,0xa1 }, { 0x42,0x0f,0xe9,0x7c }, - { 0x84,0x1e,0xc9,0xf8 }, { 0x00,0x00,0x00,0x00 }, + { 0x84,0x1e,0xc9,0xf8 }, { 0x00,0x00,0x00,0x00 }, { 0x80,0x86,0x83,0x09 }, { 0x2b,0xed,0x48,0x32 }, - { 0x11,0x70,0xac,0x1e }, { 0x5a,0x72,0x4e,0x6c }, - { 0x0e,0xff,0xfb,0xfd }, { 0x85,0x38,0x56,0x0f }, - { 0xae,0xd5,0x1e,0x3d }, { 0x2d,0x39,0x27,0x36 }, + { 0x11,0x70,0xac,0x1e }, { 0x5a,0x72,0x4e,0x6c }, + { 0x0e,0xff,0xfb,0xfd }, { 0x85,0x38,0x56,0x0f }, + { 0xae,0xd5,0x1e,0x3d }, { 0x2d,0x39,0x27,0x36 }, { 0x0f,0xd9,0x64,0x0a }, { 0x5c,0xa6,0x21,0x68 }, - { 0x5b,0x54,0xd1,0x9b }, { 0x36,0x2e,0x3a,0x24 }, + { 0x5b,0x54,0xd1,0x9b }, { 0x36,0x2e,0x3a,0x24 }, { 0x0a,0x67,0xb1,0x0c }, { 0x57,0xe7,0x0f,0x93 }, - { 0xee,0x96,0xd2,0xb4 }, { 0x9b,0x91,0x9e,0x1b }, + { 0xee,0x96,0xd2,0xb4 }, { 0x9b,0x91,0x9e,0x1b }, { 0xc0,0xc5,0x4f,0x80 }, { 0xdc,0x20,0xa2,0x61 }, - { 0x77,0x4b,0x69,0x5a }, { 0x12,0x1a,0x16,0x1c }, + { 0x77,0x4b,0x69,0x5a }, { 0x12,0x1a,0x16,0x1c }, { 0x93,0xba,0x0a,0xe2 }, { 0xa0,0x2a,0xe5,0xc0 }, - { 0x22,0xe0,0x43,0x3c }, { 0x1b,0x17,0x1d,0x12 }, + { 0x22,0xe0,0x43,0x3c }, { 0x1b,0x17,0x1d,0x12 }, { 0x09,0x0d,0x0b,0x0e }, { 0x8b,0xc7,0xad,0xf2 }, - { 0xb6,0xa8,0xb9,0x2d }, { 0x1e,0xa9,0xc8,0x14 }, + { 0xb6,0xa8,0xb9,0x2d }, { 0x1e,0xa9,0xc8,0x14 }, { 0xf1,0x19,0x85,0x57 }, { 0x75,0x07,0x4c,0xaf }, - { 0x99,0xdd,0xbb,0xee }, { 0x7f,0x60,0xfd,0xa3 }, + { 0x99,0xdd,0xbb,0xee }, { 0x7f,0x60,0xfd,0xa3 }, { 0x01,0x26,0x9f,0xf7 }, { 0x72,0xf5,0xbc,0x5c }, - { 0x66,0x3b,0xc5,0x44 }, { 0xfb,0x7e,0x34,0x5b }, + { 0x66,0x3b,0xc5,0x44 }, { 0xfb,0x7e,0x34,0x5b }, { 0x43,0x29,0x76,0x8b }, { 0x23,0xc6,0xdc,0xcb }, - { 0xed,0xfc,0x68,0xb6 }, { 0xe4,0xf1,0x63,0xb8 }, + { 0xed,0xfc,0x68,0xb6 }, { 0xe4,0xf1,0x63,0xb8 }, { 0x31,0xdc,0xca,0xd7 }, { 0x63,0x85,0x10,0x42 }, - { 0x97,0x22,0x40,0x13 }, { 0xc6,0x11,0x20,0x84 }, - { 0x4a,0x24,0x7d,0x85 }, { 0xbb,0x3d,0xf8,0xd2 }, - { 0xf9,0x32,0x11,0xae }, { 0x29,0xa1,0x6d,0xc7 }, + { 0x97,0x22,0x40,0x13 }, { 0xc6,0x11,0x20,0x84 }, + { 0x4a,0x24,0x7d,0x85 }, { 0xbb,0x3d,0xf8,0xd2 }, + { 0xf9,0x32,0x11,0xae }, { 0x29,0xa1,0x6d,0xc7 }, { 0x9e,0x2f,0x4b,0x1d }, { 0xb2,0x30,0xf3,0xdc }, - { 0x86,0x52,0xec,0x0d }, { 0xc1,0xe3,0xd0,0x77 }, + { 0x86,0x52,0xec,0x0d }, { 0xc1,0xe3,0xd0,0x77 }, { 0xb3,0x16,0x6c,0x2b }, { 0x70,0xb9,0x99,0xa9 }, - { 0x94,0x48,0xfa,0x11 }, { 0xe9,0x64,0x22,0x47 }, + { 0x94,0x48,0xfa,0x11 }, { 0xe9,0x64,0x22,0x47 }, { 0xfc,0x8c,0xc4,0xa8 }, { 0xf0,0x3f,0x1a,0xa0 }, - { 0x7d,0x2c,0xd8,0x56 }, { 0x33,0x90,0xef,0x22 }, + { 0x7d,0x2c,0xd8,0x56 }, { 0x33,0x90,0xef,0x22 }, { 0x49,0x4e,0xc7,0x87 }, { 0x38,0xd1,0xc1,0xd9 }, - { 0xca,0xa2,0xfe,0x8c }, { 0xd4,0x0b,0x36,0x98 }, + { 0xca,0xa2,0xfe,0x8c }, { 0xd4,0x0b,0x36,0x98 }, { 0xf5,0x81,0xcf,0xa6 }, { 0x7a,0xde,0x28,0xa5 }, - { 0xb7,0x8e,0x26,0xda }, { 0xad,0xbf,0xa4,0x3f }, + { 0xb7,0x8e,0x26,0xda }, { 0xad,0xbf,0xa4,0x3f }, { 0x3a,0x9d,0xe4,0x2c }, { 0x78,0x92,0x0d,0x50 }, - { 0x5f,0xcc,0x9b,0x6a }, { 0x7e,0x46,0x62,0x54 }, + { 0x5f,0xcc,0x9b,0x6a }, { 0x7e,0x46,0x62,0x54 }, { 0x8d,0x13,0xc2,0xf6 }, { 0xd8,0xb8,0xe8,0x90 }, - { 0x39,0xf7,0x5e,0x2e }, { 0xc3,0xaf,0xf5,0x82 }, + { 0x39,0xf7,0x5e,0x2e }, { 0xc3,0xaf,0xf5,0x82 }, { 0x5d,0x80,0xbe,0x9f }, { 0xd0,0x93,0x7c,0x69 }, - { 0xd5,0x2d,0xa9,0x6f }, { 0x25,0x12,0xb3,0xcf }, + { 0xd5,0x2d,0xa9,0x6f }, { 0x25,0x12,0xb3,0xcf }, { 0xac,0x99,0x3b,0xc8 }, { 0x18,0x7d,0xa7,0x10 }, - { 0x9c,0x63,0x6e,0xe8 }, { 0x3b,0xbb,0x7b,0xdb }, + { 0x9c,0x63,0x6e,0xe8 }, { 0x3b,0xbb,0x7b,0xdb }, { 0x26,0x78,0x09,0xcd }, { 0x59,0x18,0xf4,0x6e }, - { 0x9a,0xb7,0x01,0xec }, { 0x4f,0x9a,0xa8,0x83 }, + { 0x9a,0xb7,0x01,0xec }, { 0x4f,0x9a,0xa8,0x83 }, { 0x95,0x6e,0x65,0xe6 }, { 0xff,0xe6,0x7e,0xaa }, - { 0xbc,0xcf,0x08,0x21 }, { 0x15,0xe8,0xe6,0xef }, + { 0xbc,0xcf,0x08,0x21 }, { 0x15,0xe8,0xe6,0xef }, { 0xe7,0x9b,0xd9,0xba }, { 0x6f,0x36,0xce,0x4a }, - { 0x9f,0x09,0xd4,0xea }, { 0xb0,0x7c,0xd6,0x29 }, + { 0x9f,0x09,0xd4,0xea }, { 0xb0,0x7c,0xd6,0x29 }, { 0xa4,0xb2,0xaf,0x31 }, { 0x3f,0x23,0x31,0x2a }, - { 0xa5,0x94,0x30,0xc6 }, { 0xa2,0x66,0xc0,0x35 }, + { 0xa5,0x94,0x30,0xc6 }, { 0xa2,0x66,0xc0,0x35 }, { 0x4e,0xbc,0x37,0x74 }, { 0x82,0xca,0xa6,0xfc }, - { 0x90,0xd0,0xb0,0xe0 }, { 0xa7,0xd8,0x15,0x33 }, + { 0x90,0xd0,0xb0,0xe0 }, { 0xa7,0xd8,0x15,0x33 }, { 0x04,0x98,0x4a,0xf1 }, { 0xec,0xda,0xf7,0x41 }, - { 0xcd,0x50,0x0e,0x7f }, { 0x91,0xf6,0x2f,0x17 }, - { 0x4d,0xd6,0x8d,0x76 }, { 0xef,0xb0,0x4d,0x43 }, - { 0xaa,0x4d,0x54,0xcc }, { 0x96,0x04,0xdf,0xe4 }, + { 0xcd,0x50,0x0e,0x7f }, { 0x91,0xf6,0x2f,0x17 }, + { 0x4d,0xd6,0x8d,0x76 }, { 0xef,0xb0,0x4d,0x43 }, + { 0xaa,0x4d,0x54,0xcc }, { 0x96,0x04,0xdf,0xe4 }, { 0xd1,0xb5,0xe3,0x9e }, { 0x6a,0x88,0x1b,0x4c }, - { 0x2c,0x1f,0xb8,0xc1 }, { 0x65,0x51,0x7f,0x46 }, + { 0x2c,0x1f,0xb8,0xc1 }, { 0x65,0x51,0x7f,0x46 }, { 0x5e,0xea,0x04,0x9d }, { 0x8c,0x35,0x5d,0x01 }, - { 0x87,0x74,0x73,0xfa }, { 0x0b,0x41,0x2e,0xfb }, + { 0x87,0x74,0x73,0xfa }, { 0x0b,0x41,0x2e,0xfb }, { 0x67,0x1d,0x5a,0xb3 }, { 0xdb,0xd2,0x52,0x92 }, - { 0x10,0x56,0x33,0xe9 }, { 0xd6,0x47,0x13,0x6d }, + { 0x10,0x56,0x33,0xe9 }, { 0xd6,0x47,0x13,0x6d }, { 0xd7,0x61,0x8c,0x9a }, { 0xa1,0x0c,0x7a,0x37 }, - { 0xf8,0x14,0x8e,0x59 }, { 0x13,0x3c,0x89,0xeb }, + { 0xf8,0x14,0x8e,0x59 }, { 0x13,0x3c,0x89,0xeb }, { 0xa9,0x27,0xee,0xce }, { 0x61,0xc9,0x35,0xb7 }, - { 0x1c,0xe5,0xed,0xe1 }, { 0x47,0xb1,0x3c,0x7a }, + { 0x1c,0xe5,0xed,0xe1 }, { 0x47,0xb1,0x3c,0x7a }, { 0xd2,0xdf,0x59,0x9c }, { 0xf2,0x73,0x3f,0x55 }, - { 0x14,0xce,0x79,0x18 }, { 0xc7,0x37,0xbf,0x73 }, + { 0x14,0xce,0x79,0x18 }, { 0xc7,0x37,0xbf,0x73 }, { 0xf7,0xcd,0xea,0x53 }, { 0xfd,0xaa,0x5b,0x5f }, - { 0x3d,0x6f,0x14,0xdf }, { 0x44,0xdb,0x86,0x78 }, + { 0x3d,0x6f,0x14,0xdf }, { 0x44,0xdb,0x86,0x78 }, { 0xaf,0xf3,0x81,0xca }, { 0x68,0xc4,0x3e,0xb9 }, - { 0x24,0x34,0x2c,0x38 }, { 0xa3,0x40,0x5f,0xc2 }, + { 0x24,0x34,0x2c,0x38 }, { 0xa3,0x40,0x5f,0xc2 }, { 0x1d,0xc3,0x72,0x16 }, { 0xe2,0x25,0x0c,0xbc }, - { 0x3c,0x49,0x8b,0x28 }, { 0x0d,0x95,0x41,0xff }, + { 0x3c,0x49,0x8b,0x28 }, { 0x0d,0x95,0x41,0xff }, { 0xa8,0x01,0x71,0x39 }, { 0x0c,0xb3,0xde,0x08 }, - { 0xb4,0xe4,0x9c,0xd8 }, { 0x56,0xc1,0x90,0x64 }, + { 0xb4,0xe4,0x9c,0xd8 }, { 0x56,0xc1,0x90,0x64 }, { 0xcb,0x84,0x61,0x7b }, { 0x32,0xb6,0x70,0xd5 }, { 0x6c,0x5c,0x74,0x48 }, { 0xb8,0x57,0x42,0xd0 } }; -static const unsigned char S5[256] = +static const unsigned char S5[256] = { 0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38, 0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb, @@ -1150,398 +1150,398 @@ static const unsigned char S5[256] = 0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d }; -static const unsigned char U1[256][4] = +static const unsigned char U1[256][4] = { { 0x00,0x00,0x00,0x00 }, { 0x0e,0x09,0x0d,0x0b }, - { 0x1c,0x12,0x1a,0x16 }, { 0x12,0x1b,0x17,0x1d }, + { 0x1c,0x12,0x1a,0x16 }, { 0x12,0x1b,0x17,0x1d }, { 0x38,0x24,0x34,0x2c }, { 0x36,0x2d,0x39,0x27 }, - { 0x24,0x36,0x2e,0x3a }, { 0x2a,0x3f,0x23,0x31 }, + { 0x24,0x36,0x2e,0x3a }, { 0x2a,0x3f,0x23,0x31 }, { 0x70,0x48,0x68,0x58 }, { 0x7e,0x41,0x65,0x53 }, - { 0x6c,0x5a,0x72,0x4e }, { 0x62,0x53,0x7f,0x45 }, + { 0x6c,0x5a,0x72,0x4e }, { 0x62,0x53,0x7f,0x45 }, { 0x48,0x6c,0x5c,0x74 }, { 0x46,0x65,0x51,0x7f }, - { 0x54,0x7e,0x46,0x62 }, { 0x5a,0x77,0x4b,0x69 }, + { 0x54,0x7e,0x46,0x62 }, { 0x5a,0x77,0x4b,0x69 }, { 0xe0,0x90,0xd0,0xb0 }, { 0xee,0x99,0xdd,0xbb }, - { 0xfc,0x82,0xca,0xa6 }, { 0xf2,0x8b,0xc7,0xad }, + { 0xfc,0x82,0xca,0xa6 }, { 0xf2,0x8b,0xc7,0xad }, { 0xd8,0xb4,0xe4,0x9c }, { 0xd6,0xbd,0xe9,0x97 }, - { 0xc4,0xa6,0xfe,0x8a }, { 0xca,0xaf,0xf3,0x81 }, + { 0xc4,0xa6,0xfe,0x8a }, { 0xca,0xaf,0xf3,0x81 }, { 0x90,0xd8,0xb8,0xe8 }, { 0x9e,0xd1,0xb5,0xe3 }, - { 0x8c,0xca,0xa2,0xfe }, { 0x82,0xc3,0xaf,0xf5 }, + { 0x8c,0xca,0xa2,0xfe }, { 0x82,0xc3,0xaf,0xf5 }, { 0xa8,0xfc,0x8c,0xc4 }, { 0xa6,0xf5,0x81,0xcf }, - { 0xb4,0xee,0x96,0xd2 }, { 0xba,0xe7,0x9b,0xd9 }, + { 0xb4,0xee,0x96,0xd2 }, { 0xba,0xe7,0x9b,0xd9 }, { 0xdb,0x3b,0xbb,0x7b }, { 0xd5,0x32,0xb6,0x70 }, - { 0xc7,0x29,0xa1,0x6d }, { 0xc9,0x20,0xac,0x66 }, + { 0xc7,0x29,0xa1,0x6d }, { 0xc9,0x20,0xac,0x66 }, { 0xe3,0x1f,0x8f,0x57 }, { 0xed,0x16,0x82,0x5c }, - { 0xff,0x0d,0x95,0x41 }, { 0xf1,0x04,0x98,0x4a }, + { 0xff,0x0d,0x95,0x41 }, { 0xf1,0x04,0x98,0x4a }, { 0xab,0x73,0xd3,0x23 }, { 0xa5,0x7a,0xde,0x28 }, - { 0xb7,0x61,0xc9,0x35 }, { 0xb9,0x68,0xc4,0x3e }, + { 0xb7,0x61,0xc9,0x35 }, { 0xb9,0x68,0xc4,0x3e }, { 0x93,0x57,0xe7,0x0f }, { 0x9d,0x5e,0xea,0x04 }, - { 0x8f,0x45,0xfd,0x19 }, { 0x81,0x4c,0xf0,0x12 }, + { 0x8f,0x45,0xfd,0x19 }, { 0x81,0x4c,0xf0,0x12 }, { 0x3b,0xab,0x6b,0xcb }, { 0x35,0xa2,0x66,0xc0 }, - { 0x27,0xb9,0x71,0xdd }, { 0x29,0xb0,0x7c,0xd6 }, + { 0x27,0xb9,0x71,0xdd }, { 0x29,0xb0,0x7c,0xd6 }, { 0x03,0x8f,0x5f,0xe7 }, { 0x0d,0x86,0x52,0xec }, - { 0x1f,0x9d,0x45,0xf1 }, { 0x11,0x94,0x48,0xfa }, + { 0x1f,0x9d,0x45,0xf1 }, { 0x11,0x94,0x48,0xfa }, { 0x4b,0xe3,0x03,0x93 }, { 0x45,0xea,0x0e,0x98 }, - { 0x57,0xf1,0x19,0x85 }, { 0x59,0xf8,0x14,0x8e }, + { 0x57,0xf1,0x19,0x85 }, { 0x59,0xf8,0x14,0x8e }, { 0x73,0xc7,0x37,0xbf }, { 0x7d,0xce,0x3a,0xb4 }, - { 0x6f,0xd5,0x2d,0xa9 }, { 0x61,0xdc,0x20,0xa2 }, + { 0x6f,0xd5,0x2d,0xa9 }, { 0x61,0xdc,0x20,0xa2 }, { 0xad,0x76,0x6d,0xf6 }, { 0xa3,0x7f,0x60,0xfd }, - { 0xb1,0x64,0x77,0xe0 }, { 0xbf,0x6d,0x7a,0xeb }, + { 0xb1,0x64,0x77,0xe0 }, { 0xbf,0x6d,0x7a,0xeb }, { 0x95,0x52,0x59,0xda }, { 0x9b,0x5b,0x54,0xd1 }, - { 0x89,0x40,0x43,0xcc }, { 0x87,0x49,0x4e,0xc7 }, + { 0x89,0x40,0x43,0xcc }, { 0x87,0x49,0x4e,0xc7 }, { 0xdd,0x3e,0x05,0xae }, { 0xd3,0x37,0x08,0xa5 }, - { 0xc1,0x2c,0x1f,0xb8 }, { 0xcf,0x25,0x12,0xb3 }, + { 0xc1,0x2c,0x1f,0xb8 }, { 0xcf,0x25,0x12,0xb3 }, { 0xe5,0x1a,0x31,0x82 }, { 0xeb,0x13,0x3c,0x89 }, - { 0xf9,0x08,0x2b,0x94 }, { 0xf7,0x01,0x26,0x9f }, + { 0xf9,0x08,0x2b,0x94 }, { 0xf7,0x01,0x26,0x9f }, { 0x4d,0xe6,0xbd,0x46 }, { 0x43,0xef,0xb0,0x4d }, - { 0x51,0xf4,0xa7,0x50 }, { 0x5f,0xfd,0xaa,0x5b }, + { 0x51,0xf4,0xa7,0x50 }, { 0x5f,0xfd,0xaa,0x5b }, { 0x75,0xc2,0x89,0x6a }, { 0x7b,0xcb,0x84,0x61 }, - { 0x69,0xd0,0x93,0x7c }, { 0x67,0xd9,0x9e,0x77 }, + { 0x69,0xd0,0x93,0x7c }, { 0x67,0xd9,0x9e,0x77 }, { 0x3d,0xae,0xd5,0x1e }, { 0x33,0xa7,0xd8,0x15 }, - { 0x21,0xbc,0xcf,0x08 }, { 0x2f,0xb5,0xc2,0x03 }, + { 0x21,0xbc,0xcf,0x08 }, { 0x2f,0xb5,0xc2,0x03 }, { 0x05,0x8a,0xe1,0x32 }, { 0x0b,0x83,0xec,0x39 }, - { 0x19,0x98,0xfb,0x24 }, { 0x17,0x91,0xf6,0x2f }, + { 0x19,0x98,0xfb,0x24 }, { 0x17,0x91,0xf6,0x2f }, { 0x76,0x4d,0xd6,0x8d }, { 0x78,0x44,0xdb,0x86 }, - { 0x6a,0x5f,0xcc,0x9b }, { 0x64,0x56,0xc1,0x90 }, + { 0x6a,0x5f,0xcc,0x9b }, { 0x64,0x56,0xc1,0x90 }, { 0x4e,0x69,0xe2,0xa1 }, { 0x40,0x60,0xef,0xaa }, - { 0x52,0x7b,0xf8,0xb7 }, { 0x5c,0x72,0xf5,0xbc }, + { 0x52,0x7b,0xf8,0xb7 }, { 0x5c,0x72,0xf5,0xbc }, { 0x06,0x05,0xbe,0xd5 }, { 0x08,0x0c,0xb3,0xde }, - { 0x1a,0x17,0xa4,0xc3 }, { 0x14,0x1e,0xa9,0xc8 }, + { 0x1a,0x17,0xa4,0xc3 }, { 0x14,0x1e,0xa9,0xc8 }, { 0x3e,0x21,0x8a,0xf9 }, { 0x30,0x28,0x87,0xf2 }, - { 0x22,0x33,0x90,0xef }, { 0x2c,0x3a,0x9d,0xe4 }, + { 0x22,0x33,0x90,0xef }, { 0x2c,0x3a,0x9d,0xe4 }, { 0x96,0xdd,0x06,0x3d }, { 0x98,0xd4,0x0b,0x36 }, - { 0x8a,0xcf,0x1c,0x2b }, { 0x84,0xc6,0x11,0x20 }, + { 0x8a,0xcf,0x1c,0x2b }, { 0x84,0xc6,0x11,0x20 }, { 0xae,0xf9,0x32,0x11 }, { 0xa0,0xf0,0x3f,0x1a }, - { 0xb2,0xeb,0x28,0x07 }, { 0xbc,0xe2,0x25,0x0c }, + { 0xb2,0xeb,0x28,0x07 }, { 0xbc,0xe2,0x25,0x0c }, { 0xe6,0x95,0x6e,0x65 }, { 0xe8,0x9c,0x63,0x6e }, - { 0xfa,0x87,0x74,0x73 }, { 0xf4,0x8e,0x79,0x78 }, + { 0xfa,0x87,0x74,0x73 }, { 0xf4,0x8e,0x79,0x78 }, { 0xde,0xb1,0x5a,0x49 }, { 0xd0,0xb8,0x57,0x42 }, - { 0xc2,0xa3,0x40,0x5f }, { 0xcc,0xaa,0x4d,0x54 }, + { 0xc2,0xa3,0x40,0x5f }, { 0xcc,0xaa,0x4d,0x54 }, { 0x41,0xec,0xda,0xf7 }, { 0x4f,0xe5,0xd7,0xfc }, - { 0x5d,0xfe,0xc0,0xe1 }, { 0x53,0xf7,0xcd,0xea }, + { 0x5d,0xfe,0xc0,0xe1 }, { 0x53,0xf7,0xcd,0xea }, { 0x79,0xc8,0xee,0xdb }, { 0x77,0xc1,0xe3,0xd0 }, - { 0x65,0xda,0xf4,0xcd }, { 0x6b,0xd3,0xf9,0xc6 }, + { 0x65,0xda,0xf4,0xcd }, { 0x6b,0xd3,0xf9,0xc6 }, { 0x31,0xa4,0xb2,0xaf }, { 0x3f,0xad,0xbf,0xa4 }, - { 0x2d,0xb6,0xa8,0xb9 }, { 0x23,0xbf,0xa5,0xb2 }, + { 0x2d,0xb6,0xa8,0xb9 }, { 0x23,0xbf,0xa5,0xb2 }, { 0x09,0x80,0x86,0x83 }, { 0x07,0x89,0x8b,0x88 }, - { 0x15,0x92,0x9c,0x95 }, { 0x1b,0x9b,0x91,0x9e }, + { 0x15,0x92,0x9c,0x95 }, { 0x1b,0x9b,0x91,0x9e }, { 0xa1,0x7c,0x0a,0x47 }, { 0xaf,0x75,0x07,0x4c }, - { 0xbd,0x6e,0x10,0x51 }, { 0xb3,0x67,0x1d,0x5a }, + { 0xbd,0x6e,0x10,0x51 }, { 0xb3,0x67,0x1d,0x5a }, { 0x99,0x58,0x3e,0x6b }, { 0x97,0x51,0x33,0x60 }, - { 0x85,0x4a,0x24,0x7d }, { 0x8b,0x43,0x29,0x76 }, + { 0x85,0x4a,0x24,0x7d }, { 0x8b,0x43,0x29,0x76 }, { 0xd1,0x34,0x62,0x1f }, { 0xdf,0x3d,0x6f,0x14 }, - { 0xcd,0x26,0x78,0x09 }, { 0xc3,0x2f,0x75,0x02 }, + { 0xcd,0x26,0x78,0x09 }, { 0xc3,0x2f,0x75,0x02 }, { 0xe9,0x10,0x56,0x33 }, { 0xe7,0x19,0x5b,0x38 }, - { 0xf5,0x02,0x4c,0x25 }, { 0xfb,0x0b,0x41,0x2e }, - { 0x9a,0xd7,0x61,0x8c }, { 0x94,0xde,0x6c,0x87 }, - { 0x86,0xc5,0x7b,0x9a }, { 0x88,0xcc,0x76,0x91 }, + { 0xf5,0x02,0x4c,0x25 }, { 0xfb,0x0b,0x41,0x2e }, + { 0x9a,0xd7,0x61,0x8c }, { 0x94,0xde,0x6c,0x87 }, + { 0x86,0xc5,0x7b,0x9a }, { 0x88,0xcc,0x76,0x91 }, { 0xa2,0xf3,0x55,0xa0 }, { 0xac,0xfa,0x58,0xab }, - { 0xbe,0xe1,0x4f,0xb6 }, { 0xb0,0xe8,0x42,0xbd }, + { 0xbe,0xe1,0x4f,0xb6 }, { 0xb0,0xe8,0x42,0xbd }, { 0xea,0x9f,0x09,0xd4 }, { 0xe4,0x96,0x04,0xdf }, - { 0xf6,0x8d,0x13,0xc2 }, { 0xf8,0x84,0x1e,0xc9 }, + { 0xf6,0x8d,0x13,0xc2 }, { 0xf8,0x84,0x1e,0xc9 }, { 0xd2,0xbb,0x3d,0xf8 }, { 0xdc,0xb2,0x30,0xf3 }, - { 0xce,0xa9,0x27,0xee }, { 0xc0,0xa0,0x2a,0xe5 }, - { 0x7a,0x47,0xb1,0x3c }, { 0x74,0x4e,0xbc,0x37 }, - { 0x66,0x55,0xab,0x2a }, { 0x68,0x5c,0xa6,0x21 }, + { 0xce,0xa9,0x27,0xee }, { 0xc0,0xa0,0x2a,0xe5 }, + { 0x7a,0x47,0xb1,0x3c }, { 0x74,0x4e,0xbc,0x37 }, + { 0x66,0x55,0xab,0x2a }, { 0x68,0x5c,0xa6,0x21 }, { 0x42,0x63,0x85,0x10 }, { 0x4c,0x6a,0x88,0x1b }, - { 0x5e,0x71,0x9f,0x06 }, { 0x50,0x78,0x92,0x0d }, + { 0x5e,0x71,0x9f,0x06 }, { 0x50,0x78,0x92,0x0d }, { 0x0a,0x0f,0xd9,0x64 }, { 0x04,0x06,0xd4,0x6f }, - { 0x16,0x1d,0xc3,0x72 }, { 0x18,0x14,0xce,0x79 }, + { 0x16,0x1d,0xc3,0x72 }, { 0x18,0x14,0xce,0x79 }, { 0x32,0x2b,0xed,0x48 }, { 0x3c,0x22,0xe0,0x43 }, - { 0x2e,0x39,0xf7,0x5e }, { 0x20,0x30,0xfa,0x55 }, + { 0x2e,0x39,0xf7,0x5e }, { 0x20,0x30,0xfa,0x55 }, { 0xec,0x9a,0xb7,0x01 }, { 0xe2,0x93,0xba,0x0a }, - { 0xf0,0x88,0xad,0x17 }, { 0xfe,0x81,0xa0,0x1c }, + { 0xf0,0x88,0xad,0x17 }, { 0xfe,0x81,0xa0,0x1c }, { 0xd4,0xbe,0x83,0x2d }, { 0xda,0xb7,0x8e,0x26 }, - { 0xc8,0xac,0x99,0x3b }, { 0xc6,0xa5,0x94,0x30 }, + { 0xc8,0xac,0x99,0x3b }, { 0xc6,0xa5,0x94,0x30 }, { 0x9c,0xd2,0xdf,0x59 }, { 0x92,0xdb,0xd2,0x52 }, - { 0x80,0xc0,0xc5,0x4f }, { 0x8e,0xc9,0xc8,0x44 }, + { 0x80,0xc0,0xc5,0x4f }, { 0x8e,0xc9,0xc8,0x44 }, { 0xa4,0xf6,0xeb,0x75 }, { 0xaa,0xff,0xe6,0x7e }, - { 0xb8,0xe4,0xf1,0x63 }, { 0xb6,0xed,0xfc,0x68 }, + { 0xb8,0xe4,0xf1,0x63 }, { 0xb6,0xed,0xfc,0x68 }, { 0x0c,0x0a,0x67,0xb1 }, { 0x02,0x03,0x6a,0xba }, - { 0x10,0x18,0x7d,0xa7 }, { 0x1e,0x11,0x70,0xac }, + { 0x10,0x18,0x7d,0xa7 }, { 0x1e,0x11,0x70,0xac }, { 0x34,0x2e,0x53,0x9d }, { 0x3a,0x27,0x5e,0x96 }, - { 0x28,0x3c,0x49,0x8b }, { 0x26,0x35,0x44,0x80 }, + { 0x28,0x3c,0x49,0x8b }, { 0x26,0x35,0x44,0x80 }, { 0x7c,0x42,0x0f,0xe9 }, { 0x72,0x4b,0x02,0xe2 }, - { 0x60,0x50,0x15,0xff }, { 0x6e,0x59,0x18,0xf4 }, + { 0x60,0x50,0x15,0xff }, { 0x6e,0x59,0x18,0xf4 }, { 0x44,0x66,0x3b,0xc5 }, { 0x4a,0x6f,0x36,0xce }, - { 0x58,0x74,0x21,0xd3 }, { 0x56,0x7d,0x2c,0xd8 }, + { 0x58,0x74,0x21,0xd3 }, { 0x56,0x7d,0x2c,0xd8 }, { 0x37,0xa1,0x0c,0x7a }, { 0x39,0xa8,0x01,0x71 }, - { 0x2b,0xb3,0x16,0x6c }, { 0x25,0xba,0x1b,0x67 }, + { 0x2b,0xb3,0x16,0x6c }, { 0x25,0xba,0x1b,0x67 }, { 0x0f,0x85,0x38,0x56 }, { 0x01,0x8c,0x35,0x5d }, - { 0x13,0x97,0x22,0x40 }, { 0x1d,0x9e,0x2f,0x4b }, + { 0x13,0x97,0x22,0x40 }, { 0x1d,0x9e,0x2f,0x4b }, { 0x47,0xe9,0x64,0x22 }, { 0x49,0xe0,0x69,0x29 }, - { 0x5b,0xfb,0x7e,0x34 }, { 0x55,0xf2,0x73,0x3f }, + { 0x5b,0xfb,0x7e,0x34 }, { 0x55,0xf2,0x73,0x3f }, { 0x7f,0xcd,0x50,0x0e }, { 0x71,0xc4,0x5d,0x05 }, - { 0x63,0xdf,0x4a,0x18 }, { 0x6d,0xd6,0x47,0x13 }, + { 0x63,0xdf,0x4a,0x18 }, { 0x6d,0xd6,0x47,0x13 }, { 0xd7,0x31,0xdc,0xca }, { 0xd9,0x38,0xd1,0xc1 }, - { 0xcb,0x23,0xc6,0xdc }, { 0xc5,0x2a,0xcb,0xd7 }, + { 0xcb,0x23,0xc6,0xdc }, { 0xc5,0x2a,0xcb,0xd7 }, { 0xef,0x15,0xe8,0xe6 }, { 0xe1,0x1c,0xe5,0xed }, - { 0xf3,0x07,0xf2,0xf0 }, { 0xfd,0x0e,0xff,0xfb }, + { 0xf3,0x07,0xf2,0xf0 }, { 0xfd,0x0e,0xff,0xfb }, { 0xa7,0x79,0xb4,0x92 }, { 0xa9,0x70,0xb9,0x99 }, - { 0xbb,0x6b,0xae,0x84 }, { 0xb5,0x62,0xa3,0x8f }, + { 0xbb,0x6b,0xae,0x84 }, { 0xb5,0x62,0xa3,0x8f }, { 0x9f,0x5d,0x80,0xbe }, { 0x91,0x54,0x8d,0xb5 }, { 0x83,0x4f,0x9a,0xa8 }, { 0x8d,0x46,0x97,0xa3 } }; -static const unsigned char U2[256][4] = +static const unsigned char U2[256][4] = { { 0x00,0x00,0x00,0x00 }, { 0x0b,0x0e,0x09,0x0d }, - { 0x16,0x1c,0x12,0x1a }, { 0x1d,0x12,0x1b,0x17 }, + { 0x16,0x1c,0x12,0x1a }, { 0x1d,0x12,0x1b,0x17 }, { 0x2c,0x38,0x24,0x34 }, { 0x27,0x36,0x2d,0x39 }, - { 0x3a,0x24,0x36,0x2e }, { 0x31,0x2a,0x3f,0x23 }, - { 0x58,0x70,0x48,0x68 }, { 0x53,0x7e,0x41,0x65 }, - { 0x4e,0x6c,0x5a,0x72 }, { 0x45,0x62,0x53,0x7f }, + { 0x3a,0x24,0x36,0x2e }, { 0x31,0x2a,0x3f,0x23 }, + { 0x58,0x70,0x48,0x68 }, { 0x53,0x7e,0x41,0x65 }, + { 0x4e,0x6c,0x5a,0x72 }, { 0x45,0x62,0x53,0x7f }, { 0x74,0x48,0x6c,0x5c }, { 0x7f,0x46,0x65,0x51 }, - { 0x62,0x54,0x7e,0x46 }, { 0x69,0x5a,0x77,0x4b }, - { 0xb0,0xe0,0x90,0xd0 }, { 0xbb,0xee,0x99,0xdd }, - { 0xa6,0xfc,0x82,0xca }, { 0xad,0xf2,0x8b,0xc7 }, - { 0x9c,0xd8,0xb4,0xe4 }, { 0x97,0xd6,0xbd,0xe9 }, - { 0x8a,0xc4,0xa6,0xfe }, { 0x81,0xca,0xaf,0xf3 }, + { 0x62,0x54,0x7e,0x46 }, { 0x69,0x5a,0x77,0x4b }, + { 0xb0,0xe0,0x90,0xd0 }, { 0xbb,0xee,0x99,0xdd }, + { 0xa6,0xfc,0x82,0xca }, { 0xad,0xf2,0x8b,0xc7 }, + { 0x9c,0xd8,0xb4,0xe4 }, { 0x97,0xd6,0xbd,0xe9 }, + { 0x8a,0xc4,0xa6,0xfe }, { 0x81,0xca,0xaf,0xf3 }, { 0xe8,0x90,0xd8,0xb8 }, { 0xe3,0x9e,0xd1,0xb5 }, - { 0xfe,0x8c,0xca,0xa2 }, { 0xf5,0x82,0xc3,0xaf }, - { 0xc4,0xa8,0xfc,0x8c }, { 0xcf,0xa6,0xf5,0x81 }, - { 0xd2,0xb4,0xee,0x96 }, { 0xd9,0xba,0xe7,0x9b }, - { 0x7b,0xdb,0x3b,0xbb }, { 0x70,0xd5,0x32,0xb6 }, - { 0x6d,0xc7,0x29,0xa1 }, { 0x66,0xc9,0x20,0xac }, - { 0x57,0xe3,0x1f,0x8f }, { 0x5c,0xed,0x16,0x82 }, - { 0x41,0xff,0x0d,0x95 }, { 0x4a,0xf1,0x04,0x98 }, + { 0xfe,0x8c,0xca,0xa2 }, { 0xf5,0x82,0xc3,0xaf }, + { 0xc4,0xa8,0xfc,0x8c }, { 0xcf,0xa6,0xf5,0x81 }, + { 0xd2,0xb4,0xee,0x96 }, { 0xd9,0xba,0xe7,0x9b }, + { 0x7b,0xdb,0x3b,0xbb }, { 0x70,0xd5,0x32,0xb6 }, + { 0x6d,0xc7,0x29,0xa1 }, { 0x66,0xc9,0x20,0xac }, + { 0x57,0xe3,0x1f,0x8f }, { 0x5c,0xed,0x16,0x82 }, + { 0x41,0xff,0x0d,0x95 }, { 0x4a,0xf1,0x04,0x98 }, { 0x23,0xab,0x73,0xd3 }, { 0x28,0xa5,0x7a,0xde }, - { 0x35,0xb7,0x61,0xc9 }, { 0x3e,0xb9,0x68,0xc4 }, + { 0x35,0xb7,0x61,0xc9 }, { 0x3e,0xb9,0x68,0xc4 }, { 0x0f,0x93,0x57,0xe7 }, { 0x04,0x9d,0x5e,0xea }, - { 0x19,0x8f,0x45,0xfd }, { 0x12,0x81,0x4c,0xf0 }, + { 0x19,0x8f,0x45,0xfd }, { 0x12,0x81,0x4c,0xf0 }, { 0xcb,0x3b,0xab,0x6b }, { 0xc0,0x35,0xa2,0x66 }, - { 0xdd,0x27,0xb9,0x71 }, { 0xd6,0x29,0xb0,0x7c }, + { 0xdd,0x27,0xb9,0x71 }, { 0xd6,0x29,0xb0,0x7c }, { 0xe7,0x03,0x8f,0x5f }, { 0xec,0x0d,0x86,0x52 }, - { 0xf1,0x1f,0x9d,0x45 }, { 0xfa,0x11,0x94,0x48 }, - { 0x93,0x4b,0xe3,0x03 }, { 0x98,0x45,0xea,0x0e }, - { 0x85,0x57,0xf1,0x19 }, { 0x8e,0x59,0xf8,0x14 }, + { 0xf1,0x1f,0x9d,0x45 }, { 0xfa,0x11,0x94,0x48 }, + { 0x93,0x4b,0xe3,0x03 }, { 0x98,0x45,0xea,0x0e }, + { 0x85,0x57,0xf1,0x19 }, { 0x8e,0x59,0xf8,0x14 }, { 0xbf,0x73,0xc7,0x37 }, { 0xb4,0x7d,0xce,0x3a }, - { 0xa9,0x6f,0xd5,0x2d }, { 0xa2,0x61,0xdc,0x20 }, - { 0xf6,0xad,0x76,0x6d }, { 0xfd,0xa3,0x7f,0x60 }, - { 0xe0,0xb1,0x64,0x77 }, { 0xeb,0xbf,0x6d,0x7a }, - { 0xda,0x95,0x52,0x59 }, { 0xd1,0x9b,0x5b,0x54 }, - { 0xcc,0x89,0x40,0x43 }, { 0xc7,0x87,0x49,0x4e }, + { 0xa9,0x6f,0xd5,0x2d }, { 0xa2,0x61,0xdc,0x20 }, + { 0xf6,0xad,0x76,0x6d }, { 0xfd,0xa3,0x7f,0x60 }, + { 0xe0,0xb1,0x64,0x77 }, { 0xeb,0xbf,0x6d,0x7a }, + { 0xda,0x95,0x52,0x59 }, { 0xd1,0x9b,0x5b,0x54 }, + { 0xcc,0x89,0x40,0x43 }, { 0xc7,0x87,0x49,0x4e }, { 0xae,0xdd,0x3e,0x05 }, { 0xa5,0xd3,0x37,0x08 }, - { 0xb8,0xc1,0x2c,0x1f }, { 0xb3,0xcf,0x25,0x12 }, + { 0xb8,0xc1,0x2c,0x1f }, { 0xb3,0xcf,0x25,0x12 }, { 0x82,0xe5,0x1a,0x31 }, { 0x89,0xeb,0x13,0x3c }, - { 0x94,0xf9,0x08,0x2b }, { 0x9f,0xf7,0x01,0x26 }, + { 0x94,0xf9,0x08,0x2b }, { 0x9f,0xf7,0x01,0x26 }, { 0x46,0x4d,0xe6,0xbd }, { 0x4d,0x43,0xef,0xb0 }, - { 0x50,0x51,0xf4,0xa7 }, { 0x5b,0x5f,0xfd,0xaa }, + { 0x50,0x51,0xf4,0xa7 }, { 0x5b,0x5f,0xfd,0xaa }, { 0x6a,0x75,0xc2,0x89 }, { 0x61,0x7b,0xcb,0x84 }, - { 0x7c,0x69,0xd0,0x93 }, { 0x77,0x67,0xd9,0x9e }, + { 0x7c,0x69,0xd0,0x93 }, { 0x77,0x67,0xd9,0x9e }, { 0x1e,0x3d,0xae,0xd5 }, { 0x15,0x33,0xa7,0xd8 }, - { 0x08,0x21,0xbc,0xcf }, { 0x03,0x2f,0xb5,0xc2 }, + { 0x08,0x21,0xbc,0xcf }, { 0x03,0x2f,0xb5,0xc2 }, { 0x32,0x05,0x8a,0xe1 }, { 0x39,0x0b,0x83,0xec }, - { 0x24,0x19,0x98,0xfb }, { 0x2f,0x17,0x91,0xf6 }, + { 0x24,0x19,0x98,0xfb }, { 0x2f,0x17,0x91,0xf6 }, { 0x8d,0x76,0x4d,0xd6 }, { 0x86,0x78,0x44,0xdb }, - { 0x9b,0x6a,0x5f,0xcc }, { 0x90,0x64,0x56,0xc1 }, + { 0x9b,0x6a,0x5f,0xcc }, { 0x90,0x64,0x56,0xc1 }, { 0xa1,0x4e,0x69,0xe2 }, { 0xaa,0x40,0x60,0xef }, - { 0xb7,0x52,0x7b,0xf8 }, { 0xbc,0x5c,0x72,0xf5 }, + { 0xb7,0x52,0x7b,0xf8 }, { 0xbc,0x5c,0x72,0xf5 }, { 0xd5,0x06,0x05,0xbe }, { 0xde,0x08,0x0c,0xb3 }, - { 0xc3,0x1a,0x17,0xa4 }, { 0xc8,0x14,0x1e,0xa9 }, + { 0xc3,0x1a,0x17,0xa4 }, { 0xc8,0x14,0x1e,0xa9 }, { 0xf9,0x3e,0x21,0x8a }, { 0xf2,0x30,0x28,0x87 }, - { 0xef,0x22,0x33,0x90 }, { 0xe4,0x2c,0x3a,0x9d }, + { 0xef,0x22,0x33,0x90 }, { 0xe4,0x2c,0x3a,0x9d }, { 0x3d,0x96,0xdd,0x06 }, { 0x36,0x98,0xd4,0x0b }, - { 0x2b,0x8a,0xcf,0x1c }, { 0x20,0x84,0xc6,0x11 }, + { 0x2b,0x8a,0xcf,0x1c }, { 0x20,0x84,0xc6,0x11 }, { 0x11,0xae,0xf9,0x32 }, { 0x1a,0xa0,0xf0,0x3f }, - { 0x07,0xb2,0xeb,0x28 }, { 0x0c,0xbc,0xe2,0x25 }, + { 0x07,0xb2,0xeb,0x28 }, { 0x0c,0xbc,0xe2,0x25 }, { 0x65,0xe6,0x95,0x6e }, { 0x6e,0xe8,0x9c,0x63 }, - { 0x73,0xfa,0x87,0x74 }, { 0x78,0xf4,0x8e,0x79 }, + { 0x73,0xfa,0x87,0x74 }, { 0x78,0xf4,0x8e,0x79 }, { 0x49,0xde,0xb1,0x5a }, { 0x42,0xd0,0xb8,0x57 }, - { 0x5f,0xc2,0xa3,0x40 }, { 0x54,0xcc,0xaa,0x4d }, + { 0x5f,0xc2,0xa3,0x40 }, { 0x54,0xcc,0xaa,0x4d }, { 0xf7,0x41,0xec,0xda }, { 0xfc,0x4f,0xe5,0xd7 }, - { 0xe1,0x5d,0xfe,0xc0 }, { 0xea,0x53,0xf7,0xcd }, + { 0xe1,0x5d,0xfe,0xc0 }, { 0xea,0x53,0xf7,0xcd }, { 0xdb,0x79,0xc8,0xee }, { 0xd0,0x77,0xc1,0xe3 }, - { 0xcd,0x65,0xda,0xf4 }, { 0xc6,0x6b,0xd3,0xf9 }, + { 0xcd,0x65,0xda,0xf4 }, { 0xc6,0x6b,0xd3,0xf9 }, { 0xaf,0x31,0xa4,0xb2 }, { 0xa4,0x3f,0xad,0xbf }, - { 0xb9,0x2d,0xb6,0xa8 }, { 0xb2,0x23,0xbf,0xa5 }, + { 0xb9,0x2d,0xb6,0xa8 }, { 0xb2,0x23,0xbf,0xa5 }, { 0x83,0x09,0x80,0x86 }, { 0x88,0x07,0x89,0x8b }, - { 0x95,0x15,0x92,0x9c }, { 0x9e,0x1b,0x9b,0x91 }, + { 0x95,0x15,0x92,0x9c }, { 0x9e,0x1b,0x9b,0x91 }, { 0x47,0xa1,0x7c,0x0a }, { 0x4c,0xaf,0x75,0x07 }, - { 0x51,0xbd,0x6e,0x10 }, { 0x5a,0xb3,0x67,0x1d }, + { 0x51,0xbd,0x6e,0x10 }, { 0x5a,0xb3,0x67,0x1d }, { 0x6b,0x99,0x58,0x3e }, { 0x60,0x97,0x51,0x33 }, - { 0x7d,0x85,0x4a,0x24 }, { 0x76,0x8b,0x43,0x29 }, + { 0x7d,0x85,0x4a,0x24 }, { 0x76,0x8b,0x43,0x29 }, { 0x1f,0xd1,0x34,0x62 }, { 0x14,0xdf,0x3d,0x6f }, - { 0x09,0xcd,0x26,0x78 }, { 0x02,0xc3,0x2f,0x75 }, + { 0x09,0xcd,0x26,0x78 }, { 0x02,0xc3,0x2f,0x75 }, { 0x33,0xe9,0x10,0x56 }, { 0x38,0xe7,0x19,0x5b }, - { 0x25,0xf5,0x02,0x4c }, { 0x2e,0xfb,0x0b,0x41 }, + { 0x25,0xf5,0x02,0x4c }, { 0x2e,0xfb,0x0b,0x41 }, { 0x8c,0x9a,0xd7,0x61 }, { 0x87,0x94,0xde,0x6c }, - { 0x9a,0x86,0xc5,0x7b }, { 0x91,0x88,0xcc,0x76 }, + { 0x9a,0x86,0xc5,0x7b }, { 0x91,0x88,0xcc,0x76 }, { 0xa0,0xa2,0xf3,0x55 }, { 0xab,0xac,0xfa,0x58 }, - { 0xb6,0xbe,0xe1,0x4f }, { 0xbd,0xb0,0xe8,0x42 }, + { 0xb6,0xbe,0xe1,0x4f }, { 0xbd,0xb0,0xe8,0x42 }, { 0xd4,0xea,0x9f,0x09 }, { 0xdf,0xe4,0x96,0x04 }, - { 0xc2,0xf6,0x8d,0x13 }, { 0xc9,0xf8,0x84,0x1e }, + { 0xc2,0xf6,0x8d,0x13 }, { 0xc9,0xf8,0x84,0x1e }, { 0xf8,0xd2,0xbb,0x3d }, { 0xf3,0xdc,0xb2,0x30 }, - { 0xee,0xce,0xa9,0x27 }, { 0xe5,0xc0,0xa0,0x2a }, + { 0xee,0xce,0xa9,0x27 }, { 0xe5,0xc0,0xa0,0x2a }, { 0x3c,0x7a,0x47,0xb1 }, { 0x37,0x74,0x4e,0xbc }, - { 0x2a,0x66,0x55,0xab }, { 0x21,0x68,0x5c,0xa6 }, + { 0x2a,0x66,0x55,0xab }, { 0x21,0x68,0x5c,0xa6 }, { 0x10,0x42,0x63,0x85 }, { 0x1b,0x4c,0x6a,0x88 }, - { 0x06,0x5e,0x71,0x9f }, { 0x0d,0x50,0x78,0x92 }, + { 0x06,0x5e,0x71,0x9f }, { 0x0d,0x50,0x78,0x92 }, { 0x64,0x0a,0x0f,0xd9 }, { 0x6f,0x04,0x06,0xd4 }, - { 0x72,0x16,0x1d,0xc3 }, { 0x79,0x18,0x14,0xce }, + { 0x72,0x16,0x1d,0xc3 }, { 0x79,0x18,0x14,0xce }, { 0x48,0x32,0x2b,0xed }, { 0x43,0x3c,0x22,0xe0 }, - { 0x5e,0x2e,0x39,0xf7 }, { 0x55,0x20,0x30,0xfa }, + { 0x5e,0x2e,0x39,0xf7 }, { 0x55,0x20,0x30,0xfa }, { 0x01,0xec,0x9a,0xb7 }, { 0x0a,0xe2,0x93,0xba }, - { 0x17,0xf0,0x88,0xad }, { 0x1c,0xfe,0x81,0xa0 }, + { 0x17,0xf0,0x88,0xad }, { 0x1c,0xfe,0x81,0xa0 }, { 0x2d,0xd4,0xbe,0x83 }, { 0x26,0xda,0xb7,0x8e }, - { 0x3b,0xc8,0xac,0x99 }, { 0x30,0xc6,0xa5,0x94 }, + { 0x3b,0xc8,0xac,0x99 }, { 0x30,0xc6,0xa5,0x94 }, { 0x59,0x9c,0xd2,0xdf }, { 0x52,0x92,0xdb,0xd2 }, - { 0x4f,0x80,0xc0,0xc5 }, { 0x44,0x8e,0xc9,0xc8 }, + { 0x4f,0x80,0xc0,0xc5 }, { 0x44,0x8e,0xc9,0xc8 }, { 0x75,0xa4,0xf6,0xeb }, { 0x7e,0xaa,0xff,0xe6 }, - { 0x63,0xb8,0xe4,0xf1 }, { 0x68,0xb6,0xed,0xfc }, + { 0x63,0xb8,0xe4,0xf1 }, { 0x68,0xb6,0xed,0xfc }, { 0xb1,0x0c,0x0a,0x67 }, { 0xba,0x02,0x03,0x6a }, - { 0xa7,0x10,0x18,0x7d }, { 0xac,0x1e,0x11,0x70 }, + { 0xa7,0x10,0x18,0x7d }, { 0xac,0x1e,0x11,0x70 }, { 0x9d,0x34,0x2e,0x53 }, { 0x96,0x3a,0x27,0x5e }, - { 0x8b,0x28,0x3c,0x49 }, { 0x80,0x26,0x35,0x44 }, + { 0x8b,0x28,0x3c,0x49 }, { 0x80,0x26,0x35,0x44 }, { 0xe9,0x7c,0x42,0x0f }, { 0xe2,0x72,0x4b,0x02 }, - { 0xff,0x60,0x50,0x15 }, { 0xf4,0x6e,0x59,0x18 }, + { 0xff,0x60,0x50,0x15 }, { 0xf4,0x6e,0x59,0x18 }, { 0xc5,0x44,0x66,0x3b }, { 0xce,0x4a,0x6f,0x36 }, - { 0xd3,0x58,0x74,0x21 }, { 0xd8,0x56,0x7d,0x2c }, + { 0xd3,0x58,0x74,0x21 }, { 0xd8,0x56,0x7d,0x2c }, { 0x7a,0x37,0xa1,0x0c }, { 0x71,0x39,0xa8,0x01 }, - { 0x6c,0x2b,0xb3,0x16 }, { 0x67,0x25,0xba,0x1b }, + { 0x6c,0x2b,0xb3,0x16 }, { 0x67,0x25,0xba,0x1b }, { 0x56,0x0f,0x85,0x38 }, { 0x5d,0x01,0x8c,0x35 }, - { 0x40,0x13,0x97,0x22 }, { 0x4b,0x1d,0x9e,0x2f }, + { 0x40,0x13,0x97,0x22 }, { 0x4b,0x1d,0x9e,0x2f }, { 0x22,0x47,0xe9,0x64 }, { 0x29,0x49,0xe0,0x69 }, - { 0x34,0x5b,0xfb,0x7e }, { 0x3f,0x55,0xf2,0x73 }, + { 0x34,0x5b,0xfb,0x7e }, { 0x3f,0x55,0xf2,0x73 }, { 0x0e,0x7f,0xcd,0x50 }, { 0x05,0x71,0xc4,0x5d }, - { 0x18,0x63,0xdf,0x4a }, { 0x13,0x6d,0xd6,0x47 }, + { 0x18,0x63,0xdf,0x4a }, { 0x13,0x6d,0xd6,0x47 }, { 0xca,0xd7,0x31,0xdc }, { 0xc1,0xd9,0x38,0xd1 }, - { 0xdc,0xcb,0x23,0xc6 }, { 0xd7,0xc5,0x2a,0xcb }, + { 0xdc,0xcb,0x23,0xc6 }, { 0xd7,0xc5,0x2a,0xcb }, { 0xe6,0xef,0x15,0xe8 }, { 0xed,0xe1,0x1c,0xe5 }, - { 0xf0,0xf3,0x07,0xf2 }, { 0xfb,0xfd,0x0e,0xff }, + { 0xf0,0xf3,0x07,0xf2 }, { 0xfb,0xfd,0x0e,0xff }, { 0x92,0xa7,0x79,0xb4 }, { 0x99,0xa9,0x70,0xb9 }, - { 0x84,0xbb,0x6b,0xae }, { 0x8f,0xb5,0x62,0xa3 }, + { 0x84,0xbb,0x6b,0xae }, { 0x8f,0xb5,0x62,0xa3 }, { 0xbe,0x9f,0x5d,0x80 }, { 0xb5,0x91,0x54,0x8d }, { 0xa8,0x83,0x4f,0x9a }, { 0xa3,0x8d,0x46,0x97 } }; -static const unsigned char U3[256][4] = +static const unsigned char U3[256][4] = { { 0x00,0x00,0x00,0x00 }, { 0x0d,0x0b,0x0e,0x09 }, - { 0x1a,0x16,0x1c,0x12 }, { 0x17,0x1d,0x12,0x1b }, + { 0x1a,0x16,0x1c,0x12 }, { 0x17,0x1d,0x12,0x1b }, { 0x34,0x2c,0x38,0x24 }, { 0x39,0x27,0x36,0x2d }, - { 0x2e,0x3a,0x24,0x36 }, { 0x23,0x31,0x2a,0x3f }, + { 0x2e,0x3a,0x24,0x36 }, { 0x23,0x31,0x2a,0x3f }, { 0x68,0x58,0x70,0x48 }, { 0x65,0x53,0x7e,0x41 }, - { 0x72,0x4e,0x6c,0x5a }, { 0x7f,0x45,0x62,0x53 }, + { 0x72,0x4e,0x6c,0x5a }, { 0x7f,0x45,0x62,0x53 }, { 0x5c,0x74,0x48,0x6c }, { 0x51,0x7f,0x46,0x65 }, - { 0x46,0x62,0x54,0x7e }, { 0x4b,0x69,0x5a,0x77 }, + { 0x46,0x62,0x54,0x7e }, { 0x4b,0x69,0x5a,0x77 }, { 0xd0,0xb0,0xe0,0x90 }, { 0xdd,0xbb,0xee,0x99 }, - { 0xca,0xa6,0xfc,0x82 }, { 0xc7,0xad,0xf2,0x8b }, + { 0xca,0xa6,0xfc,0x82 }, { 0xc7,0xad,0xf2,0x8b }, { 0xe4,0x9c,0xd8,0xb4 }, { 0xe9,0x97,0xd6,0xbd }, - { 0xfe,0x8a,0xc4,0xa6 }, { 0xf3,0x81,0xca,0xaf }, + { 0xfe,0x8a,0xc4,0xa6 }, { 0xf3,0x81,0xca,0xaf }, { 0xb8,0xe8,0x90,0xd8 }, { 0xb5,0xe3,0x9e,0xd1 }, - { 0xa2,0xfe,0x8c,0xca }, { 0xaf,0xf5,0x82,0xc3 }, + { 0xa2,0xfe,0x8c,0xca }, { 0xaf,0xf5,0x82,0xc3 }, { 0x8c,0xc4,0xa8,0xfc }, { 0x81,0xcf,0xa6,0xf5 }, - { 0x96,0xd2,0xb4,0xee }, { 0x9b,0xd9,0xba,0xe7 }, + { 0x96,0xd2,0xb4,0xee }, { 0x9b,0xd9,0xba,0xe7 }, { 0xbb,0x7b,0xdb,0x3b }, { 0xb6,0x70,0xd5,0x32 }, - { 0xa1,0x6d,0xc7,0x29 }, { 0xac,0x66,0xc9,0x20 }, + { 0xa1,0x6d,0xc7,0x29 }, { 0xac,0x66,0xc9,0x20 }, { 0x8f,0x57,0xe3,0x1f }, { 0x82,0x5c,0xed,0x16 }, - { 0x95,0x41,0xff,0x0d }, { 0x98,0x4a,0xf1,0x04 }, + { 0x95,0x41,0xff,0x0d }, { 0x98,0x4a,0xf1,0x04 }, { 0xd3,0x23,0xab,0x73 }, { 0xde,0x28,0xa5,0x7a }, - { 0xc9,0x35,0xb7,0x61 }, { 0xc4,0x3e,0xb9,0x68 }, + { 0xc9,0x35,0xb7,0x61 }, { 0xc4,0x3e,0xb9,0x68 }, { 0xe7,0x0f,0x93,0x57 }, { 0xea,0x04,0x9d,0x5e }, - { 0xfd,0x19,0x8f,0x45 }, { 0xf0,0x12,0x81,0x4c }, + { 0xfd,0x19,0x8f,0x45 }, { 0xf0,0x12,0x81,0x4c }, { 0x6b,0xcb,0x3b,0xab }, { 0x66,0xc0,0x35,0xa2 }, - { 0x71,0xdd,0x27,0xb9 }, { 0x7c,0xd6,0x29,0xb0 }, + { 0x71,0xdd,0x27,0xb9 }, { 0x7c,0xd6,0x29,0xb0 }, { 0x5f,0xe7,0x03,0x8f }, { 0x52,0xec,0x0d,0x86 }, - { 0x45,0xf1,0x1f,0x9d }, { 0x48,0xfa,0x11,0x94 }, + { 0x45,0xf1,0x1f,0x9d }, { 0x48,0xfa,0x11,0x94 }, { 0x03,0x93,0x4b,0xe3 }, { 0x0e,0x98,0x45,0xea }, - { 0x19,0x85,0x57,0xf1 }, { 0x14,0x8e,0x59,0xf8 }, - { 0x37,0xbf,0x73,0xc7 }, { 0x3a,0xb4,0x7d,0xce }, - { 0x2d,0xa9,0x6f,0xd5 }, { 0x20,0xa2,0x61,0xdc }, + { 0x19,0x85,0x57,0xf1 }, { 0x14,0x8e,0x59,0xf8 }, + { 0x37,0xbf,0x73,0xc7 }, { 0x3a,0xb4,0x7d,0xce }, + { 0x2d,0xa9,0x6f,0xd5 }, { 0x20,0xa2,0x61,0xdc }, { 0x6d,0xf6,0xad,0x76 }, { 0x60,0xfd,0xa3,0x7f }, - { 0x77,0xe0,0xb1,0x64 }, { 0x7a,0xeb,0xbf,0x6d }, + { 0x77,0xe0,0xb1,0x64 }, { 0x7a,0xeb,0xbf,0x6d }, { 0x59,0xda,0x95,0x52 }, { 0x54,0xd1,0x9b,0x5b }, - { 0x43,0xcc,0x89,0x40 }, { 0x4e,0xc7,0x87,0x49 }, + { 0x43,0xcc,0x89,0x40 }, { 0x4e,0xc7,0x87,0x49 }, { 0x05,0xae,0xdd,0x3e }, { 0x08,0xa5,0xd3,0x37 }, - { 0x1f,0xb8,0xc1,0x2c }, { 0x12,0xb3,0xcf,0x25 }, - { 0x31,0x82,0xe5,0x1a }, { 0x3c,0x89,0xeb,0x13 }, - { 0x2b,0x94,0xf9,0x08 }, { 0x26,0x9f,0xf7,0x01 }, - { 0xbd,0x46,0x4d,0xe6 }, { 0xb0,0x4d,0x43,0xef }, - { 0xa7,0x50,0x51,0xf4 }, { 0xaa,0x5b,0x5f,0xfd }, - { 0x89,0x6a,0x75,0xc2 }, { 0x84,0x61,0x7b,0xcb }, - { 0x93,0x7c,0x69,0xd0 }, { 0x9e,0x77,0x67,0xd9 }, + { 0x1f,0xb8,0xc1,0x2c }, { 0x12,0xb3,0xcf,0x25 }, + { 0x31,0x82,0xe5,0x1a }, { 0x3c,0x89,0xeb,0x13 }, + { 0x2b,0x94,0xf9,0x08 }, { 0x26,0x9f,0xf7,0x01 }, + { 0xbd,0x46,0x4d,0xe6 }, { 0xb0,0x4d,0x43,0xef }, + { 0xa7,0x50,0x51,0xf4 }, { 0xaa,0x5b,0x5f,0xfd }, + { 0x89,0x6a,0x75,0xc2 }, { 0x84,0x61,0x7b,0xcb }, + { 0x93,0x7c,0x69,0xd0 }, { 0x9e,0x77,0x67,0xd9 }, { 0xd5,0x1e,0x3d,0xae }, { 0xd8,0x15,0x33,0xa7 }, - { 0xcf,0x08,0x21,0xbc }, { 0xc2,0x03,0x2f,0xb5 }, + { 0xcf,0x08,0x21,0xbc }, { 0xc2,0x03,0x2f,0xb5 }, { 0xe1,0x32,0x05,0x8a }, { 0xec,0x39,0x0b,0x83 }, - { 0xfb,0x24,0x19,0x98 }, { 0xf6,0x2f,0x17,0x91 }, - { 0xd6,0x8d,0x76,0x4d }, { 0xdb,0x86,0x78,0x44 }, - { 0xcc,0x9b,0x6a,0x5f }, { 0xc1,0x90,0x64,0x56 }, - { 0xe2,0xa1,0x4e,0x69 }, { 0xef,0xaa,0x40,0x60 }, - { 0xf8,0xb7,0x52,0x7b }, { 0xf5,0xbc,0x5c,0x72 }, - { 0xbe,0xd5,0x06,0x05 }, { 0xb3,0xde,0x08,0x0c }, - { 0xa4,0xc3,0x1a,0x17 }, { 0xa9,0xc8,0x14,0x1e }, + { 0xfb,0x24,0x19,0x98 }, { 0xf6,0x2f,0x17,0x91 }, + { 0xd6,0x8d,0x76,0x4d }, { 0xdb,0x86,0x78,0x44 }, + { 0xcc,0x9b,0x6a,0x5f }, { 0xc1,0x90,0x64,0x56 }, + { 0xe2,0xa1,0x4e,0x69 }, { 0xef,0xaa,0x40,0x60 }, + { 0xf8,0xb7,0x52,0x7b }, { 0xf5,0xbc,0x5c,0x72 }, + { 0xbe,0xd5,0x06,0x05 }, { 0xb3,0xde,0x08,0x0c }, + { 0xa4,0xc3,0x1a,0x17 }, { 0xa9,0xc8,0x14,0x1e }, { 0x8a,0xf9,0x3e,0x21 }, { 0x87,0xf2,0x30,0x28 }, - { 0x90,0xef,0x22,0x33 }, { 0x9d,0xe4,0x2c,0x3a }, + { 0x90,0xef,0x22,0x33 }, { 0x9d,0xe4,0x2c,0x3a }, { 0x06,0x3d,0x96,0xdd }, { 0x0b,0x36,0x98,0xd4 }, - { 0x1c,0x2b,0x8a,0xcf }, { 0x11,0x20,0x84,0xc6 }, + { 0x1c,0x2b,0x8a,0xcf }, { 0x11,0x20,0x84,0xc6 }, { 0x32,0x11,0xae,0xf9 }, { 0x3f,0x1a,0xa0,0xf0 }, - { 0x28,0x07,0xb2,0xeb }, { 0x25,0x0c,0xbc,0xe2 }, + { 0x28,0x07,0xb2,0xeb }, { 0x25,0x0c,0xbc,0xe2 }, { 0x6e,0x65,0xe6,0x95 }, { 0x63,0x6e,0xe8,0x9c }, - { 0x74,0x73,0xfa,0x87 }, { 0x79,0x78,0xf4,0x8e }, + { 0x74,0x73,0xfa,0x87 }, { 0x79,0x78,0xf4,0x8e }, { 0x5a,0x49,0xde,0xb1 }, { 0x57,0x42,0xd0,0xb8 }, - { 0x40,0x5f,0xc2,0xa3 }, { 0x4d,0x54,0xcc,0xaa }, + { 0x40,0x5f,0xc2,0xa3 }, { 0x4d,0x54,0xcc,0xaa }, { 0xda,0xf7,0x41,0xec }, { 0xd7,0xfc,0x4f,0xe5 }, - { 0xc0,0xe1,0x5d,0xfe }, { 0xcd,0xea,0x53,0xf7 }, + { 0xc0,0xe1,0x5d,0xfe }, { 0xcd,0xea,0x53,0xf7 }, { 0xee,0xdb,0x79,0xc8 }, { 0xe3,0xd0,0x77,0xc1 }, - { 0xf4,0xcd,0x65,0xda }, { 0xf9,0xc6,0x6b,0xd3 }, + { 0xf4,0xcd,0x65,0xda }, { 0xf9,0xc6,0x6b,0xd3 }, { 0xb2,0xaf,0x31,0xa4 }, { 0xbf,0xa4,0x3f,0xad }, - { 0xa8,0xb9,0x2d,0xb6 }, { 0xa5,0xb2,0x23,0xbf }, + { 0xa8,0xb9,0x2d,0xb6 }, { 0xa5,0xb2,0x23,0xbf }, { 0x86,0x83,0x09,0x80 }, { 0x8b,0x88,0x07,0x89 }, - { 0x9c,0x95,0x15,0x92 }, { 0x91,0x9e,0x1b,0x9b }, + { 0x9c,0x95,0x15,0x92 }, { 0x91,0x9e,0x1b,0x9b }, { 0x0a,0x47,0xa1,0x7c }, { 0x07,0x4c,0xaf,0x75 }, - { 0x10,0x51,0xbd,0x6e }, { 0x1d,0x5a,0xb3,0x67 }, + { 0x10,0x51,0xbd,0x6e }, { 0x1d,0x5a,0xb3,0x67 }, { 0x3e,0x6b,0x99,0x58 }, { 0x33,0x60,0x97,0x51 }, - { 0x24,0x7d,0x85,0x4a }, { 0x29,0x76,0x8b,0x43 }, + { 0x24,0x7d,0x85,0x4a }, { 0x29,0x76,0x8b,0x43 }, { 0x62,0x1f,0xd1,0x34 }, { 0x6f,0x14,0xdf,0x3d }, - { 0x78,0x09,0xcd,0x26 }, { 0x75,0x02,0xc3,0x2f }, + { 0x78,0x09,0xcd,0x26 }, { 0x75,0x02,0xc3,0x2f }, { 0x56,0x33,0xe9,0x10 }, { 0x5b,0x38,0xe7,0x19 }, - { 0x4c,0x25,0xf5,0x02 }, { 0x41,0x2e,0xfb,0x0b }, + { 0x4c,0x25,0xf5,0x02 }, { 0x41,0x2e,0xfb,0x0b }, { 0x61,0x8c,0x9a,0xd7 }, { 0x6c,0x87,0x94,0xde }, - { 0x7b,0x9a,0x86,0xc5 }, { 0x76,0x91,0x88,0xcc }, + { 0x7b,0x9a,0x86,0xc5 }, { 0x76,0x91,0x88,0xcc }, { 0x55,0xa0,0xa2,0xf3 }, { 0x58,0xab,0xac,0xfa }, - { 0x4f,0xb6,0xbe,0xe1 }, { 0x42,0xbd,0xb0,0xe8 }, + { 0x4f,0xb6,0xbe,0xe1 }, { 0x42,0xbd,0xb0,0xe8 }, { 0x09,0xd4,0xea,0x9f }, { 0x04,0xdf,0xe4,0x96 }, - { 0x13,0xc2,0xf6,0x8d }, { 0x1e,0xc9,0xf8,0x84 }, + { 0x13,0xc2,0xf6,0x8d }, { 0x1e,0xc9,0xf8,0x84 }, { 0x3d,0xf8,0xd2,0xbb }, { 0x30,0xf3,0xdc,0xb2 }, - { 0x27,0xee,0xce,0xa9 }, { 0x2a,0xe5,0xc0,0xa0 }, + { 0x27,0xee,0xce,0xa9 }, { 0x2a,0xe5,0xc0,0xa0 }, { 0xb1,0x3c,0x7a,0x47 }, { 0xbc,0x37,0x74,0x4e }, - { 0xab,0x2a,0x66,0x55 }, { 0xa6,0x21,0x68,0x5c }, + { 0xab,0x2a,0x66,0x55 }, { 0xa6,0x21,0x68,0x5c }, { 0x85,0x10,0x42,0x63 }, { 0x88,0x1b,0x4c,0x6a }, - { 0x9f,0x06,0x5e,0x71 }, { 0x92,0x0d,0x50,0x78 }, + { 0x9f,0x06,0x5e,0x71 }, { 0x92,0x0d,0x50,0x78 }, { 0xd9,0x64,0x0a,0x0f }, { 0xd4,0x6f,0x04,0x06 }, - { 0xc3,0x72,0x16,0x1d }, { 0xce,0x79,0x18,0x14 }, + { 0xc3,0x72,0x16,0x1d }, { 0xce,0x79,0x18,0x14 }, { 0xed,0x48,0x32,0x2b }, { 0xe0,0x43,0x3c,0x22 }, - { 0xf7,0x5e,0x2e,0x39 }, { 0xfa,0x55,0x20,0x30 }, + { 0xf7,0x5e,0x2e,0x39 }, { 0xfa,0x55,0x20,0x30 }, { 0xb7,0x01,0xec,0x9a }, { 0xba,0x0a,0xe2,0x93 }, - { 0xad,0x17,0xf0,0x88 }, { 0xa0,0x1c,0xfe,0x81 }, + { 0xad,0x17,0xf0,0x88 }, { 0xa0,0x1c,0xfe,0x81 }, { 0x83,0x2d,0xd4,0xbe }, { 0x8e,0x26,0xda,0xb7 }, - { 0x99,0x3b,0xc8,0xac }, { 0x94,0x30,0xc6,0xa5 }, + { 0x99,0x3b,0xc8,0xac }, { 0x94,0x30,0xc6,0xa5 }, { 0xdf,0x59,0x9c,0xd2 }, { 0xd2,0x52,0x92,0xdb }, - { 0xc5,0x4f,0x80,0xc0 }, { 0xc8,0x44,0x8e,0xc9 }, + { 0xc5,0x4f,0x80,0xc0 }, { 0xc8,0x44,0x8e,0xc9 }, { 0xeb,0x75,0xa4,0xf6 }, { 0xe6,0x7e,0xaa,0xff }, - { 0xf1,0x63,0xb8,0xe4 }, { 0xfc,0x68,0xb6,0xed }, + { 0xf1,0x63,0xb8,0xe4 }, { 0xfc,0x68,0xb6,0xed }, { 0x67,0xb1,0x0c,0x0a }, { 0x6a,0xba,0x02,0x03 }, - { 0x7d,0xa7,0x10,0x18 }, { 0x70,0xac,0x1e,0x11 }, + { 0x7d,0xa7,0x10,0x18 }, { 0x70,0xac,0x1e,0x11 }, { 0x53,0x9d,0x34,0x2e }, { 0x5e,0x96,0x3a,0x27 }, - { 0x49,0x8b,0x28,0x3c }, { 0x44,0x80,0x26,0x35 }, + { 0x49,0x8b,0x28,0x3c }, { 0x44,0x80,0x26,0x35 }, { 0x0f,0xe9,0x7c,0x42 }, { 0x02,0xe2,0x72,0x4b }, - { 0x15,0xff,0x60,0x50 }, { 0x18,0xf4,0x6e,0x59 }, + { 0x15,0xff,0x60,0x50 }, { 0x18,0xf4,0x6e,0x59 }, { 0x3b,0xc5,0x44,0x66 }, { 0x36,0xce,0x4a,0x6f }, - { 0x21,0xd3,0x58,0x74 }, { 0x2c,0xd8,0x56,0x7d }, + { 0x21,0xd3,0x58,0x74 }, { 0x2c,0xd8,0x56,0x7d }, { 0x0c,0x7a,0x37,0xa1 }, { 0x01,0x71,0x39,0xa8 }, - { 0x16,0x6c,0x2b,0xb3 }, { 0x1b,0x67,0x25,0xba }, + { 0x16,0x6c,0x2b,0xb3 }, { 0x1b,0x67,0x25,0xba }, { 0x38,0x56,0x0f,0x85 }, { 0x35,0x5d,0x01,0x8c }, - { 0x22,0x40,0x13,0x97 }, { 0x2f,0x4b,0x1d,0x9e }, + { 0x22,0x40,0x13,0x97 }, { 0x2f,0x4b,0x1d,0x9e }, { 0x64,0x22,0x47,0xe9 }, { 0x69,0x29,0x49,0xe0 }, - { 0x7e,0x34,0x5b,0xfb }, { 0x73,0x3f,0x55,0xf2 }, + { 0x7e,0x34,0x5b,0xfb }, { 0x73,0x3f,0x55,0xf2 }, { 0x50,0x0e,0x7f,0xcd }, { 0x5d,0x05,0x71,0xc4 }, - { 0x4a,0x18,0x63,0xdf }, { 0x47,0x13,0x6d,0xd6 }, + { 0x4a,0x18,0x63,0xdf }, { 0x47,0x13,0x6d,0xd6 }, { 0xdc,0xca,0xd7,0x31 }, { 0xd1,0xc1,0xd9,0x38 }, - { 0xc6,0xdc,0xcb,0x23 }, { 0xcb,0xd7,0xc5,0x2a }, + { 0xc6,0xdc,0xcb,0x23 }, { 0xcb,0xd7,0xc5,0x2a }, { 0xe8,0xe6,0xef,0x15 }, { 0xe5,0xed,0xe1,0x1c }, - { 0xf2,0xf0,0xf3,0x07 }, { 0xff,0xfb,0xfd,0x0e }, + { 0xf2,0xf0,0xf3,0x07 }, { 0xff,0xfb,0xfd,0x0e }, { 0xb4,0x92,0xa7,0x79 }, { 0xb9,0x99,0xa9,0x70 }, - { 0xae,0x84,0xbb,0x6b }, { 0xa3,0x8f,0xb5,0x62 }, + { 0xae,0x84,0xbb,0x6b }, { 0xa3,0x8f,0xb5,0x62 }, { 0x80,0xbe,0x9f,0x5d }, { 0x8d,0xb5,0x91,0x54 }, { 0x9a,0xa8,0x83,0x4f }, { 0x97,0xa3,0x8d,0x46 } }; @@ -1549,139 +1549,138 @@ static const unsigned char U3[256][4] = static const unsigned char U4[256][4] = { { 0x00,0x00,0x00,0x00 }, { 0x09,0x0d,0x0b,0x0e }, - { 0x12,0x1a,0x16,0x1c }, { 0x1b,0x17,0x1d,0x12 }, + { 0x12,0x1a,0x16,0x1c }, { 0x1b,0x17,0x1d,0x12 }, { 0x24,0x34,0x2c,0x38 }, { 0x2d,0x39,0x27,0x36 }, - { 0x36,0x2e,0x3a,0x24 }, { 0x3f,0x23,0x31,0x2a }, + { 0x36,0x2e,0x3a,0x24 }, { 0x3f,0x23,0x31,0x2a }, { 0x48,0x68,0x58,0x70 }, { 0x41,0x65,0x53,0x7e }, - { 0x5a,0x72,0x4e,0x6c }, { 0x53,0x7f,0x45,0x62 }, + { 0x5a,0x72,0x4e,0x6c }, { 0x53,0x7f,0x45,0x62 }, { 0x6c,0x5c,0x74,0x48 }, { 0x65,0x51,0x7f,0x46 }, - { 0x7e,0x46,0x62,0x54 }, { 0x77,0x4b,0x69,0x5a }, + { 0x7e,0x46,0x62,0x54 }, { 0x77,0x4b,0x69,0x5a }, { 0x90,0xd0,0xb0,0xe0 }, { 0x99,0xdd,0xbb,0xee }, - { 0x82,0xca,0xa6,0xfc }, { 0x8b,0xc7,0xad,0xf2 }, + { 0x82,0xca,0xa6,0xfc }, { 0x8b,0xc7,0xad,0xf2 }, { 0xb4,0xe4,0x9c,0xd8 }, { 0xbd,0xe9,0x97,0xd6 }, - { 0xa6,0xfe,0x8a,0xc4 }, { 0xaf,0xf3,0x81,0xca }, + { 0xa6,0xfe,0x8a,0xc4 }, { 0xaf,0xf3,0x81,0xca }, { 0xd8,0xb8,0xe8,0x90 }, { 0xd1,0xb5,0xe3,0x9e }, - { 0xca,0xa2,0xfe,0x8c }, { 0xc3,0xaf,0xf5,0x82 }, + { 0xca,0xa2,0xfe,0x8c }, { 0xc3,0xaf,0xf5,0x82 }, { 0xfc,0x8c,0xc4,0xa8 }, { 0xf5,0x81,0xcf,0xa6 }, - { 0xee,0x96,0xd2,0xb4 }, { 0xe7,0x9b,0xd9,0xba }, + { 0xee,0x96,0xd2,0xb4 }, { 0xe7,0x9b,0xd9,0xba }, { 0x3b,0xbb,0x7b,0xdb }, { 0x32,0xb6,0x70,0xd5 }, - { 0x29,0xa1,0x6d,0xc7 }, { 0x20,0xac,0x66,0xc9 }, + { 0x29,0xa1,0x6d,0xc7 }, { 0x20,0xac,0x66,0xc9 }, { 0x1f,0x8f,0x57,0xe3 }, { 0x16,0x82,0x5c,0xed }, - { 0x0d,0x95,0x41,0xff }, { 0x04,0x98,0x4a,0xf1 }, + { 0x0d,0x95,0x41,0xff }, { 0x04,0x98,0x4a,0xf1 }, { 0x73,0xd3,0x23,0xab }, { 0x7a,0xde,0x28,0xa5 }, - { 0x61,0xc9,0x35,0xb7 }, { 0x68,0xc4,0x3e,0xb9 }, + { 0x61,0xc9,0x35,0xb7 }, { 0x68,0xc4,0x3e,0xb9 }, { 0x57,0xe7,0x0f,0x93 }, { 0x5e,0xea,0x04,0x9d }, - { 0x45,0xfd,0x19,0x8f }, { 0x4c,0xf0,0x12,0x81 }, + { 0x45,0xfd,0x19,0x8f }, { 0x4c,0xf0,0x12,0x81 }, { 0xab,0x6b,0xcb,0x3b }, { 0xa2,0x66,0xc0,0x35 }, - { 0xb9,0x71,0xdd,0x27 }, { 0xb0,0x7c,0xd6,0x29 }, + { 0xb9,0x71,0xdd,0x27 }, { 0xb0,0x7c,0xd6,0x29 }, { 0x8f,0x5f,0xe7,0x03 }, { 0x86,0x52,0xec,0x0d }, - { 0x9d,0x45,0xf1,0x1f }, { 0x94,0x48,0xfa,0x11 }, + { 0x9d,0x45,0xf1,0x1f }, { 0x94,0x48,0xfa,0x11 }, { 0xe3,0x03,0x93,0x4b }, { 0xea,0x0e,0x98,0x45 }, - { 0xf1,0x19,0x85,0x57 }, { 0xf8,0x14,0x8e,0x59 }, + { 0xf1,0x19,0x85,0x57 }, { 0xf8,0x14,0x8e,0x59 }, { 0xc7,0x37,0xbf,0x73 }, { 0xce,0x3a,0xb4,0x7d }, - { 0xd5,0x2d,0xa9,0x6f }, { 0xdc,0x20,0xa2,0x61 }, + { 0xd5,0x2d,0xa9,0x6f }, { 0xdc,0x20,0xa2,0x61 }, { 0x76,0x6d,0xf6,0xad }, { 0x7f,0x60,0xfd,0xa3 }, - { 0x64,0x77,0xe0,0xb1 }, { 0x6d,0x7a,0xeb,0xbf }, + { 0x64,0x77,0xe0,0xb1 }, { 0x6d,0x7a,0xeb,0xbf }, { 0x52,0x59,0xda,0x95 }, { 0x5b,0x54,0xd1,0x9b }, - { 0x40,0x43,0xcc,0x89 }, { 0x49,0x4e,0xc7,0x87 }, + { 0x40,0x43,0xcc,0x89 }, { 0x49,0x4e,0xc7,0x87 }, { 0x3e,0x05,0xae,0xdd }, { 0x37,0x08,0xa5,0xd3 }, - { 0x2c,0x1f,0xb8,0xc1 }, { 0x25,0x12,0xb3,0xcf }, + { 0x2c,0x1f,0xb8,0xc1 }, { 0x25,0x12,0xb3,0xcf }, { 0x1a,0x31,0x82,0xe5 }, { 0x13,0x3c,0x89,0xeb }, - { 0x08,0x2b,0x94,0xf9 }, { 0x01,0x26,0x9f,0xf7 }, + { 0x08,0x2b,0x94,0xf9 }, { 0x01,0x26,0x9f,0xf7 }, { 0xe6,0xbd,0x46,0x4d }, { 0xef,0xb0,0x4d,0x43 }, - { 0xf4,0xa7,0x50,0x51 }, { 0xfd,0xaa,0x5b,0x5f }, + { 0xf4,0xa7,0x50,0x51 }, { 0xfd,0xaa,0x5b,0x5f }, { 0xc2,0x89,0x6a,0x75 }, { 0xcb,0x84,0x61,0x7b }, - { 0xd0,0x93,0x7c,0x69 }, { 0xd9,0x9e,0x77,0x67 }, + { 0xd0,0x93,0x7c,0x69 }, { 0xd9,0x9e,0x77,0x67 }, { 0xae,0xd5,0x1e,0x3d }, { 0xa7,0xd8,0x15,0x33 }, - { 0xbc,0xcf,0x08,0x21 }, { 0xb5,0xc2,0x03,0x2f }, + { 0xbc,0xcf,0x08,0x21 }, { 0xb5,0xc2,0x03,0x2f }, { 0x8a,0xe1,0x32,0x05 }, { 0x83,0xec,0x39,0x0b }, - { 0x98,0xfb,0x24,0x19 }, { 0x91,0xf6,0x2f,0x17 }, + { 0x98,0xfb,0x24,0x19 }, { 0x91,0xf6,0x2f,0x17 }, { 0x4d,0xd6,0x8d,0x76 }, { 0x44,0xdb,0x86,0x78 }, - { 0x5f,0xcc,0x9b,0x6a }, { 0x56,0xc1,0x90,0x64 }, + { 0x5f,0xcc,0x9b,0x6a }, { 0x56,0xc1,0x90,0x64 }, { 0x69,0xe2,0xa1,0x4e }, { 0x60,0xef,0xaa,0x40 }, - { 0x7b,0xf8,0xb7,0x52 }, { 0x72,0xf5,0xbc,0x5c }, + { 0x7b,0xf8,0xb7,0x52 }, { 0x72,0xf5,0xbc,0x5c }, { 0x05,0xbe,0xd5,0x06 }, { 0x0c,0xb3,0xde,0x08 }, - { 0x17,0xa4,0xc3,0x1a }, { 0x1e,0xa9,0xc8,0x14 }, + { 0x17,0xa4,0xc3,0x1a }, { 0x1e,0xa9,0xc8,0x14 }, { 0x21,0x8a,0xf9,0x3e }, { 0x28,0x87,0xf2,0x30 }, - { 0x33,0x90,0xef,0x22 }, { 0x3a,0x9d,0xe4,0x2c }, + { 0x33,0x90,0xef,0x22 }, { 0x3a,0x9d,0xe4,0x2c }, { 0xdd,0x06,0x3d,0x96 }, { 0xd4,0x0b,0x36,0x98 }, - { 0xcf,0x1c,0x2b,0x8a }, { 0xc6,0x11,0x20,0x84 }, + { 0xcf,0x1c,0x2b,0x8a }, { 0xc6,0x11,0x20,0x84 }, { 0xf9,0x32,0x11,0xae }, { 0xf0,0x3f,0x1a,0xa0 }, - { 0xeb,0x28,0x07,0xb2 }, { 0xe2,0x25,0x0c,0xbc }, + { 0xeb,0x28,0x07,0xb2 }, { 0xe2,0x25,0x0c,0xbc }, { 0x95,0x6e,0x65,0xe6 }, { 0x9c,0x63,0x6e,0xe8 }, - { 0x87,0x74,0x73,0xfa }, { 0x8e,0x79,0x78,0xf4 }, + { 0x87,0x74,0x73,0xfa }, { 0x8e,0x79,0x78,0xf4 }, { 0xb1,0x5a,0x49,0xde }, { 0xb8,0x57,0x42,0xd0 }, - { 0xa3,0x40,0x5f,0xc2 }, { 0xaa,0x4d,0x54,0xcc }, + { 0xa3,0x40,0x5f,0xc2 }, { 0xaa,0x4d,0x54,0xcc }, { 0xec,0xda,0xf7,0x41 }, { 0xe5,0xd7,0xfc,0x4f }, - { 0xfe,0xc0,0xe1,0x5d }, { 0xf7,0xcd,0xea,0x53 }, + { 0xfe,0xc0,0xe1,0x5d }, { 0xf7,0xcd,0xea,0x53 }, { 0xc8,0xee,0xdb,0x79 }, { 0xc1,0xe3,0xd0,0x77 }, - { 0xda,0xf4,0xcd,0x65 }, { 0xd3,0xf9,0xc6,0x6b }, + { 0xda,0xf4,0xcd,0x65 }, { 0xd3,0xf9,0xc6,0x6b }, { 0xa4,0xb2,0xaf,0x31 }, { 0xad,0xbf,0xa4,0x3f }, - { 0xb6,0xa8,0xb9,0x2d }, { 0xbf,0xa5,0xb2,0x23 }, + { 0xb6,0xa8,0xb9,0x2d }, { 0xbf,0xa5,0xb2,0x23 }, { 0x80,0x86,0x83,0x09 }, { 0x89,0x8b,0x88,0x07 }, - { 0x92,0x9c,0x95,0x15 }, { 0x9b,0x91,0x9e,0x1b }, + { 0x92,0x9c,0x95,0x15 }, { 0x9b,0x91,0x9e,0x1b }, { 0x7c,0x0a,0x47,0xa1 }, { 0x75,0x07,0x4c,0xaf }, - { 0x6e,0x10,0x51,0xbd }, { 0x67,0x1d,0x5a,0xb3 }, + { 0x6e,0x10,0x51,0xbd }, { 0x67,0x1d,0x5a,0xb3 }, { 0x58,0x3e,0x6b,0x99 }, { 0x51,0x33,0x60,0x97 }, - { 0x4a,0x24,0x7d,0x85 }, { 0x43,0x29,0x76,0x8b }, + { 0x4a,0x24,0x7d,0x85 }, { 0x43,0x29,0x76,0x8b }, { 0x34,0x62,0x1f,0xd1 }, { 0x3d,0x6f,0x14,0xdf }, - { 0x26,0x78,0x09,0xcd }, { 0x2f,0x75,0x02,0xc3 }, + { 0x26,0x78,0x09,0xcd }, { 0x2f,0x75,0x02,0xc3 }, { 0x10,0x56,0x33,0xe9 }, { 0x19,0x5b,0x38,0xe7 }, - { 0x02,0x4c,0x25,0xf5 }, { 0x0b,0x41,0x2e,0xfb }, + { 0x02,0x4c,0x25,0xf5 }, { 0x0b,0x41,0x2e,0xfb }, { 0xd7,0x61,0x8c,0x9a }, { 0xde,0x6c,0x87,0x94 }, - { 0xc5,0x7b,0x9a,0x86 }, { 0xcc,0x76,0x91,0x88 }, + { 0xc5,0x7b,0x9a,0x86 }, { 0xcc,0x76,0x91,0x88 }, { 0xf3,0x55,0xa0,0xa2 }, { 0xfa,0x58,0xab,0xac }, - { 0xe1,0x4f,0xb6,0xbe }, { 0xe8,0x42,0xbd,0xb0 }, + { 0xe1,0x4f,0xb6,0xbe }, { 0xe8,0x42,0xbd,0xb0 }, { 0x9f,0x09,0xd4,0xea }, { 0x96,0x04,0xdf,0xe4 }, - { 0x8d,0x13,0xc2,0xf6 }, { 0x84,0x1e,0xc9,0xf8 }, + { 0x8d,0x13,0xc2,0xf6 }, { 0x84,0x1e,0xc9,0xf8 }, { 0xbb,0x3d,0xf8,0xd2 }, { 0xb2,0x30,0xf3,0xdc }, - { 0xa9,0x27,0xee,0xce }, { 0xa0,0x2a,0xe5,0xc0 }, + { 0xa9,0x27,0xee,0xce }, { 0xa0,0x2a,0xe5,0xc0 }, { 0x47,0xb1,0x3c,0x7a }, { 0x4e,0xbc,0x37,0x74 }, - { 0x55,0xab,0x2a,0x66 }, { 0x5c,0xa6,0x21,0x68 }, + { 0x55,0xab,0x2a,0x66 }, { 0x5c,0xa6,0x21,0x68 }, { 0x63,0x85,0x10,0x42 }, { 0x6a,0x88,0x1b,0x4c }, - { 0x71,0x9f,0x06,0x5e }, { 0x78,0x92,0x0d,0x50 }, + { 0x71,0x9f,0x06,0x5e }, { 0x78,0x92,0x0d,0x50 }, { 0x0f,0xd9,0x64,0x0a }, { 0x06,0xd4,0x6f,0x04 }, - { 0x1d,0xc3,0x72,0x16 }, { 0x14,0xce,0x79,0x18 }, + { 0x1d,0xc3,0x72,0x16 }, { 0x14,0xce,0x79,0x18 }, { 0x2b,0xed,0x48,0x32 }, { 0x22,0xe0,0x43,0x3c }, - { 0x39,0xf7,0x5e,0x2e }, { 0x30,0xfa,0x55,0x20 }, - { 0x9a,0xb7,0x01,0xec }, { 0x93,0xba,0x0a,0xe2 }, - { 0x88,0xad,0x17,0xf0 }, { 0x81,0xa0,0x1c,0xfe }, + { 0x39,0xf7,0x5e,0x2e }, { 0x30,0xfa,0x55,0x20 }, + { 0x9a,0xb7,0x01,0xec }, { 0x93,0xba,0x0a,0xe2 }, + { 0x88,0xad,0x17,0xf0 }, { 0x81,0xa0,0x1c,0xfe }, { 0xbe,0x83,0x2d,0xd4 }, { 0xb7,0x8e,0x26,0xda }, - { 0xac,0x99,0x3b,0xc8 }, { 0xa5,0x94,0x30,0xc6 }, - { 0xd2,0xdf,0x59,0x9c }, { 0xdb,0xd2,0x52,0x92 }, - { 0xc0,0xc5,0x4f,0x80 }, { 0xc9,0xc8,0x44,0x8e }, + { 0xac,0x99,0x3b,0xc8 }, { 0xa5,0x94,0x30,0xc6 }, + { 0xd2,0xdf,0x59,0x9c }, { 0xdb,0xd2,0x52,0x92 }, + { 0xc0,0xc5,0x4f,0x80 }, { 0xc9,0xc8,0x44,0x8e }, { 0xf6,0xeb,0x75,0xa4 }, { 0xff,0xe6,0x7e,0xaa }, - { 0xe4,0xf1,0x63,0xb8 }, { 0xed,0xfc,0x68,0xb6 }, + { 0xe4,0xf1,0x63,0xb8 }, { 0xed,0xfc,0x68,0xb6 }, { 0x0a,0x67,0xb1,0x0c }, { 0x03,0x6a,0xba,0x02 }, - { 0x18,0x7d,0xa7,0x10 }, { 0x11,0x70,0xac,0x1e }, + { 0x18,0x7d,0xa7,0x10 }, { 0x11,0x70,0xac,0x1e }, { 0x2e,0x53,0x9d,0x34 }, { 0x27,0x5e,0x96,0x3a }, - { 0x3c,0x49,0x8b,0x28 }, { 0x35,0x44,0x80,0x26 }, - { 0x42,0x0f,0xe9,0x7c }, { 0x4b,0x02,0xe2,0x72 }, - { 0x50,0x15,0xff,0x60 }, { 0x59,0x18,0xf4,0x6e }, + { 0x3c,0x49,0x8b,0x28 }, { 0x35,0x44,0x80,0x26 }, + { 0x42,0x0f,0xe9,0x7c }, { 0x4b,0x02,0xe2,0x72 }, + { 0x50,0x15,0xff,0x60 }, { 0x59,0x18,0xf4,0x6e }, { 0x66,0x3b,0xc5,0x44 }, { 0x6f,0x36,0xce,0x4a }, - { 0x74,0x21,0xd3,0x58 }, { 0x7d,0x2c,0xd8,0x56 }, + { 0x74,0x21,0xd3,0x58 }, { 0x7d,0x2c,0xd8,0x56 }, { 0xa1,0x0c,0x7a,0x37 }, { 0xa8,0x01,0x71,0x39 }, - { 0xb3,0x16,0x6c,0x2b }, { 0xba,0x1b,0x67,0x25 }, + { 0xb3,0x16,0x6c,0x2b }, { 0xba,0x1b,0x67,0x25 }, { 0x85,0x38,0x56,0x0f }, { 0x8c,0x35,0x5d,0x01 }, - { 0x97,0x22,0x40,0x13 }, { 0x9e,0x2f,0x4b,0x1d }, - { 0xe9,0x64,0x22,0x47 }, { 0xe0,0x69,0x29,0x49 }, - { 0xfb,0x7e,0x34,0x5b }, { 0xf2,0x73,0x3f,0x55 }, + { 0x97,0x22,0x40,0x13 }, { 0x9e,0x2f,0x4b,0x1d }, + { 0xe9,0x64,0x22,0x47 }, { 0xe0,0x69,0x29,0x49 }, + { 0xfb,0x7e,0x34,0x5b }, { 0xf2,0x73,0x3f,0x55 }, { 0xcd,0x50,0x0e,0x7f }, { 0xc4,0x5d,0x05,0x71 }, - { 0xdf,0x4a,0x18,0x63 }, { 0xd6,0x47,0x13,0x6d }, + { 0xdf,0x4a,0x18,0x63 }, { 0xd6,0x47,0x13,0x6d }, { 0x31,0xdc,0xca,0xd7 }, { 0x38,0xd1,0xc1,0xd9 }, - { 0x23,0xc6,0xdc,0xcb }, { 0x2a,0xcb,0xd7,0xc5 }, + { 0x23,0xc6,0xdc,0xcb }, { 0x2a,0xcb,0xd7,0xc5 }, { 0x15,0xe8,0xe6,0xef }, { 0x1c,0xe5,0xed,0xe1 }, - { 0x07,0xf2,0xf0,0xf3 }, { 0x0e,0xff,0xfb,0xfd }, + { 0x07,0xf2,0xf0,0xf3 }, { 0x0e,0xff,0xfb,0xfd }, { 0x79,0xb4,0x92,0xa7 }, { 0x70,0xb9,0x99,0xa9 }, - { 0x6b,0xae,0x84,0xbb }, { 0x62,0xa3,0x8f,0xb5 }, + { 0x6b,0xae,0x84,0xbb }, { 0x62,0xa3,0x8f,0xb5 }, { 0x5d,0x80,0xbe,0x9f }, { 0x54,0x8d,0xb5,0x91 }, { 0x4f,0x9a,0xa8,0x83 }, { 0x46,0x97,0xa3,0x8d } }; -static const u32 rcon[30] = - { +static const u32 rcon[30] = + { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 }; - diff --git a/plugins/MirOTR/Libgcrypt/cipher/rijndael.c b/plugins/MirOTR/Libgcrypt/cipher/rijndael.c index d43b349b41..8019f0aad8 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/rijndael.c +++ b/plugins/MirOTR/Libgcrypt/cipher/rijndael.c @@ -1,6 +1,6 @@ /* Rijndael (AES) for GnuPG * Copyright (C) 2000, 2001, 2002, 2003, 2007, - * 2008 Free Software Foundation, Inc. + * 2008, 2011, 2012 Free Software Foundation, Inc. * * This file is part of Libgcrypt. * @@ -45,77 +45,434 @@ #include "types.h" /* for byte and u32 typedefs */ #include "g10lib.h" #include "cipher.h" +#include "bufhelp.h" +#include "cipher-selftest.h" #define MAXKC (256/32) #define MAXROUNDS 14 #define BLOCKSIZE (128/8) +/* Helper macro to force alignment to 16 bytes. */ +#ifdef HAVE_GCC_ATTRIBUTE_ALIGNED +# define ATTR_ALIGNED_16 __attribute__ ((aligned (16))) +#else +# define ATTR_ALIGNED_16 +#endif + + +/* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */ +#undef USE_AMD64_ASM +#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) +# define USE_AMD64_ASM 1 +#endif + +/* USE_ARM_ASM indicates whether to use ARM assembly code. */ +#undef USE_ARM_ASM +#if defined(__ARMEL__) +# ifdef HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS +# define USE_ARM_ASM 1 +# endif +#endif + /* USE_PADLOCK indicates whether to compile the padlock specific code. */ #undef USE_PADLOCK #ifdef ENABLE_PADLOCK_SUPPORT -# if defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4 && defined (__GNUC__) -# define USE_PADLOCK +# ifdef HAVE_GCC_ATTRIBUTE_ALIGNED +# if (defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4) || defined(__x86_64__) +# define USE_PADLOCK 1 +# endif # endif #endif /*ENABLE_PADLOCK_SUPPORT*/ -static const char *selftest(void); +/* USE_AESNI inidicates whether to compile with Intel AES-NI code. We + need the vector-size attribute which seems to be available since + gcc 3. However, to be on the safe side we require at least gcc 4. */ +#undef USE_AESNI +#ifdef ENABLE_AESNI_SUPPORT +# if ((defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4) || defined(__x86_64__)) +# if __GNUC__ >= 4 +# define USE_AESNI 1 +# endif +# endif +#endif /* ENABLE_AESNI_SUPPORT */ -typedef struct -{ - int ROUNDS; /* Key-length-dependent number of rounds. */ - int decryption_prepared; /* The decryption key schedule is available. */ -#ifdef USE_PADLOCK - int use_padlock; /* Padlock shall be used. */ - /* The key as passed to the padlock engine. */ - unsigned char padlock_key[16] __attribute__ ((aligned (16))); +#ifdef USE_AESNI + typedef struct u128_s { u32 a, b, c, d; } u128_t; +#endif /*USE_AESNI*/ + +/* Define an u32 variant for the sake of gcc 4.4's strict aliasing. */ +#if __GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 4 ) +typedef u32 __attribute__ ((__may_alias__)) u32_a_t; +#else +typedef u32 u32_a_t; #endif + + +#ifdef USE_AMD64_ASM +/* AMD64 assembly implementations of AES */ +extern void _gcry_aes_amd64_encrypt_block(const void *keysched_enc, + unsigned char *out, + const unsigned char *in, + int rounds); + +extern void _gcry_aes_amd64_decrypt_block(const void *keysched_dec, + unsigned char *out, + const unsigned char *in, + int rounds); +#endif /*USE_AMD64_ASM*/ + +#ifdef USE_ARM_ASM +/* ARM assembly implementations of AES */ +extern void _gcry_aes_arm_encrypt_block(const void *keysched_enc, + unsigned char *out, + const unsigned char *in, + int rounds); + +extern void _gcry_aes_arm_decrypt_block(const void *keysched_dec, + unsigned char *out, + const unsigned char *in, + int rounds); +#endif /*USE_ARM_ASM*/ + + + +/* Our context object. */ +typedef struct +{ + /* The first fields are the keyschedule arrays. This is so that + they are aligned on a 16 byte boundary if using gcc. This + alignment is required for the AES-NI code and a good idea in any + case. The alignment is guaranteed due to the way cipher.c + allocates the space for the context. The PROPERLY_ALIGNED_TYPE + hack is used to force a minimal alignment if not using gcc of if + the alignment requirement is higher that 16 bytes. */ union { PROPERLY_ALIGNED_TYPE dummy; byte keyschedule[MAXROUNDS+1][4][4]; +#ifdef USE_PADLOCK + /* The key as passed to the padlock engine. It is only used if + the padlock engine is used (USE_PADLOCK, below). */ + unsigned char padlock_key[16] __attribute__ ((aligned (16))); +#endif /*USE_PADLOCK*/ } u1; union { PROPERLY_ALIGNED_TYPE dummy; - byte keyschedule[MAXROUNDS+1][4][4]; + byte keyschedule[MAXROUNDS+1][4][4]; } u2; -} RIJNDAEL_context; + int rounds; /* Key-length-dependent number of rounds. */ + unsigned int decryption_prepared:1; /* The decryption key schedule is available. */ +#ifdef USE_PADLOCK + unsigned int use_padlock:1; /* Padlock shall be used. */ +#endif /*USE_PADLOCK*/ +#ifdef USE_AESNI + unsigned int use_aesni:1; /* AES-NI shall be used. */ +#endif /*USE_AESNI*/ +} RIJNDAEL_context ATTR_ALIGNED_16; + +/* Macros defining alias for the keyschedules. */ +#define keyschenc u1.keyschedule +#define keyschdec u2.keyschedule +#define padlockkey u1.padlock_key + +/* Two macros to be called prior and after the use of AESNI + instructions. There should be no external function calls between + the use of these macros. There purpose is to make sure that the + SSE regsiters are cleared and won't reveal any information about + the key or the data. */ +#ifdef USE_AESNI +# define aesni_prepare() do { } while (0) +# define aesni_cleanup() \ + do { asm volatile ("pxor %%xmm0, %%xmm0\n\t" \ + "pxor %%xmm1, %%xmm1\n" :: ); \ + } while (0) +# define aesni_cleanup_2_6() \ + do { asm volatile ("pxor %%xmm2, %%xmm2\n\t" \ + "pxor %%xmm3, %%xmm3\n" \ + "pxor %%xmm4, %%xmm4\n" \ + "pxor %%xmm5, %%xmm5\n" \ + "pxor %%xmm6, %%xmm6\n":: ); \ + } while (0) +#else +# define aesni_prepare() do { } while (0) +# define aesni_cleanup() do { } while (0) +#endif -#define keySched u1.keyschedule -#define keySched2 u2.keyschedule /* All the numbers. */ #include "rijndael-tables.h" -/* Perform the key setup. */ + +/* Function prototypes. */ +#if defined(__i386__) && defined(USE_AESNI) +/* We don't want to inline these functions on i386 to help gcc allocate enough + registers. */ +static void do_aesni_ctr (const RIJNDAEL_context *ctx, unsigned char *ctr, + unsigned char *b, const unsigned char *a) + __attribute__ ((__noinline__)); +static void do_aesni_ctr_4 (const RIJNDAEL_context *ctx, unsigned char *ctr, + unsigned char *b, const unsigned char *a) + __attribute__ ((__noinline__)); +#endif /*USE_AESNI*/ + +static const char *selftest(void); + + + +#ifdef USE_AESNI +static void +aesni_do_setkey (RIJNDAEL_context *ctx, const byte *key) +{ + aesni_prepare(); + + if (ctx->rounds < 12) + { + /* 128-bit key */ +#define AESKEYGENASSIST_xmm1_xmm2(imm8) \ + ".byte 0x66, 0x0f, 0x3a, 0xdf, 0xd1, " #imm8 " \n\t" +#define AESKEY_EXPAND128 \ + "pshufd $0xff, %%xmm2, %%xmm2\n\t" \ + "movdqa %%xmm1, %%xmm3\n\t" \ + "pslldq $4, %%xmm3\n\t" \ + "pxor %%xmm3, %%xmm1\n\t" \ + "pslldq $4, %%xmm3\n\t" \ + "pxor %%xmm3, %%xmm1\n\t" \ + "pslldq $4, %%xmm3\n\t" \ + "pxor %%xmm3, %%xmm2\n\t" \ + "pxor %%xmm2, %%xmm1\n\t" + + asm volatile ("movdqu (%[key]), %%xmm1\n\t" /* xmm1 := key */ + "movdqa %%xmm1, (%[ksch])\n\t" /* ksch[0] := xmm1 */ + AESKEYGENASSIST_xmm1_xmm2(0x01) + AESKEY_EXPAND128 + "movdqa %%xmm1, 0x10(%[ksch])\n\t" /* ksch[1] := xmm1 */ + AESKEYGENASSIST_xmm1_xmm2(0x02) + AESKEY_EXPAND128 + "movdqa %%xmm1, 0x20(%[ksch])\n\t" /* ksch[2] := xmm1 */ + AESKEYGENASSIST_xmm1_xmm2(0x04) + AESKEY_EXPAND128 + "movdqa %%xmm1, 0x30(%[ksch])\n\t" /* ksch[3] := xmm1 */ + AESKEYGENASSIST_xmm1_xmm2(0x08) + AESKEY_EXPAND128 + "movdqa %%xmm1, 0x40(%[ksch])\n\t" /* ksch[4] := xmm1 */ + AESKEYGENASSIST_xmm1_xmm2(0x10) + AESKEY_EXPAND128 + "movdqa %%xmm1, 0x50(%[ksch])\n\t" /* ksch[5] := xmm1 */ + AESKEYGENASSIST_xmm1_xmm2(0x20) + AESKEY_EXPAND128 + "movdqa %%xmm1, 0x60(%[ksch])\n\t" /* ksch[6] := xmm1 */ + AESKEYGENASSIST_xmm1_xmm2(0x40) + AESKEY_EXPAND128 + "movdqa %%xmm1, 0x70(%[ksch])\n\t" /* ksch[7] := xmm1 */ + AESKEYGENASSIST_xmm1_xmm2(0x80) + AESKEY_EXPAND128 + "movdqa %%xmm1, 0x80(%[ksch])\n\t" /* ksch[8] := xmm1 */ + AESKEYGENASSIST_xmm1_xmm2(0x1b) + AESKEY_EXPAND128 + "movdqa %%xmm1, 0x90(%[ksch])\n\t" /* ksch[9] := xmm1 */ + AESKEYGENASSIST_xmm1_xmm2(0x36) + AESKEY_EXPAND128 + "movdqa %%xmm1, 0xa0(%[ksch])\n\t" /* ksch[10] := xmm1 */ + : + : [key] "r" (key), [ksch] "r" (ctx->keyschenc) + : "cc", "memory" ); +#undef AESKEYGENASSIST_xmm1_xmm2 +#undef AESKEY_EXPAND128 + } + else if (ctx->rounds == 12) + { + /* 192-bit key */ +#define AESKEYGENASSIST_xmm3_xmm2(imm8) \ + ".byte 0x66, 0x0f, 0x3a, 0xdf, 0xd3, " #imm8 " \n\t" +#define AESKEY_EXPAND192 \ + "pshufd $0x55, %%xmm2, %%xmm2\n\t" \ + "movdqu %%xmm1, %%xmm4\n\t" \ + "pslldq $4, %%xmm4\n\t" \ + "pxor %%xmm4, %%xmm1\n\t" \ + "pslldq $4, %%xmm4\n\t" \ + "pxor %%xmm4, %%xmm1\n\t" \ + "pslldq $4, %%xmm4\n\t" \ + "pxor %%xmm4, %%xmm1\n\t" \ + "pxor %%xmm2, %%xmm1\n\t" \ + "pshufd $0xff, %%xmm1, %%xmm2\n\t" \ + "movdqu %%xmm3, %%xmm4\n\t" \ + "pslldq $4, %%xmm4\n\t" \ + "pxor %%xmm4, %%xmm3\n\t" \ + "pxor %%xmm2, %%xmm3\n\t" + + asm volatile ("movdqu (%[key]), %%xmm1\n\t" /* xmm1 := key[0..15] */ + "movq 16(%[key]), %%xmm3\n\t" /* xmm3 := key[16..23] */ + "movdqa %%xmm1, (%[ksch])\n\t" /* ksch[0] := xmm1 */ + "movdqa %%xmm3, %%xmm5\n\t" + + AESKEYGENASSIST_xmm3_xmm2(0x01) + AESKEY_EXPAND192 + "shufpd $0, %%xmm1, %%xmm5\n\t" + "movdqa %%xmm5, 0x10(%[ksch])\n\t" /* ksch[1] := xmm5 */ + "movdqa %%xmm1, %%xmm6\n\t" + "shufpd $1, %%xmm3, %%xmm6\n\t" + "movdqa %%xmm6, 0x20(%[ksch])\n\t" /* ksch[2] := xmm6 */ + AESKEYGENASSIST_xmm3_xmm2(0x02) + AESKEY_EXPAND192 + "movdqa %%xmm1, 0x30(%[ksch])\n\t" /* ksch[3] := xmm1 */ + "movdqa %%xmm3, %%xmm5\n\t" + + AESKEYGENASSIST_xmm3_xmm2(0x04) + AESKEY_EXPAND192 + "shufpd $0, %%xmm1, %%xmm5\n\t" + "movdqa %%xmm5, 0x40(%[ksch])\n\t" /* ksch[4] := xmm5 */ + "movdqa %%xmm1, %%xmm6\n\t" + "shufpd $1, %%xmm3, %%xmm6\n\t" + "movdqa %%xmm6, 0x50(%[ksch])\n\t" /* ksch[5] := xmm6 */ + AESKEYGENASSIST_xmm3_xmm2(0x08) + AESKEY_EXPAND192 + "movdqa %%xmm1, 0x60(%[ksch])\n\t" /* ksch[6] := xmm1 */ + "movdqa %%xmm3, %%xmm5\n\t" + + AESKEYGENASSIST_xmm3_xmm2(0x10) + AESKEY_EXPAND192 + "shufpd $0, %%xmm1, %%xmm5\n\t" + "movdqa %%xmm5, 0x70(%[ksch])\n\t" /* ksch[7] := xmm5 */ + "movdqa %%xmm1, %%xmm6\n\t" + "shufpd $1, %%xmm3, %%xmm6\n\t" + "movdqa %%xmm6, 0x80(%[ksch])\n\t" /* ksch[8] := xmm6 */ + AESKEYGENASSIST_xmm3_xmm2(0x20) + AESKEY_EXPAND192 + "movdqa %%xmm1, 0x90(%[ksch])\n\t" /* ksch[9] := xmm1 */ + "movdqa %%xmm3, %%xmm5\n\t" + + AESKEYGENASSIST_xmm3_xmm2(0x40) + AESKEY_EXPAND192 + "shufpd $0, %%xmm1, %%xmm5\n\t" + "movdqa %%xmm5, 0xa0(%[ksch])\n\t" /* ksch[10] := xmm5 */ + "movdqa %%xmm1, %%xmm6\n\t" + "shufpd $1, %%xmm3, %%xmm6\n\t" + "movdqa %%xmm6, 0xb0(%[ksch])\n\t" /* ksch[11] := xmm6 */ + AESKEYGENASSIST_xmm3_xmm2(0x80) + AESKEY_EXPAND192 + "movdqa %%xmm1, 0xc0(%[ksch])\n\t" /* ksch[12] := xmm1 */ + : + : [key] "r" (key), [ksch] "r" (ctx->keyschenc) + : "cc", "memory" ); +#undef AESKEYGENASSIST_xmm3_xmm2 +#undef AESKEY_EXPAND192 + } + else if (ctx->rounds > 12) + { + /* 256-bit key */ +#define AESKEYGENASSIST_xmm1_xmm2(imm8) \ + ".byte 0x66, 0x0f, 0x3a, 0xdf, 0xd1, " #imm8 " \n\t" +#define AESKEYGENASSIST_xmm3_xmm2(imm8) \ + ".byte 0x66, 0x0f, 0x3a, 0xdf, 0xd3, " #imm8 " \n\t" +#define AESKEY_EXPAND256_A \ + "pshufd $0xff, %%xmm2, %%xmm2\n\t" \ + "movdqa %%xmm1, %%xmm4\n\t" \ + "pslldq $4, %%xmm4\n\t" \ + "pxor %%xmm4, %%xmm1\n\t" \ + "pslldq $4, %%xmm4\n\t" \ + "pxor %%xmm4, %%xmm1\n\t" \ + "pslldq $4, %%xmm4\n\t" \ + "pxor %%xmm4, %%xmm1\n\t" \ + "pxor %%xmm2, %%xmm1\n\t" +#define AESKEY_EXPAND256_B \ + "pshufd $0xaa, %%xmm2, %%xmm2\n\t" \ + "movdqa %%xmm3, %%xmm4\n\t" \ + "pslldq $4, %%xmm4\n\t" \ + "pxor %%xmm4, %%xmm3\n\t" \ + "pslldq $4, %%xmm4\n\t" \ + "pxor %%xmm4, %%xmm3\n\t" \ + "pslldq $4, %%xmm4\n\t" \ + "pxor %%xmm4, %%xmm3\n\t" \ + "pxor %%xmm2, %%xmm3\n\t" + + asm volatile ("movdqu (%[key]), %%xmm1\n\t" /* xmm1 := key[0..15] */ + "movdqu 16(%[key]), %%xmm3\n\t" /* xmm3 := key[16..31] */ + "movdqa %%xmm1, (%[ksch])\n\t" /* ksch[0] := xmm1 */ + "movdqa %%xmm3, 0x10(%[ksch])\n\t" /* ksch[1] := xmm3 */ + + AESKEYGENASSIST_xmm3_xmm2(0x01) + AESKEY_EXPAND256_A + "movdqa %%xmm1, 0x20(%[ksch])\n\t" /* ksch[2] := xmm1 */ + AESKEYGENASSIST_xmm1_xmm2(0x00) + AESKEY_EXPAND256_B + "movdqa %%xmm3, 0x30(%[ksch])\n\t" /* ksch[3] := xmm3 */ + + AESKEYGENASSIST_xmm3_xmm2(0x02) + AESKEY_EXPAND256_A + "movdqa %%xmm1, 0x40(%[ksch])\n\t" /* ksch[4] := xmm1 */ + AESKEYGENASSIST_xmm1_xmm2(0x00) + AESKEY_EXPAND256_B + "movdqa %%xmm3, 0x50(%[ksch])\n\t" /* ksch[5] := xmm3 */ + + AESKEYGENASSIST_xmm3_xmm2(0x04) + AESKEY_EXPAND256_A + "movdqa %%xmm1, 0x60(%[ksch])\n\t" /* ksch[6] := xmm1 */ + AESKEYGENASSIST_xmm1_xmm2(0x00) + AESKEY_EXPAND256_B + "movdqa %%xmm3, 0x70(%[ksch])\n\t" /* ksch[7] := xmm3 */ + + AESKEYGENASSIST_xmm3_xmm2(0x08) + AESKEY_EXPAND256_A + "movdqa %%xmm1, 0x80(%[ksch])\n\t" /* ksch[8] := xmm1 */ + AESKEYGENASSIST_xmm1_xmm2(0x00) + AESKEY_EXPAND256_B + "movdqa %%xmm3, 0x90(%[ksch])\n\t" /* ksch[9] := xmm3 */ + + AESKEYGENASSIST_xmm3_xmm2(0x10) + AESKEY_EXPAND256_A + "movdqa %%xmm1, 0xa0(%[ksch])\n\t" /* ksch[10] := xmm1 */ + AESKEYGENASSIST_xmm1_xmm2(0x00) + AESKEY_EXPAND256_B + "movdqa %%xmm3, 0xb0(%[ksch])\n\t" /* ksch[11] := xmm3 */ + + AESKEYGENASSIST_xmm3_xmm2(0x20) + AESKEY_EXPAND256_A + "movdqa %%xmm1, 0xc0(%[ksch])\n\t" /* ksch[12] := xmm1 */ + AESKEYGENASSIST_xmm1_xmm2(0x00) + AESKEY_EXPAND256_B + "movdqa %%xmm3, 0xd0(%[ksch])\n\t" /* ksch[13] := xmm3 */ + + AESKEYGENASSIST_xmm3_xmm2(0x40) + AESKEY_EXPAND256_A + "movdqa %%xmm1, 0xe0(%[ksch])\n\t" /* ksch[14] := xmm1 */ + + : + : [key] "r" (key), [ksch] "r" (ctx->keyschenc) + : "cc", "memory" ); +#undef AESKEYGENASSIST_xmm1_xmm2 +#undef AESKEYGENASSIST_xmm3_xmm2 +#undef AESKEY_EXPAND256_A +#undef AESKEY_EXPAND256_B + } + + aesni_cleanup(); + aesni_cleanup_2_6(); +} +#endif /*USE_AESNI*/ + + + +/* Perform the key setup. */ static gcry_err_code_t do_setkey (RIJNDAEL_context *ctx, const byte *key, const unsigned keylen) { static int initialized = 0; static const char *selftest_failed=0; - int ROUNDS; + int rounds; int i,j, r, t, rconpointer = 0; int KC; - union - { - PROPERLY_ALIGNED_TYPE dummy; - byte k[MAXKC][4]; - } k; -#define k k.k - union - { - PROPERLY_ALIGNED_TYPE dummy; - byte tk[MAXKC][4]; - } tk; -#define tk tk.tk +#if defined(USE_AESNI) || defined(USE_PADLOCK) + unsigned int hwfeatures; +#endif /* The on-the-fly self tests are only run in non-fips mode. In fips mode explicit self-tests are required. Actually the on-the-fly self-tests are not fully thread-safe and it might happen that a - failed self-test won't get noticed in another thread. + failed self-test won't get noticed in another thread. FIXME: We might want to have a central registry of succeeded self-tests. */ @@ -129,65 +486,115 @@ do_setkey (RIJNDAEL_context *ctx, const byte *key, const unsigned keylen) if (selftest_failed) return GPG_ERR_SELFTEST_FAILED; +#if defined(USE_AESNI) || defined(USE_PADLOCK) + hwfeatures = _gcry_get_hw_features (); +#endif + ctx->decryption_prepared = 0; #ifdef USE_PADLOCK ctx->use_padlock = 0; #endif +#ifdef USE_AESNI + ctx->use_aesni = 0; +#endif if( keylen == 128/8 ) { - ROUNDS = 10; + rounds = 10; KC = 4; + + if (0) + { + ; + } #ifdef USE_PADLOCK - if ((_gcry_get_hw_features () & HWF_PADLOCK_AES)) + else if (hwfeatures & HWF_PADLOCK_AES) { ctx->use_padlock = 1; - memcpy (ctx->padlock_key, key, keylen); + memcpy (ctx->padlockkey, key, keylen); + } +#endif +#ifdef USE_AESNI + else if (hwfeatures & HWF_INTEL_AESNI) + { + ctx->use_aesni = 1; } #endif } else if ( keylen == 192/8 ) { - ROUNDS = 12; + rounds = 12; KC = 6; + + if (0) + { + ; + } +#ifdef USE_AESNI + else if (hwfeatures & HWF_INTEL_AESNI) + { + ctx->use_aesni = 1; + } +#endif } else if ( keylen == 256/8 ) { - ROUNDS = 14; + rounds = 14; KC = 8; + + if (0) + { + ; + } +#ifdef USE_AESNI + else if (hwfeatures & HWF_INTEL_AESNI) + { + ctx->use_aesni = 1; + } +#endif } else return GPG_ERR_INV_KEYLEN; - ctx->ROUNDS = ROUNDS; + ctx->rounds = rounds; -#ifdef USE_PADLOCK - if (ctx->use_padlock) + /* NB: We don't yet support Padlock hardware key generation. */ + + if (0) { - /* Nothing to do as we support only hardware key generation for - now. */ + ; } +#ifdef USE_AESNI + else if (ctx->use_aesni) + aesni_do_setkey(ctx, key); +#endif else -#endif /*USE_PADLOCK*/ { -#define W (ctx->keySched) - for (i = 0; i < keylen; i++) + union { - k[i >> 2][i & 3] = key[i]; + PROPERLY_ALIGNED_TYPE dummy; + byte data[MAXKC][4]; + } k, tk; +#define k k.data +#define tk tk.data +#define W (ctx->keyschenc) + for (i = 0; i < keylen; i++) + { + k[i >> 2][i & 3] = key[i]; } - - for (j = KC-1; j >= 0; j--) + + for (j = KC-1; j >= 0; j--) { - *((u32*)tk[j]) = *((u32*)k[j]); + *((u32_a_t*)tk[j]) = *((u32_a_t*)k[j]); } r = 0; t = 0; /* Copy values into round key array. */ - for (j = 0; (j < KC) && (r < ROUNDS + 1); ) + for (j = 0; (j < KC) && (r < rounds + 1); ) { for (; (j < KC) && (t < 4); j++, t++) { - *((u32*)W[r][t]) = *((u32*)tk[j]); + *((u32_a_t*)W[r][t]) = *((u32_a_t*)tk[j]); } if (t == 4) { @@ -195,8 +602,8 @@ do_setkey (RIJNDAEL_context *ctx, const byte *key, const unsigned keylen) t = 0; } } - - while (r < ROUNDS + 1) + + while (r < rounds + 1) { /* While not enough round key material calculated calculate new values. */ @@ -205,19 +612,19 @@ do_setkey (RIJNDAEL_context *ctx, const byte *key, const unsigned keylen) tk[0][2] ^= S[tk[KC-1][3]]; tk[0][3] ^= S[tk[KC-1][0]]; tk[0][0] ^= rcon[rconpointer++]; - + if (KC != 8) { - for (j = 1; j < KC; j++) + for (j = 1; j < KC; j++) { - *((u32*)tk[j]) ^= *((u32*)tk[j-1]); + *((u32_a_t*)tk[j]) ^= *((u32_a_t*)tk[j-1]); } - } - else + } + else { for (j = 1; j < KC/2; j++) { - *((u32*)tk[j]) ^= *((u32*)tk[j-1]); + *((u32_a_t*)tk[j]) ^= *((u32_a_t*)tk[j-1]); } tk[KC/2][0] ^= S[tk[KC/2 - 1][0]]; tk[KC/2][1] ^= S[tk[KC/2 - 1][1]]; @@ -225,16 +632,16 @@ do_setkey (RIJNDAEL_context *ctx, const byte *key, const unsigned keylen) tk[KC/2][3] ^= S[tk[KC/2 - 1][3]]; for (j = KC/2 + 1; j < KC; j++) { - *((u32*)tk[j]) ^= *((u32*)tk[j-1]); + *((u32_a_t*)tk[j]) ^= *((u32_a_t*)tk[j-1]); } } - + /* Copy values into round key array. */ - for (j = 0; (j < KC) && (r < ROUNDS + 1); ) + for (j = 0; (j < KC) && (r < rounds + 1); ) { for (; (j < KC) && (t < 4); j++, t++) { - *((u32*)W[r][t]) = *((u32*)tk[j]); + *((u32_a_t*)W[r][t]) = *((u32_a_t*)tk[j]); } if (t == 4) { @@ -242,13 +649,15 @@ do_setkey (RIJNDAEL_context *ctx, const byte *key, const unsigned keylen) t = 0; } } - } -#undef W + } +#undef W +#undef tk +#undef k + wipememory(&tk, sizeof(tk)); + wipememory(&t, sizeof(t)); } return 0; -#undef tk -#undef k } @@ -256,10 +665,7 @@ static gcry_err_code_t rijndael_setkey (void *context, const byte *key, const unsigned keylen) { RIJNDAEL_context *ctx = context; - - int rc = do_setkey (ctx, key, keylen); - _gcry_burn_stack ( 100 + 16*sizeof(int)); - return rc; + return do_setkey (ctx, key, keylen); } @@ -268,53 +674,113 @@ static void prepare_decryption( RIJNDAEL_context *ctx ) { int r; - union - { - PROPERLY_ALIGNED_TYPE dummy; - byte *w; - } w; -#define w w.w - for (r=0; r < MAXROUNDS+1; r++ ) +#ifdef USE_AESNI + if (ctx->use_aesni) { - *((u32*)ctx->keySched2[r][0]) = *((u32*)ctx->keySched[r][0]); - *((u32*)ctx->keySched2[r][1]) = *((u32*)ctx->keySched[r][1]); - *((u32*)ctx->keySched2[r][2]) = *((u32*)ctx->keySched[r][2]); - *((u32*)ctx->keySched2[r][3]) = *((u32*)ctx->keySched[r][3]); + /* The AES-NI decrypt instructions use the Equivalent Inverse + Cipher, thus we can't use the the standard decrypt key + preparation. */ + u128_t *ekey = (u128_t *)ctx->keyschenc; + u128_t *dkey = (u128_t *)ctx->keyschdec; + int rr; + + aesni_prepare(); + +#define DO_AESNI_AESIMC() \ + asm volatile ("movdqa %[ekey], %%xmm1\n\t" \ + /*"aesimc %%xmm1, %%xmm1\n\t"*/ \ + ".byte 0x66, 0x0f, 0x38, 0xdb, 0xc9\n\t" \ + "movdqa %%xmm1, %[dkey]" \ + : [dkey] "=m" (dkey[r]) \ + : [ekey] "m" (ekey[rr]) \ + : "memory") + + dkey[0] = ekey[ctx->rounds]; + r=1; + rr=ctx->rounds-1; + DO_AESNI_AESIMC(); r++; rr--; /* round 1 */ + DO_AESNI_AESIMC(); r++; rr--; /* round 2 */ + DO_AESNI_AESIMC(); r++; rr--; /* round 3 */ + DO_AESNI_AESIMC(); r++; rr--; /* round 4 */ + DO_AESNI_AESIMC(); r++; rr--; /* round 5 */ + DO_AESNI_AESIMC(); r++; rr--; /* round 6 */ + DO_AESNI_AESIMC(); r++; rr--; /* round 7 */ + DO_AESNI_AESIMC(); r++; rr--; /* round 8 */ + DO_AESNI_AESIMC(); r++; rr--; /* round 9 */ + if (ctx->rounds > 10) + { + DO_AESNI_AESIMC(); r++; rr--; /* round 10 */ + DO_AESNI_AESIMC(); r++; rr--; /* round 11 */ + if (ctx->rounds > 12) + { + DO_AESNI_AESIMC(); r++; rr--; /* round 12 */ + DO_AESNI_AESIMC(); r++; rr--; /* round 13 */ + } + } + + dkey[r] = ekey[0]; + +#undef DO_AESNI_AESIMC + + aesni_cleanup(); } -#define W (ctx->keySched2) - for (r = 1; r < ctx->ROUNDS; r++) + else +#endif /*USE_AESNI*/ { - w = W[r][0]; - *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) - ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); - - w = W[r][1]; - *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) - ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); - - w = W[r][2]; - *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) - ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); - - w = W[r][3]; - *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) - ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); - } + union + { + PROPERLY_ALIGNED_TYPE dummy; + byte *w; + } w; +#define w w.w + + for (r=0; r < MAXROUNDS+1; r++ ) + { + *((u32_a_t*)ctx->keyschdec[r][0]) = *((u32_a_t*)ctx->keyschenc[r][0]); + *((u32_a_t*)ctx->keyschdec[r][1]) = *((u32_a_t*)ctx->keyschenc[r][1]); + *((u32_a_t*)ctx->keyschdec[r][2]) = *((u32_a_t*)ctx->keyschenc[r][2]); + *((u32_a_t*)ctx->keyschdec[r][3]) = *((u32_a_t*)ctx->keyschenc[r][3]); + } +#define W (ctx->keyschdec) + for (r = 1; r < ctx->rounds; r++) + { + w = W[r][0]; + *((u32_a_t*)w) = *((u32_a_t*)U1[w[0]]) ^ *((u32_a_t*)U2[w[1]]) + ^ *((u32_a_t*)U3[w[2]]) ^ *((u32_a_t*)U4[w[3]]); + + w = W[r][1]; + *((u32_a_t*)w) = *((u32_a_t*)U1[w[0]]) ^ *((u32_a_t*)U2[w[1]]) + ^ *((u32_a_t*)U3[w[2]]) ^ *((u32_a_t*)U4[w[3]]); + + w = W[r][2]; + *((u32_a_t*)w) = *((u32_a_t*)U1[w[0]]) ^ *((u32_a_t*)U2[w[1]]) + ^ *((u32_a_t*)U3[w[2]]) ^ *((u32_a_t*)U4[w[3]]); + + w = W[r][3]; + *((u32_a_t*)w) = *((u32_a_t*)U1[w[0]]) ^ *((u32_a_t*)U2[w[1]]) + ^ *((u32_a_t*)U3[w[2]]) ^ *((u32_a_t*)U4[w[3]]); + } #undef W #undef w -} - + wipememory(&w, sizeof(w)); + } +} /* Encrypt one block. A and B need to be aligned on a 4 byte boundary. A and B may be the same. */ static void -do_encrypt_aligned (const RIJNDAEL_context *ctx, +do_encrypt_aligned (const RIJNDAEL_context *ctx, unsigned char *b, const unsigned char *a) { -#define rk (ctx->keySched) - int ROUNDS = ctx->ROUNDS; +#ifdef USE_AMD64_ASM + _gcry_aes_amd64_encrypt_block(ctx->keyschenc, b, a, ctx->rounds); +#elif defined(USE_ARM_ASM) + _gcry_aes_arm_encrypt_block(ctx->keyschenc, b, a, ctx->rounds); +#else +#define rk (ctx->keyschenc) + int rounds = ctx->rounds; int r; union { @@ -322,57 +788,57 @@ do_encrypt_aligned (const RIJNDAEL_context *ctx, byte temp[4][4]; } u; - *((u32*)u.temp[0]) = *((u32*)(a )) ^ *((u32*)rk[0][0]); - *((u32*)u.temp[1]) = *((u32*)(a+ 4)) ^ *((u32*)rk[0][1]); - *((u32*)u.temp[2]) = *((u32*)(a+ 8)) ^ *((u32*)rk[0][2]); - *((u32*)u.temp[3]) = *((u32*)(a+12)) ^ *((u32*)rk[0][3]); - *((u32*)(b )) = (*((u32*)T1[u.temp[0][0]]) - ^ *((u32*)T2[u.temp[1][1]]) - ^ *((u32*)T3[u.temp[2][2]]) - ^ *((u32*)T4[u.temp[3][3]])); - *((u32*)(b + 4)) = (*((u32*)T1[u.temp[1][0]]) - ^ *((u32*)T2[u.temp[2][1]]) - ^ *((u32*)T3[u.temp[3][2]]) - ^ *((u32*)T4[u.temp[0][3]])); - *((u32*)(b + 8)) = (*((u32*)T1[u.temp[2][0]]) - ^ *((u32*)T2[u.temp[3][1]]) - ^ *((u32*)T3[u.temp[0][2]]) - ^ *((u32*)T4[u.temp[1][3]])); - *((u32*)(b +12)) = (*((u32*)T1[u.temp[3][0]]) - ^ *((u32*)T2[u.temp[0][1]]) - ^ *((u32*)T3[u.temp[1][2]]) - ^ *((u32*)T4[u.temp[2][3]])); - - for (r = 1; r < ROUNDS-1; r++) + *((u32_a_t*)u.temp[0]) = *((u32_a_t*)(a )) ^ *((u32_a_t*)rk[0][0]); + *((u32_a_t*)u.temp[1]) = *((u32_a_t*)(a+ 4)) ^ *((u32_a_t*)rk[0][1]); + *((u32_a_t*)u.temp[2]) = *((u32_a_t*)(a+ 8)) ^ *((u32_a_t*)rk[0][2]); + *((u32_a_t*)u.temp[3]) = *((u32_a_t*)(a+12)) ^ *((u32_a_t*)rk[0][3]); + *((u32_a_t*)(b )) = (*((u32_a_t*)T1[u.temp[0][0]]) + ^ *((u32_a_t*)T2[u.temp[1][1]]) + ^ *((u32_a_t*)T3[u.temp[2][2]]) + ^ *((u32_a_t*)T4[u.temp[3][3]])); + *((u32_a_t*)(b + 4)) = (*((u32_a_t*)T1[u.temp[1][0]]) + ^ *((u32_a_t*)T2[u.temp[2][1]]) + ^ *((u32_a_t*)T3[u.temp[3][2]]) + ^ *((u32_a_t*)T4[u.temp[0][3]])); + *((u32_a_t*)(b + 8)) = (*((u32_a_t*)T1[u.temp[2][0]]) + ^ *((u32_a_t*)T2[u.temp[3][1]]) + ^ *((u32_a_t*)T3[u.temp[0][2]]) + ^ *((u32_a_t*)T4[u.temp[1][3]])); + *((u32_a_t*)(b +12)) = (*((u32_a_t*)T1[u.temp[3][0]]) + ^ *((u32_a_t*)T2[u.temp[0][1]]) + ^ *((u32_a_t*)T3[u.temp[1][2]]) + ^ *((u32_a_t*)T4[u.temp[2][3]])); + + for (r = 1; r < rounds-1; r++) { - *((u32*)u.temp[0]) = *((u32*)(b )) ^ *((u32*)rk[r][0]); - *((u32*)u.temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[r][1]); - *((u32*)u.temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[r][2]); - *((u32*)u.temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[r][3]); - - *((u32*)(b )) = (*((u32*)T1[u.temp[0][0]]) - ^ *((u32*)T2[u.temp[1][1]]) - ^ *((u32*)T3[u.temp[2][2]]) - ^ *((u32*)T4[u.temp[3][3]])); - *((u32*)(b + 4)) = (*((u32*)T1[u.temp[1][0]]) - ^ *((u32*)T2[u.temp[2][1]]) - ^ *((u32*)T3[u.temp[3][2]]) - ^ *((u32*)T4[u.temp[0][3]])); - *((u32*)(b + 8)) = (*((u32*)T1[u.temp[2][0]]) - ^ *((u32*)T2[u.temp[3][1]]) - ^ *((u32*)T3[u.temp[0][2]]) - ^ *((u32*)T4[u.temp[1][3]])); - *((u32*)(b +12)) = (*((u32*)T1[u.temp[3][0]]) - ^ *((u32*)T2[u.temp[0][1]]) - ^ *((u32*)T3[u.temp[1][2]]) - ^ *((u32*)T4[u.temp[2][3]])); + *((u32_a_t*)u.temp[0]) = *((u32_a_t*)(b )) ^ *((u32_a_t*)rk[r][0]); + *((u32_a_t*)u.temp[1]) = *((u32_a_t*)(b+ 4)) ^ *((u32_a_t*)rk[r][1]); + *((u32_a_t*)u.temp[2]) = *((u32_a_t*)(b+ 8)) ^ *((u32_a_t*)rk[r][2]); + *((u32_a_t*)u.temp[3]) = *((u32_a_t*)(b+12)) ^ *((u32_a_t*)rk[r][3]); + + *((u32_a_t*)(b )) = (*((u32_a_t*)T1[u.temp[0][0]]) + ^ *((u32_a_t*)T2[u.temp[1][1]]) + ^ *((u32_a_t*)T3[u.temp[2][2]]) + ^ *((u32_a_t*)T4[u.temp[3][3]])); + *((u32_a_t*)(b + 4)) = (*((u32_a_t*)T1[u.temp[1][0]]) + ^ *((u32_a_t*)T2[u.temp[2][1]]) + ^ *((u32_a_t*)T3[u.temp[3][2]]) + ^ *((u32_a_t*)T4[u.temp[0][3]])); + *((u32_a_t*)(b + 8)) = (*((u32_a_t*)T1[u.temp[2][0]]) + ^ *((u32_a_t*)T2[u.temp[3][1]]) + ^ *((u32_a_t*)T3[u.temp[0][2]]) + ^ *((u32_a_t*)T4[u.temp[1][3]])); + *((u32_a_t*)(b +12)) = (*((u32_a_t*)T1[u.temp[3][0]]) + ^ *((u32_a_t*)T2[u.temp[0][1]]) + ^ *((u32_a_t*)T3[u.temp[1][2]]) + ^ *((u32_a_t*)T4[u.temp[2][3]])); } - /* Last round is special. */ - *((u32*)u.temp[0]) = *((u32*)(b )) ^ *((u32*)rk[ROUNDS-1][0]); - *((u32*)u.temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[ROUNDS-1][1]); - *((u32*)u.temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[ROUNDS-1][2]); - *((u32*)u.temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[ROUNDS-1][3]); + /* Last round is special. */ + *((u32_a_t*)u.temp[0]) = *((u32_a_t*)(b )) ^ *((u32_a_t*)rk[rounds-1][0]); + *((u32_a_t*)u.temp[1]) = *((u32_a_t*)(b+ 4)) ^ *((u32_a_t*)rk[rounds-1][1]); + *((u32_a_t*)u.temp[2]) = *((u32_a_t*)(b+ 8)) ^ *((u32_a_t*)rk[rounds-1][2]); + *((u32_a_t*)u.temp[3]) = *((u32_a_t*)(b+12)) ^ *((u32_a_t*)rk[rounds-1][3]); b[ 0] = T1[u.temp[0][0]][1]; b[ 1] = T1[u.temp[1][1]][1]; b[ 2] = T1[u.temp[2][2]][1]; @@ -389,11 +855,12 @@ do_encrypt_aligned (const RIJNDAEL_context *ctx, b[13] = T1[u.temp[0][1]][1]; b[14] = T1[u.temp[1][2]][1]; b[15] = T1[u.temp[2][3]][1]; - *((u32*)(b )) ^= *((u32*)rk[ROUNDS][0]); - *((u32*)(b+ 4)) ^= *((u32*)rk[ROUNDS][1]); - *((u32*)(b+ 8)) ^= *((u32*)rk[ROUNDS][2]); - *((u32*)(b+12)) ^= *((u32*)rk[ROUNDS][3]); + *((u32_a_t*)(b )) ^= *((u32_a_t*)rk[rounds][0]); + *((u32_a_t*)(b+ 4)) ^= *((u32_a_t*)rk[rounds][1]); + *((u32_a_t*)(b+ 8)) ^= *((u32_a_t*)rk[rounds][2]); + *((u32_a_t*)(b+12)) ^= *((u32_a_t*)rk[rounds][3]); #undef rk +#endif /*!USE_AMD64_ASM && !USE_ARM_ASM*/ } @@ -401,22 +868,31 @@ static void do_encrypt (const RIJNDAEL_context *ctx, unsigned char *bx, const unsigned char *ax) { - /* BX and AX are not necessary correctly aligned. Thus we need to - copy them here. */ - union - { - u32 dummy[4]; - byte a[16]; - } a; - union - { - u32 dummy[4]; - byte b[16]; - } b; +#if !defined(USE_AMD64_ASM) && !defined(USE_ARM_ASM) + /* BX and AX are not necessary correctly aligned. Thus we might + need to copy them here. We try to align to a 16 bytes. */ + if (((size_t)ax & 0x0f) || ((size_t)bx & 0x0f)) + { + union + { + u32 dummy[4]; + byte a[16] ATTR_ALIGNED_16; + } a; + union + { + u32 dummy[4]; + byte b[16] ATTR_ALIGNED_16; + } b; - memcpy (a.a, ax, 16); - do_encrypt_aligned (ctx, b.b, a.a); - memcpy (bx, b.b, 16); + buf_cpy (a.a, ax, 16); + do_encrypt_aligned (ctx, b.b, a.a); + buf_cpy (bx, b.b, 16); + } + else +#endif /*!USE_AMD64_ASM && !USE_ARM_ASM*/ + { + do_encrypt_aligned (ctx, bx, ax); + } } @@ -432,11 +908,12 @@ do_padlock (const RIJNDAEL_context *ctx, int decrypt_flag, unsigned char a[16] __attribute__ ((aligned (16))); unsigned char b[16] __attribute__ ((aligned (16))); unsigned int cword[4] __attribute__ ((aligned (16))); + int blocks; /* The control word fields are: 127:12 11:10 9 8 7 6 5 4 3:0 RESERVED KSIZE CRYPT INTER KEYGN CIPHR ALIGN DGEST ROUND */ - cword[0] = (ctx->ROUNDS & 15); /* (The mask is just a safeguard.) */ + cword[0] = (ctx->rounds & 15); /* (The mask is just a safeguard.) */ cword[1] = 0; cword[2] = 0; cword[3] = 0; @@ -444,18 +921,29 @@ do_padlock (const RIJNDAEL_context *ctx, int decrypt_flag, cword[0] |= 0x00000200; memcpy (a, ax, 16); - - asm volatile - ("pushfl\n\t" /* Force key reload. */ + + blocks = 1; /* Init counter for just one block. */ +#ifdef __x86_64__ + asm volatile + ("pushfq\n\t" /* Force key reload. */ + "popfq\n\t" + ".byte 0xf3, 0x0f, 0xa7, 0xc8\n\t" /* REP XCRYPT ECB. */ + : /* No output */ + : "S" (a), "D" (b), "d" (cword), "b" (ctx->padlockkey), "c" (blocks) + : "cc", "memory" + ); +#else + asm volatile + ("pushfl\n\t" /* Force key reload. */ "popfl\n\t" "xchg %3, %%ebx\n\t" /* Load key. */ - "movl $1, %%ecx\n\t" /* Init counter for just one block. */ - ".byte 0xf3, 0x0f, 0xa7, 0xc8\n\t" /* REP XSTORE ECB. */ + ".byte 0xf3, 0x0f, 0xa7, 0xc8\n\t" /* REP XCRYPT ECB. */ "xchg %3, %%ebx\n" /* Restore GOT register. */ : /* No output */ - : "S" (a), "D" (b), "d" (cword), "r" (ctx->padlock_key) - : "%ecx", "cc", "memory" + : "S" (a), "D" (b), "d" (cword), "r" (ctx->padlockkey), "c" (blocks) + : "cc", "memory" ); +#endif memcpy (bx, b, 16); @@ -463,23 +951,721 @@ do_padlock (const RIJNDAEL_context *ctx, int decrypt_flag, #endif /*USE_PADLOCK*/ +#ifdef USE_AESNI +/* Encrypt one block using the Intel AES-NI instructions. A and B may + be the same. + + Our problem here is that gcc does not allow the "x" constraint for + SSE registers in asm unless you compile with -msse. The common + wisdom is to use a separate file for SSE instructions and build it + separately. This would require a lot of extra build system stuff, + similar to what we do in mpi/ for the asm stuff. What we do + instead is to use standard registers and a bit more of plain asm + which copies the data and key stuff to the SSE registers and later + back. If we decide to implement some block modes with parallelized + AES instructions, it might indeed be better to use plain asm ala + mpi/. */ +static inline void +do_aesni_enc (const RIJNDAEL_context *ctx, unsigned char *b, + const unsigned char *a) +{ +#define aesenc_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xc1\n\t" +#define aesenclast_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xc1\n\t" + /* Note: For now we relax the alignment requirement for A and B: It + does not make much difference because in many case we would need + to memcpy them to an extra buffer; using the movdqu is much faster + that memcpy and movdqa. For CFB we know that the IV is properly + aligned but that is a special case. We should better implement + CFB direct in asm. */ + asm volatile ("movdqu %[src], %%xmm0\n\t" /* xmm0 := *a */ + "movdqa (%[key]), %%xmm1\n\t" /* xmm1 := key[0] */ + "pxor %%xmm1, %%xmm0\n\t" /* xmm0 ^= key[0] */ + "movdqa 0x10(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x20(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x30(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x40(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x50(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x60(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x70(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x80(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x90(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0xa0(%[key]), %%xmm1\n\t" + "cmpl $10, %[rounds]\n\t" + "jz .Lenclast%=\n\t" + aesenc_xmm1_xmm0 + "movdqa 0xb0(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0xc0(%[key]), %%xmm1\n\t" + "cmpl $12, %[rounds]\n\t" + "jz .Lenclast%=\n\t" + aesenc_xmm1_xmm0 + "movdqa 0xd0(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0xe0(%[key]), %%xmm1\n" + + ".Lenclast%=:\n\t" + aesenclast_xmm1_xmm0 + "movdqu %%xmm0, %[dst]\n" + : [dst] "=m" (*b) + : [src] "m" (*a), + [key] "r" (ctx->keyschenc), + [rounds] "r" (ctx->rounds) + : "cc", "memory"); +#undef aesenc_xmm1_xmm0 +#undef aesenclast_xmm1_xmm0 +} + + +static inline void +do_aesni_dec (const RIJNDAEL_context *ctx, unsigned char *b, + const unsigned char *a) +{ +#define aesdec_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xde, 0xc1\n\t" +#define aesdeclast_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdf, 0xc1\n\t" + asm volatile ("movdqu %[src], %%xmm0\n\t" /* xmm0 := *a */ + "movdqa (%[key]), %%xmm1\n\t" + "pxor %%xmm1, %%xmm0\n\t" /* xmm0 ^= key[0] */ + "movdqa 0x10(%[key]), %%xmm1\n\t" + aesdec_xmm1_xmm0 + "movdqa 0x20(%[key]), %%xmm1\n\t" + aesdec_xmm1_xmm0 + "movdqa 0x30(%[key]), %%xmm1\n\t" + aesdec_xmm1_xmm0 + "movdqa 0x40(%[key]), %%xmm1\n\t" + aesdec_xmm1_xmm0 + "movdqa 0x50(%[key]), %%xmm1\n\t" + aesdec_xmm1_xmm0 + "movdqa 0x60(%[key]), %%xmm1\n\t" + aesdec_xmm1_xmm0 + "movdqa 0x70(%[key]), %%xmm1\n\t" + aesdec_xmm1_xmm0 + "movdqa 0x80(%[key]), %%xmm1\n\t" + aesdec_xmm1_xmm0 + "movdqa 0x90(%[key]), %%xmm1\n\t" + aesdec_xmm1_xmm0 + "movdqa 0xa0(%[key]), %%xmm1\n\t" + "cmpl $10, %[rounds]\n\t" + "jz .Ldeclast%=\n\t" + aesdec_xmm1_xmm0 + "movdqa 0xb0(%[key]), %%xmm1\n\t" + aesdec_xmm1_xmm0 + "movdqa 0xc0(%[key]), %%xmm1\n\t" + "cmpl $12, %[rounds]\n\t" + "jz .Ldeclast%=\n\t" + aesdec_xmm1_xmm0 + "movdqa 0xd0(%[key]), %%xmm1\n\t" + aesdec_xmm1_xmm0 + "movdqa 0xe0(%[key]), %%xmm1\n" + + ".Ldeclast%=:\n\t" + aesdeclast_xmm1_xmm0 + "movdqu %%xmm0, %[dst]\n" + : [dst] "=m" (*b) + : [src] "m" (*a), + [key] "r" (ctx->keyschdec), + [rounds] "r" (ctx->rounds) + : "cc", "memory"); +#undef aesdec_xmm1_xmm0 +#undef aesdeclast_xmm1_xmm0 +} + + +/* Encrypt four blocks using the Intel AES-NI instructions. Blocks are input + * and output through SSE registers xmm1 to xmm4. */ +static void +do_aesni_enc_vec4 (const RIJNDAEL_context *ctx) +{ +#define aesenc_xmm0_xmm1 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xc8\n\t" +#define aesenc_xmm0_xmm2 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xd0\n\t" +#define aesenc_xmm0_xmm3 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xd8\n\t" +#define aesenc_xmm0_xmm4 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xe0\n\t" +#define aesenclast_xmm0_xmm1 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xc8\n\t" +#define aesenclast_xmm0_xmm2 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xd0\n\t" +#define aesenclast_xmm0_xmm3 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xd8\n\t" +#define aesenclast_xmm0_xmm4 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xe0\n\t" + asm volatile ("movdqa (%[key]), %%xmm0\n\t" + "pxor %%xmm0, %%xmm1\n\t" /* xmm1 ^= key[0] */ + "pxor %%xmm0, %%xmm2\n\t" /* xmm2 ^= key[0] */ + "pxor %%xmm0, %%xmm3\n\t" /* xmm3 ^= key[0] */ + "pxor %%xmm0, %%xmm4\n\t" /* xmm4 ^= key[0] */ + "movdqa 0x10(%[key]), %%xmm0\n\t" + aesenc_xmm0_xmm1 + aesenc_xmm0_xmm2 + aesenc_xmm0_xmm3 + aesenc_xmm0_xmm4 + "movdqa 0x20(%[key]), %%xmm0\n\t" + aesenc_xmm0_xmm1 + aesenc_xmm0_xmm2 + aesenc_xmm0_xmm3 + aesenc_xmm0_xmm4 + "movdqa 0x30(%[key]), %%xmm0\n\t" + aesenc_xmm0_xmm1 + aesenc_xmm0_xmm2 + aesenc_xmm0_xmm3 + aesenc_xmm0_xmm4 + "movdqa 0x40(%[key]), %%xmm0\n\t" + aesenc_xmm0_xmm1 + aesenc_xmm0_xmm2 + aesenc_xmm0_xmm3 + aesenc_xmm0_xmm4 + "movdqa 0x50(%[key]), %%xmm0\n\t" + aesenc_xmm0_xmm1 + aesenc_xmm0_xmm2 + aesenc_xmm0_xmm3 + aesenc_xmm0_xmm4 + "movdqa 0x60(%[key]), %%xmm0\n\t" + aesenc_xmm0_xmm1 + aesenc_xmm0_xmm2 + aesenc_xmm0_xmm3 + aesenc_xmm0_xmm4 + "movdqa 0x70(%[key]), %%xmm0\n\t" + aesenc_xmm0_xmm1 + aesenc_xmm0_xmm2 + aesenc_xmm0_xmm3 + aesenc_xmm0_xmm4 + "movdqa 0x80(%[key]), %%xmm0\n\t" + aesenc_xmm0_xmm1 + aesenc_xmm0_xmm2 + aesenc_xmm0_xmm3 + aesenc_xmm0_xmm4 + "movdqa 0x90(%[key]), %%xmm0\n\t" + aesenc_xmm0_xmm1 + aesenc_xmm0_xmm2 + aesenc_xmm0_xmm3 + aesenc_xmm0_xmm4 + "movdqa 0xa0(%[key]), %%xmm0\n\t" + "cmpl $10, %[rounds]\n\t" + "jz .Ldeclast%=\n\t" + aesenc_xmm0_xmm1 + aesenc_xmm0_xmm2 + aesenc_xmm0_xmm3 + aesenc_xmm0_xmm4 + "movdqa 0xb0(%[key]), %%xmm0\n\t" + aesenc_xmm0_xmm1 + aesenc_xmm0_xmm2 + aesenc_xmm0_xmm3 + aesenc_xmm0_xmm4 + "movdqa 0xc0(%[key]), %%xmm0\n\t" + "cmpl $12, %[rounds]\n\t" + "jz .Ldeclast%=\n\t" + aesenc_xmm0_xmm1 + aesenc_xmm0_xmm2 + aesenc_xmm0_xmm3 + aesenc_xmm0_xmm4 + "movdqa 0xd0(%[key]), %%xmm0\n\t" + aesenc_xmm0_xmm1 + aesenc_xmm0_xmm2 + aesenc_xmm0_xmm3 + aesenc_xmm0_xmm4 + "movdqa 0xe0(%[key]), %%xmm0\n" + + ".Ldeclast%=:\n\t" + aesenclast_xmm0_xmm1 + aesenclast_xmm0_xmm2 + aesenclast_xmm0_xmm3 + aesenclast_xmm0_xmm4 + : /* no output */ + : [key] "r" (ctx->keyschenc), + [rounds] "r" (ctx->rounds) + : "cc", "memory"); +#undef aesenc_xmm0_xmm1 +#undef aesenc_xmm0_xmm2 +#undef aesenc_xmm0_xmm3 +#undef aesenc_xmm0_xmm4 +#undef aesenclast_xmm0_xmm1 +#undef aesenclast_xmm0_xmm2 +#undef aesenclast_xmm0_xmm3 +#undef aesenclast_xmm0_xmm4 +} + + +/* Decrypt four blocks using the Intel AES-NI instructions. Blocks are input + * and output through SSE registers xmm1 to xmm4. */ +static void +do_aesni_dec_vec4 (const RIJNDAEL_context *ctx) +{ +#define aesdec_xmm0_xmm1 ".byte 0x66, 0x0f, 0x38, 0xde, 0xc8\n\t" +#define aesdec_xmm0_xmm2 ".byte 0x66, 0x0f, 0x38, 0xde, 0xd0\n\t" +#define aesdec_xmm0_xmm3 ".byte 0x66, 0x0f, 0x38, 0xde, 0xd8\n\t" +#define aesdec_xmm0_xmm4 ".byte 0x66, 0x0f, 0x38, 0xde, 0xe0\n\t" +#define aesdeclast_xmm0_xmm1 ".byte 0x66, 0x0f, 0x38, 0xdf, 0xc8\n\t" +#define aesdeclast_xmm0_xmm2 ".byte 0x66, 0x0f, 0x38, 0xdf, 0xd0\n\t" +#define aesdeclast_xmm0_xmm3 ".byte 0x66, 0x0f, 0x38, 0xdf, 0xd8\n\t" +#define aesdeclast_xmm0_xmm4 ".byte 0x66, 0x0f, 0x38, 0xdf, 0xe0\n\t" + asm volatile ("movdqa (%[key]), %%xmm0\n\t" + "pxor %%xmm0, %%xmm1\n\t" /* xmm1 ^= key[0] */ + "pxor %%xmm0, %%xmm2\n\t" /* xmm2 ^= key[0] */ + "pxor %%xmm0, %%xmm3\n\t" /* xmm3 ^= key[0] */ + "pxor %%xmm0, %%xmm4\n\t" /* xmm4 ^= key[0] */ + "movdqa 0x10(%[key]), %%xmm0\n\t" + aesdec_xmm0_xmm1 + aesdec_xmm0_xmm2 + aesdec_xmm0_xmm3 + aesdec_xmm0_xmm4 + "movdqa 0x20(%[key]), %%xmm0\n\t" + aesdec_xmm0_xmm1 + aesdec_xmm0_xmm2 + aesdec_xmm0_xmm3 + aesdec_xmm0_xmm4 + "movdqa 0x30(%[key]), %%xmm0\n\t" + aesdec_xmm0_xmm1 + aesdec_xmm0_xmm2 + aesdec_xmm0_xmm3 + aesdec_xmm0_xmm4 + "movdqa 0x40(%[key]), %%xmm0\n\t" + aesdec_xmm0_xmm1 + aesdec_xmm0_xmm2 + aesdec_xmm0_xmm3 + aesdec_xmm0_xmm4 + "movdqa 0x50(%[key]), %%xmm0\n\t" + aesdec_xmm0_xmm1 + aesdec_xmm0_xmm2 + aesdec_xmm0_xmm3 + aesdec_xmm0_xmm4 + "movdqa 0x60(%[key]), %%xmm0\n\t" + aesdec_xmm0_xmm1 + aesdec_xmm0_xmm2 + aesdec_xmm0_xmm3 + aesdec_xmm0_xmm4 + "movdqa 0x70(%[key]), %%xmm0\n\t" + aesdec_xmm0_xmm1 + aesdec_xmm0_xmm2 + aesdec_xmm0_xmm3 + aesdec_xmm0_xmm4 + "movdqa 0x80(%[key]), %%xmm0\n\t" + aesdec_xmm0_xmm1 + aesdec_xmm0_xmm2 + aesdec_xmm0_xmm3 + aesdec_xmm0_xmm4 + "movdqa 0x90(%[key]), %%xmm0\n\t" + aesdec_xmm0_xmm1 + aesdec_xmm0_xmm2 + aesdec_xmm0_xmm3 + aesdec_xmm0_xmm4 + "movdqa 0xa0(%[key]), %%xmm0\n\t" + "cmpl $10, %[rounds]\n\t" + "jz .Ldeclast%=\n\t" + aesdec_xmm0_xmm1 + aesdec_xmm0_xmm2 + aesdec_xmm0_xmm3 + aesdec_xmm0_xmm4 + "movdqa 0xb0(%[key]), %%xmm0\n\t" + aesdec_xmm0_xmm1 + aesdec_xmm0_xmm2 + aesdec_xmm0_xmm3 + aesdec_xmm0_xmm4 + "movdqa 0xc0(%[key]), %%xmm0\n\t" + "cmpl $12, %[rounds]\n\t" + "jz .Ldeclast%=\n\t" + aesdec_xmm0_xmm1 + aesdec_xmm0_xmm2 + aesdec_xmm0_xmm3 + aesdec_xmm0_xmm4 + "movdqa 0xd0(%[key]), %%xmm0\n\t" + aesdec_xmm0_xmm1 + aesdec_xmm0_xmm2 + aesdec_xmm0_xmm3 + aesdec_xmm0_xmm4 + "movdqa 0xe0(%[key]), %%xmm0\n" + + ".Ldeclast%=:\n\t" + aesdeclast_xmm0_xmm1 + aesdeclast_xmm0_xmm2 + aesdeclast_xmm0_xmm3 + aesdeclast_xmm0_xmm4 + : /* no output */ + : [key] "r" (ctx->keyschdec), + [rounds] "r" (ctx->rounds) + : "cc", "memory"); +#undef aesdec_xmm0_xmm1 +#undef aesdec_xmm0_xmm2 +#undef aesdec_xmm0_xmm3 +#undef aesdec_xmm0_xmm4 +#undef aesdeclast_xmm0_xmm1 +#undef aesdeclast_xmm0_xmm2 +#undef aesdeclast_xmm0_xmm3 +#undef aesdeclast_xmm0_xmm4 +} + + +/* Perform a CFB encryption or decryption round using the + initialization vector IV and the input block A. Write the result + to the output block B and update IV. IV needs to be 16 byte + aligned. */ +static void +do_aesni_cfb (const RIJNDAEL_context *ctx, int decrypt_flag, + unsigned char *iv, unsigned char *b, const unsigned char *a) +{ +#define aesenc_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xc1\n\t" +#define aesenclast_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xc1\n\t" + asm volatile ("movdqa %[iv], %%xmm0\n\t" /* xmm0 := IV */ + "movdqa (%[key]), %%xmm1\n\t" /* xmm1 := key[0] */ + "pxor %%xmm1, %%xmm0\n\t" /* xmm0 ^= key[0] */ + "movdqa 0x10(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x20(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x30(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x40(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x50(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x60(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x70(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x80(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x90(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0xa0(%[key]), %%xmm1\n\t" + "cmpl $10, %[rounds]\n\t" + "jz .Lenclast%=\n\t" + aesenc_xmm1_xmm0 + "movdqa 0xb0(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0xc0(%[key]), %%xmm1\n\t" + "cmpl $12, %[rounds]\n\t" + "jz .Lenclast%=\n\t" + aesenc_xmm1_xmm0 + "movdqa 0xd0(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0xe0(%[key]), %%xmm1\n" + + ".Lenclast%=:\n\t" + aesenclast_xmm1_xmm0 + "movdqu %[src], %%xmm1\n\t" /* Save input. */ + "pxor %%xmm1, %%xmm0\n\t" /* xmm0 = input ^ IV */ + + "cmpl $1, %[decrypt]\n\t" + "jz .Ldecrypt_%=\n\t" + "movdqa %%xmm0, %[iv]\n\t" /* [encrypt] Store IV. */ + "jmp .Lleave_%=\n" + ".Ldecrypt_%=:\n\t" + "movdqa %%xmm1, %[iv]\n" /* [decrypt] Store IV. */ + ".Lleave_%=:\n\t" + "movdqu %%xmm0, %[dst]\n" /* Store output. */ + : [iv] "+m" (*iv), [dst] "=m" (*b) + : [src] "m" (*a), + [key] "r" (ctx->keyschenc), + [rounds] "g" (ctx->rounds), + [decrypt] "m" (decrypt_flag) + : "cc", "memory"); +#undef aesenc_xmm1_xmm0 +#undef aesenclast_xmm1_xmm0 +} + +/* Perform a CTR encryption round using the counter CTR and the input + block A. Write the result to the output block B and update CTR. + CTR needs to be a 16 byte aligned little-endian value. */ +static void +do_aesni_ctr (const RIJNDAEL_context *ctx, + unsigned char *ctr, unsigned char *b, const unsigned char *a) +{ +#define aesenc_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xc1\n\t" +#define aesenclast_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xc1\n\t" + + asm volatile ("movdqa %%xmm5, %%xmm0\n\t" /* xmm0 := CTR (xmm5) */ + "pcmpeqd %%xmm1, %%xmm1\n\t" + "psrldq $8, %%xmm1\n\t" /* xmm1 = -1 */ + + "pshufb %%xmm6, %%xmm5\n\t" + "psubq %%xmm1, %%xmm5\n\t" /* xmm5++ (big endian) */ + + /* detect if 64-bit carry handling is needed */ + "cmpl $0xffffffff, 8(%[ctr])\n\t" + "jne .Lno_carry%=\n\t" + "cmpl $0xffffffff, 12(%[ctr])\n\t" + "jne .Lno_carry%=\n\t" + + "pslldq $8, %%xmm1\n\t" /* move lower 64-bit to high */ + "psubq %%xmm1, %%xmm5\n\t" /* add carry to upper 64bits */ + + ".Lno_carry%=:\n\t" + + "pshufb %%xmm6, %%xmm5\n\t" + "movdqa %%xmm5, (%[ctr])\n\t" /* Update CTR (mem). */ + + "pxor (%[key]), %%xmm0\n\t" /* xmm1 ^= key[0] */ + "movdqa 0x10(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x20(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x30(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x40(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x50(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x60(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x70(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x80(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0x90(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0xa0(%[key]), %%xmm1\n\t" + "cmpl $10, %[rounds]\n\t" + "jz .Lenclast%=\n\t" + aesenc_xmm1_xmm0 + "movdqa 0xb0(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0xc0(%[key]), %%xmm1\n\t" + "cmpl $12, %[rounds]\n\t" + "jz .Lenclast%=\n\t" + aesenc_xmm1_xmm0 + "movdqa 0xd0(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + "movdqa 0xe0(%[key]), %%xmm1\n" + + ".Lenclast%=:\n\t" + aesenclast_xmm1_xmm0 + "movdqu %[src], %%xmm1\n\t" /* xmm1 := input */ + "pxor %%xmm1, %%xmm0\n\t" /* EncCTR ^= input */ + "movdqu %%xmm0, %[dst]" /* Store EncCTR. */ + + : [dst] "=m" (*b) + : [src] "m" (*a), + [ctr] "r" (ctr), + [key] "r" (ctx->keyschenc), + [rounds] "g" (ctx->rounds) + : "cc", "memory"); +#undef aesenc_xmm1_xmm0 +#undef aesenclast_xmm1_xmm0 +} + + +/* Four blocks at a time variant of do_aesni_ctr. */ static void +do_aesni_ctr_4 (const RIJNDAEL_context *ctx, + unsigned char *ctr, unsigned char *b, const unsigned char *a) +{ +#define aesenc_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xc1\n\t" +#define aesenc_xmm1_xmm2 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xd1\n\t" +#define aesenc_xmm1_xmm3 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xd9\n\t" +#define aesenc_xmm1_xmm4 ".byte 0x66, 0x0f, 0x38, 0xdc, 0xe1\n\t" +#define aesenclast_xmm1_xmm0 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xc1\n\t" +#define aesenclast_xmm1_xmm2 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xd1\n\t" +#define aesenclast_xmm1_xmm3 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xd9\n\t" +#define aesenclast_xmm1_xmm4 ".byte 0x66, 0x0f, 0x38, 0xdd, 0xe1\n\t" + + /* Register usage: + esi keyschedule + xmm0 CTR-0 + xmm1 temp / round key + xmm2 CTR-1 + xmm3 CTR-2 + xmm4 CTR-3 + xmm5 copy of *ctr + xmm6 endian swapping mask + */ + + asm volatile ("movdqa %%xmm5, %%xmm0\n\t" /* xmm0, xmm2 := CTR (xmm5) */ + "movdqa %%xmm0, %%xmm2\n\t" + "pcmpeqd %%xmm1, %%xmm1\n\t" + "psrldq $8, %%xmm1\n\t" /* xmm1 = -1 */ + + "pshufb %%xmm6, %%xmm2\n\t" /* xmm2 := le(xmm2) */ + "psubq %%xmm1, %%xmm2\n\t" /* xmm2++ */ + "movdqa %%xmm2, %%xmm3\n\t" /* xmm3 := xmm2 */ + "psubq %%xmm1, %%xmm3\n\t" /* xmm3++ */ + "movdqa %%xmm3, %%xmm4\n\t" /* xmm4 := xmm3 */ + "psubq %%xmm1, %%xmm4\n\t" /* xmm4++ */ + "movdqa %%xmm4, %%xmm5\n\t" /* xmm5 := xmm4 */ + "psubq %%xmm1, %%xmm5\n\t" /* xmm5++ */ + + /* detect if 64-bit carry handling is needed */ + "cmpl $0xffffffff, 8(%[ctr])\n\t" + "jne .Lno_carry%=\n\t" + "movl 12(%[ctr]), %%esi\n\t" + "bswapl %%esi\n\t" + "cmpl $0xfffffffc, %%esi\n\t" + "jb .Lno_carry%=\n\t" /* no carry */ + + "pslldq $8, %%xmm1\n\t" /* move lower 64-bit to high */ + "je .Lcarry_xmm5%=\n\t" /* esi == 0xfffffffc */ + "cmpl $0xfffffffe, %%esi\n\t" + "jb .Lcarry_xmm4%=\n\t" /* esi == 0xfffffffd */ + "je .Lcarry_xmm3%=\n\t" /* esi == 0xfffffffe */ + /* esi == 0xffffffff */ + + "psubq %%xmm1, %%xmm2\n\t" + ".Lcarry_xmm3%=:\n\t" + "psubq %%xmm1, %%xmm3\n\t" + ".Lcarry_xmm4%=:\n\t" + "psubq %%xmm1, %%xmm4\n\t" + ".Lcarry_xmm5%=:\n\t" + "psubq %%xmm1, %%xmm5\n\t" + + ".Lno_carry%=:\n\t" + "movdqa (%[key]), %%xmm1\n\t" /* xmm1 := key[0] */ + "movl %[rounds], %%esi\n\t" + + "pshufb %%xmm6, %%xmm2\n\t" /* xmm2 := be(xmm2) */ + "pshufb %%xmm6, %%xmm3\n\t" /* xmm3 := be(xmm3) */ + "pshufb %%xmm6, %%xmm4\n\t" /* xmm4 := be(xmm4) */ + "pshufb %%xmm6, %%xmm5\n\t" /* xmm5 := be(xmm5) */ + "movdqa %%xmm5, (%[ctr])\n\t" /* Update CTR (mem). */ + + "pxor %%xmm1, %%xmm0\n\t" /* xmm0 ^= key[0] */ + "pxor %%xmm1, %%xmm2\n\t" /* xmm2 ^= key[0] */ + "pxor %%xmm1, %%xmm3\n\t" /* xmm3 ^= key[0] */ + "pxor %%xmm1, %%xmm4\n\t" /* xmm4 ^= key[0] */ + "movdqa 0x10(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + aesenc_xmm1_xmm2 + aesenc_xmm1_xmm3 + aesenc_xmm1_xmm4 + "movdqa 0x20(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + aesenc_xmm1_xmm2 + aesenc_xmm1_xmm3 + aesenc_xmm1_xmm4 + "movdqa 0x30(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + aesenc_xmm1_xmm2 + aesenc_xmm1_xmm3 + aesenc_xmm1_xmm4 + "movdqa 0x40(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + aesenc_xmm1_xmm2 + aesenc_xmm1_xmm3 + aesenc_xmm1_xmm4 + "movdqa 0x50(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + aesenc_xmm1_xmm2 + aesenc_xmm1_xmm3 + aesenc_xmm1_xmm4 + "movdqa 0x60(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + aesenc_xmm1_xmm2 + aesenc_xmm1_xmm3 + aesenc_xmm1_xmm4 + "movdqa 0x70(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + aesenc_xmm1_xmm2 + aesenc_xmm1_xmm3 + aesenc_xmm1_xmm4 + "movdqa 0x80(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + aesenc_xmm1_xmm2 + aesenc_xmm1_xmm3 + aesenc_xmm1_xmm4 + "movdqa 0x90(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + aesenc_xmm1_xmm2 + aesenc_xmm1_xmm3 + aesenc_xmm1_xmm4 + "movdqa 0xa0(%[key]), %%xmm1\n\t" + "cmpl $10, %%esi\n\t" + "jz .Lenclast%=\n\t" + aesenc_xmm1_xmm0 + aesenc_xmm1_xmm2 + aesenc_xmm1_xmm3 + aesenc_xmm1_xmm4 + "movdqa 0xb0(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + aesenc_xmm1_xmm2 + aesenc_xmm1_xmm3 + aesenc_xmm1_xmm4 + "movdqa 0xc0(%[key]), %%xmm1\n\t" + "cmpl $12, %%esi\n\t" + "jz .Lenclast%=\n\t" + aesenc_xmm1_xmm0 + aesenc_xmm1_xmm2 + aesenc_xmm1_xmm3 + aesenc_xmm1_xmm4 + "movdqa 0xd0(%[key]), %%xmm1\n\t" + aesenc_xmm1_xmm0 + aesenc_xmm1_xmm2 + aesenc_xmm1_xmm3 + aesenc_xmm1_xmm4 + "movdqa 0xe0(%[key]), %%xmm1\n" + + ".Lenclast%=:\n\t" + aesenclast_xmm1_xmm0 + aesenclast_xmm1_xmm2 + aesenclast_xmm1_xmm3 + aesenclast_xmm1_xmm4 + + "movdqu (%[src]), %%xmm1\n\t" /* Get block 1. */ + "pxor %%xmm1, %%xmm0\n\t" /* EncCTR-1 ^= input */ + "movdqu %%xmm0, (%[dst])\n\t" /* Store block 1 */ + + "movdqu 16(%[src]), %%xmm1\n\t" /* Get block 2. */ + "pxor %%xmm1, %%xmm2\n\t" /* EncCTR-2 ^= input */ + "movdqu %%xmm2, 16(%[dst])\n\t" /* Store block 2. */ + + "movdqu 32(%[src]), %%xmm1\n\t" /* Get block 3. */ + "pxor %%xmm1, %%xmm3\n\t" /* EncCTR-3 ^= input */ + "movdqu %%xmm3, 32(%[dst])\n\t" /* Store block 3. */ + + "movdqu 48(%[src]), %%xmm1\n\t" /* Get block 4. */ + "pxor %%xmm1, %%xmm4\n\t" /* EncCTR-4 ^= input */ + "movdqu %%xmm4, 48(%[dst])" /* Store block 4. */ + + : + : [ctr] "r" (ctr), + [src] "r" (a), + [dst] "r" (b), + [key] "r" (ctx->keyschenc), + [rounds] "g" (ctx->rounds) + : "%esi", "cc", "memory"); +#undef aesenc_xmm1_xmm0 +#undef aesenc_xmm1_xmm2 +#undef aesenc_xmm1_xmm3 +#undef aesenc_xmm1_xmm4 +#undef aesenclast_xmm1_xmm0 +#undef aesenclast_xmm1_xmm2 +#undef aesenclast_xmm1_xmm3 +#undef aesenclast_xmm1_xmm4 +} + +#endif /*USE_AESNI*/ + + +static unsigned int rijndael_encrypt (void *context, byte *b, const byte *a) { RIJNDAEL_context *ctx = context; + unsigned int burn_stack; + if (0) + ; #ifdef USE_PADLOCK - if (ctx->use_padlock) + else if (ctx->use_padlock) { do_padlock (ctx, 0, b, a); - _gcry_burn_stack (48 + 15 /* possible padding for alignment */); + burn_stack = (48 + 15 /* possible padding for alignment */); } - else #endif /*USE_PADLOCK*/ +#ifdef USE_AESNI + else if (ctx->use_aesni) + { + aesni_prepare (); + do_aesni_enc (ctx, b, a); + aesni_cleanup (); + burn_stack = 0; + } +#endif /*USE_AESNI*/ + else { do_encrypt (ctx, b, a); - _gcry_burn_stack (48 + 2*sizeof(int)); + burn_stack = (56 + 2*sizeof(int)); } + + return burn_stack; } @@ -488,18 +1674,19 @@ rijndael_encrypt (void *context, byte *b, const byte *a) function is only intended for the bulk encryption feature of cipher.c. */ void -_gcry_aes_cfb_enc (void *context, unsigned char *iv, +_gcry_aes_cfb_enc (void *context, unsigned char *iv, void *outbuf_arg, const void *inbuf_arg, - unsigned int nblocks) + size_t nblocks) { RIJNDAEL_context *ctx = context; unsigned char *outbuf = outbuf_arg; const unsigned char *inbuf = inbuf_arg; - unsigned char *ivp; - int i; + unsigned int burn_depth = 48 + 2*sizeof(int); + if (0) + ; #ifdef USE_PADLOCK - if (ctx->use_padlock) + else if (ctx->use_padlock) { /* Fixme: Let Padlock do the CFBing. */ for ( ;nblocks; nblocks-- ) @@ -507,24 +1694,42 @@ _gcry_aes_cfb_enc (void *context, unsigned char *iv, /* Encrypt the IV. */ do_padlock (ctx, 0, iv, iv); /* XOR the input with the IV and store input into IV. */ - for (ivp=iv,i=0; i < BLOCKSIZE; i++ ) - *outbuf++ = (*ivp++ ^= *inbuf++); + buf_xor_2dst(outbuf, iv, inbuf, BLOCKSIZE); + outbuf += BLOCKSIZE; + inbuf += BLOCKSIZE; } } +#endif /*USE_PADLOCK*/ +#ifdef USE_AESNI + else if (ctx->use_aesni) + { + aesni_prepare (); + for ( ;nblocks; nblocks-- ) + { + do_aesni_cfb (ctx, 0, iv, outbuf, inbuf); + outbuf += BLOCKSIZE; + inbuf += BLOCKSIZE; + } + aesni_cleanup (); + + burn_depth = 0; /* No stack usage. */ + } +#endif /*USE_AESNI*/ else -#endif /* USE_PADLOCK*/ { for ( ;nblocks; nblocks-- ) { /* Encrypt the IV. */ do_encrypt_aligned (ctx, iv, iv); /* XOR the input with the IV and store input into IV. */ - for (ivp=iv,i=0; i < BLOCKSIZE; i++ ) - *outbuf++ = (*ivp++ ^= *inbuf++); + buf_xor_2dst(outbuf, iv, inbuf, BLOCKSIZE); + outbuf += BLOCKSIZE; + inbuf += BLOCKSIZE; } } - _gcry_burn_stack (48 + 2*sizeof(int)); + if (burn_depth) + _gcry_burn_stack (burn_depth); } @@ -533,35 +1738,173 @@ _gcry_aes_cfb_enc (void *context, unsigned char *iv, function is only intended for the bulk encryption feature of cipher.c. */ void -_gcry_aes_cbc_enc (void *context, unsigned char *iv, +_gcry_aes_cbc_enc (void *context, unsigned char *iv, void *outbuf_arg, const void *inbuf_arg, - unsigned int nblocks, int cbc_mac) + size_t nblocks, int cbc_mac) { RIJNDAEL_context *ctx = context; unsigned char *outbuf = outbuf_arg; const unsigned char *inbuf = inbuf_arg; - unsigned char *ivp; - int i; + unsigned char *last_iv; + unsigned int burn_depth = 48 + 2*sizeof(int); +#ifdef USE_AESNI + int use_aesni = ctx->use_aesni; +#endif + +#ifdef USE_AESNI + if (use_aesni) + aesni_prepare (); +#endif /*USE_AESNI*/ + + last_iv = iv; for ( ;nblocks; nblocks-- ) { - for (ivp=iv, i=0; i < BLOCKSIZE; i++ ) - outbuf[i] = inbuf[i] ^ *ivp++; + if (0) + ; +#ifdef USE_AESNI + else if (use_aesni) + { + /* ~35% speed up on Sandy-Bridge when doing xoring and copying with + SSE registers. */ + asm volatile ("movdqu %[iv], %%xmm0\n\t" + "movdqu %[inbuf], %%xmm1\n\t" + "pxor %%xmm0, %%xmm1\n\t" + "movdqu %%xmm1, %[outbuf]\n\t" + : /* No output */ + : [iv] "m" (*last_iv), + [inbuf] "m" (*inbuf), + [outbuf] "m" (*outbuf) + : "memory" ); + + do_aesni_enc (ctx, outbuf, outbuf); + } +#endif /*USE_AESNI*/ + else + { + buf_xor(outbuf, inbuf, last_iv, BLOCKSIZE); + if (0) + ; #ifdef USE_PADLOCK - if (ctx->use_padlock) - do_padlock (ctx, 0, outbuf, outbuf); - else + else if (ctx->use_padlock) + do_padlock (ctx, 0, outbuf, outbuf); #endif /*USE_PADLOCK*/ - do_encrypt (ctx, outbuf, outbuf ); + else + do_encrypt (ctx, outbuf, outbuf ); + } - memcpy (iv, outbuf, BLOCKSIZE); + last_iv = outbuf; inbuf += BLOCKSIZE; if (!cbc_mac) outbuf += BLOCKSIZE; } - _gcry_burn_stack (48 + 2*sizeof(int)); + if (last_iv != iv) + { + if (0) + ; +#ifdef USE_AESNI + else if (use_aesni) + asm volatile ("movdqu %[last], %%xmm0\n\t" + "movdqu %%xmm0, %[iv]\n\t" + : /* No output */ + : [last] "m" (*last_iv), + [iv] "m" (*iv) + : "memory" ); +#endif /*USE_AESNI*/ + else + buf_cpy (iv, last_iv, BLOCKSIZE); + } + +#ifdef USE_AESNI + if (use_aesni) + { + aesni_cleanup (); + burn_depth = 0; /* No stack usage. */ + } +#endif /*USE_AESNI*/ + + if (burn_depth) + _gcry_burn_stack (burn_depth); +} + + +/* Bulk encryption of complete blocks in CTR mode. Caller needs to + make sure that CTR is aligned on a 16 byte boundary if AESNI; the + minimum alignment is for an u32. This function is only intended + for the bulk encryption feature of cipher.c. CTR is expected to be + of size BLOCKSIZE. */ +void +_gcry_aes_ctr_enc (void *context, unsigned char *ctr, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks) +{ + RIJNDAEL_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned int burn_depth = 48 + 2*sizeof(int); + int i; + + if (0) + ; +#ifdef USE_AESNI + else if (ctx->use_aesni) + { + static const unsigned char be_mask[16] __attribute__ ((aligned (16))) = + { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + + aesni_prepare (); + + asm volatile ("movdqa %[mask], %%xmm6\n\t" /* Preload mask */ + "movdqa %[ctr], %%xmm5\n\t" /* Preload CTR */ + : /* No output */ + : [mask] "m" (*be_mask), + [ctr] "m" (*ctr) + : "memory"); + + for ( ;nblocks > 3 ; nblocks -= 4 ) + { + do_aesni_ctr_4 (ctx, ctr, outbuf, inbuf); + outbuf += 4*BLOCKSIZE; + inbuf += 4*BLOCKSIZE; + } + for ( ;nblocks; nblocks-- ) + { + do_aesni_ctr (ctx, ctr, outbuf, inbuf); + outbuf += BLOCKSIZE; + inbuf += BLOCKSIZE; + } + aesni_cleanup (); + aesni_cleanup_2_6 (); + + burn_depth = 0; /* No stack usage. */ + } +#endif /*USE_AESNI*/ + else + { + union { unsigned char x1[16]; u32 x32[4]; } tmp; + + for ( ;nblocks; nblocks-- ) + { + /* Encrypt the counter. */ + do_encrypt_aligned (ctx, tmp.x1, ctr); + /* XOR the input with the encrypted counter and store in output. */ + buf_xor(outbuf, tmp.x1, inbuf, BLOCKSIZE); + outbuf += BLOCKSIZE; + inbuf += BLOCKSIZE; + /* Increment the counter. */ + for (i = BLOCKSIZE; i > 0; i--) + { + ctr[i-1]++; + if (ctr[i-1]) + break; + } + } + } + + if (burn_depth) + _gcry_burn_stack (burn_depth); } @@ -570,70 +1913,75 @@ _gcry_aes_cbc_enc (void *context, unsigned char *iv, and the decryption must have been prepared. A and B may be the same. */ static void -do_decrypt_aligned (RIJNDAEL_context *ctx, +do_decrypt_aligned (RIJNDAEL_context *ctx, unsigned char *b, const unsigned char *a) { -#define rk (ctx->keySched2) - int ROUNDS = ctx->ROUNDS; +#ifdef USE_AMD64_ASM + _gcry_aes_amd64_decrypt_block(ctx->keyschdec, b, a, ctx->rounds); +#elif defined(USE_ARM_ASM) + _gcry_aes_arm_decrypt_block(ctx->keyschdec, b, a, ctx->rounds); +#else +#define rk (ctx->keyschdec) + int rounds = ctx->rounds; int r; - union + union { u32 tempu32[4]; /* Force correct alignment. */ byte temp[4][4]; } u; - *((u32*)u.temp[0]) = *((u32*)(a )) ^ *((u32*)rk[ROUNDS][0]); - *((u32*)u.temp[1]) = *((u32*)(a+ 4)) ^ *((u32*)rk[ROUNDS][1]); - *((u32*)u.temp[2]) = *((u32*)(a+ 8)) ^ *((u32*)rk[ROUNDS][2]); - *((u32*)u.temp[3]) = *((u32*)(a+12)) ^ *((u32*)rk[ROUNDS][3]); - - *((u32*)(b )) = (*((u32*)T5[u.temp[0][0]]) - ^ *((u32*)T6[u.temp[3][1]]) - ^ *((u32*)T7[u.temp[2][2]]) - ^ *((u32*)T8[u.temp[1][3]])); - *((u32*)(b+ 4)) = (*((u32*)T5[u.temp[1][0]]) - ^ *((u32*)T6[u.temp[0][1]]) - ^ *((u32*)T7[u.temp[3][2]]) - ^ *((u32*)T8[u.temp[2][3]])); - *((u32*)(b+ 8)) = (*((u32*)T5[u.temp[2][0]]) - ^ *((u32*)T6[u.temp[1][1]]) - ^ *((u32*)T7[u.temp[0][2]]) - ^ *((u32*)T8[u.temp[3][3]])); - *((u32*)(b+12)) = (*((u32*)T5[u.temp[3][0]]) - ^ *((u32*)T6[u.temp[2][1]]) - ^ *((u32*)T7[u.temp[1][2]]) - ^ *((u32*)T8[u.temp[0][3]])); - - for (r = ROUNDS-1; r > 1; r--) + *((u32_a_t*)u.temp[0]) = *((u32_a_t*)(a )) ^ *((u32_a_t*)rk[rounds][0]); + *((u32_a_t*)u.temp[1]) = *((u32_a_t*)(a+ 4)) ^ *((u32_a_t*)rk[rounds][1]); + *((u32_a_t*)u.temp[2]) = *((u32_a_t*)(a+ 8)) ^ *((u32_a_t*)rk[rounds][2]); + *((u32_a_t*)u.temp[3]) = *((u32_a_t*)(a+12)) ^ *((u32_a_t*)rk[rounds][3]); + + *((u32_a_t*)(b )) = (*((u32_a_t*)T5[u.temp[0][0]]) + ^ *((u32_a_t*)T6[u.temp[3][1]]) + ^ *((u32_a_t*)T7[u.temp[2][2]]) + ^ *((u32_a_t*)T8[u.temp[1][3]])); + *((u32_a_t*)(b+ 4)) = (*((u32_a_t*)T5[u.temp[1][0]]) + ^ *((u32_a_t*)T6[u.temp[0][1]]) + ^ *((u32_a_t*)T7[u.temp[3][2]]) + ^ *((u32_a_t*)T8[u.temp[2][3]])); + *((u32_a_t*)(b+ 8)) = (*((u32_a_t*)T5[u.temp[2][0]]) + ^ *((u32_a_t*)T6[u.temp[1][1]]) + ^ *((u32_a_t*)T7[u.temp[0][2]]) + ^ *((u32_a_t*)T8[u.temp[3][3]])); + *((u32_a_t*)(b+12)) = (*((u32_a_t*)T5[u.temp[3][0]]) + ^ *((u32_a_t*)T6[u.temp[2][1]]) + ^ *((u32_a_t*)T7[u.temp[1][2]]) + ^ *((u32_a_t*)T8[u.temp[0][3]])); + + for (r = rounds-1; r > 1; r--) { - *((u32*)u.temp[0]) = *((u32*)(b )) ^ *((u32*)rk[r][0]); - *((u32*)u.temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[r][1]); - *((u32*)u.temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[r][2]); - *((u32*)u.temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[r][3]); - *((u32*)(b )) = (*((u32*)T5[u.temp[0][0]]) - ^ *((u32*)T6[u.temp[3][1]]) - ^ *((u32*)T7[u.temp[2][2]]) - ^ *((u32*)T8[u.temp[1][3]])); - *((u32*)(b+ 4)) = (*((u32*)T5[u.temp[1][0]]) - ^ *((u32*)T6[u.temp[0][1]]) - ^ *((u32*)T7[u.temp[3][2]]) - ^ *((u32*)T8[u.temp[2][3]])); - *((u32*)(b+ 8)) = (*((u32*)T5[u.temp[2][0]]) - ^ *((u32*)T6[u.temp[1][1]]) - ^ *((u32*)T7[u.temp[0][2]]) - ^ *((u32*)T8[u.temp[3][3]])); - *((u32*)(b+12)) = (*((u32*)T5[u.temp[3][0]]) - ^ *((u32*)T6[u.temp[2][1]]) - ^ *((u32*)T7[u.temp[1][2]]) - ^ *((u32*)T8[u.temp[0][3]])); + *((u32_a_t*)u.temp[0]) = *((u32_a_t*)(b )) ^ *((u32_a_t*)rk[r][0]); + *((u32_a_t*)u.temp[1]) = *((u32_a_t*)(b+ 4)) ^ *((u32_a_t*)rk[r][1]); + *((u32_a_t*)u.temp[2]) = *((u32_a_t*)(b+ 8)) ^ *((u32_a_t*)rk[r][2]); + *((u32_a_t*)u.temp[3]) = *((u32_a_t*)(b+12)) ^ *((u32_a_t*)rk[r][3]); + *((u32_a_t*)(b )) = (*((u32_a_t*)T5[u.temp[0][0]]) + ^ *((u32_a_t*)T6[u.temp[3][1]]) + ^ *((u32_a_t*)T7[u.temp[2][2]]) + ^ *((u32_a_t*)T8[u.temp[1][3]])); + *((u32_a_t*)(b+ 4)) = (*((u32_a_t*)T5[u.temp[1][0]]) + ^ *((u32_a_t*)T6[u.temp[0][1]]) + ^ *((u32_a_t*)T7[u.temp[3][2]]) + ^ *((u32_a_t*)T8[u.temp[2][3]])); + *((u32_a_t*)(b+ 8)) = (*((u32_a_t*)T5[u.temp[2][0]]) + ^ *((u32_a_t*)T6[u.temp[1][1]]) + ^ *((u32_a_t*)T7[u.temp[0][2]]) + ^ *((u32_a_t*)T8[u.temp[3][3]])); + *((u32_a_t*)(b+12)) = (*((u32_a_t*)T5[u.temp[3][0]]) + ^ *((u32_a_t*)T6[u.temp[2][1]]) + ^ *((u32_a_t*)T7[u.temp[1][2]]) + ^ *((u32_a_t*)T8[u.temp[0][3]])); } - /* Last round is special. */ - *((u32*)u.temp[0]) = *((u32*)(b )) ^ *((u32*)rk[1][0]); - *((u32*)u.temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[1][1]); - *((u32*)u.temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[1][2]); - *((u32*)u.temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[1][3]); + /* Last round is special. */ + *((u32_a_t*)u.temp[0]) = *((u32_a_t*)(b )) ^ *((u32_a_t*)rk[1][0]); + *((u32_a_t*)u.temp[1]) = *((u32_a_t*)(b+ 4)) ^ *((u32_a_t*)rk[1][1]); + *((u32_a_t*)u.temp[2]) = *((u32_a_t*)(b+ 8)) ^ *((u32_a_t*)rk[1][2]); + *((u32_a_t*)u.temp[3]) = *((u32_a_t*)(b+12)) ^ *((u32_a_t*)rk[1][3]); b[ 0] = S5[u.temp[0][0]]; b[ 1] = S5[u.temp[3][1]]; b[ 2] = S5[u.temp[2][2]]; @@ -650,11 +1998,12 @@ do_decrypt_aligned (RIJNDAEL_context *ctx, b[13] = S5[u.temp[2][1]]; b[14] = S5[u.temp[1][2]]; b[15] = S5[u.temp[0][3]]; - *((u32*)(b )) ^= *((u32*)rk[0][0]); - *((u32*)(b+ 4)) ^= *((u32*)rk[0][1]); - *((u32*)(b+ 8)) ^= *((u32*)rk[0][2]); - *((u32*)(b+12)) ^= *((u32*)rk[0][3]); + *((u32_a_t*)(b )) ^= *((u32_a_t*)rk[0][0]); + *((u32_a_t*)(b+ 4)) ^= *((u32_a_t*)rk[0][1]); + *((u32_a_t*)(b+ 8)) ^= *((u32_a_t*)rk[0][2]); + *((u32_a_t*)(b+12)) ^= *((u32_a_t*)rk[0][3]); #undef rk +#endif /*!USE_AMD64_ASM && !USE_ARM_ASM*/ } @@ -662,102 +2011,189 @@ do_decrypt_aligned (RIJNDAEL_context *ctx, static void do_decrypt (RIJNDAEL_context *ctx, byte *bx, const byte *ax) { - /* BX and AX are not necessary correctly aligned. Thus we need to - copy them here. */ - union - { - u32 dummy[4]; - byte a[16]; - } a; - union - { - u32 dummy[4]; - byte b[16]; - } b; +#if !defined(USE_AMD64_ASM) && !defined(USE_ARM_ASM) + /* BX and AX are not necessary correctly aligned. Thus we might + need to copy them here. We try to align to a 16 bytes. */ + if (((size_t)ax & 0x0f) || ((size_t)bx & 0x0f)) + { + union + { + u32 dummy[4]; + byte a[16] ATTR_ALIGNED_16; + } a; + union + { + u32 dummy[4]; + byte b[16] ATTR_ALIGNED_16; + } b; - if ( !ctx->decryption_prepared ) + buf_cpy (a.a, ax, 16); + do_decrypt_aligned (ctx, b.b, a.a); + buf_cpy (bx, b.b, 16); + } + else +#endif /*!USE_AMD64_ASM && !USE_ARM_ASM*/ + { + do_decrypt_aligned (ctx, bx, ax); + } +} + + +static inline void +check_decryption_preparation (RIJNDAEL_context *ctx) +{ + if (0) + ; +#ifdef USE_PADLOCK + else if (ctx->use_padlock) + { /* Padlock does not need decryption subkeys. */ } +#endif /*USE_PADLOCK*/ + else if ( !ctx->decryption_prepared ) { prepare_decryption ( ctx ); - _gcry_burn_stack (64); ctx->decryption_prepared = 1; } - - memcpy (a.a, ax, 16); - do_decrypt_aligned (ctx, b.b, a.a); - memcpy (bx, b.b, 16); -#undef rk } - - -static void +static unsigned int rijndael_decrypt (void *context, byte *b, const byte *a) { RIJNDAEL_context *ctx = context; + unsigned int burn_stack; + check_decryption_preparation (ctx); + + if (0) + ; #ifdef USE_PADLOCK - if (ctx->use_padlock) + else if (ctx->use_padlock) { do_padlock (ctx, 1, b, a); - _gcry_burn_stack (48 + 2*sizeof(int) /* FIXME */); + burn_stack = (48 + 2*sizeof(int) /* FIXME */); } - else #endif /*USE_PADLOCK*/ +#ifdef USE_AESNI + else if (ctx->use_aesni) + { + aesni_prepare (); + do_aesni_dec (ctx, b, a); + aesni_cleanup (); + burn_stack = 0; + } +#endif /*USE_AESNI*/ + else { do_decrypt (ctx, b, a); - _gcry_burn_stack (48+2*sizeof(int)); + burn_stack = (56+2*sizeof(int)); } + + return burn_stack; } /* Bulk decryption of complete blocks in CFB mode. Caller needs to - make sure that IV is aligned on an unisgned lonhg boundary. This + make sure that IV is aligned on an unsigned long boundary. This function is only intended for the bulk encryption feature of cipher.c. */ void -_gcry_aes_cfb_dec (void *context, unsigned char *iv, +_gcry_aes_cfb_dec (void *context, unsigned char *iv, void *outbuf_arg, const void *inbuf_arg, - unsigned int nblocks) + size_t nblocks) { RIJNDAEL_context *ctx = context; unsigned char *outbuf = outbuf_arg; const unsigned char *inbuf = inbuf_arg; - unsigned char *ivp; - unsigned char temp; - int i; + unsigned int burn_depth = 48 + 2*sizeof(int); + if (0) + ; #ifdef USE_PADLOCK - if (ctx->use_padlock) + else if (ctx->use_padlock) { /* Fixme: Let Padlock do the CFBing. */ for ( ;nblocks; nblocks-- ) { do_padlock (ctx, 0, iv, iv); - for (ivp=iv,i=0; i < BLOCKSIZE; i++ ) - { - temp = *inbuf++; - *outbuf++ = *ivp ^ temp; - *ivp++ = temp; - } + buf_xor_n_copy(outbuf, iv, inbuf, BLOCKSIZE); + outbuf += BLOCKSIZE; + inbuf += BLOCKSIZE; } } - else #endif /*USE_PADLOCK*/ +#ifdef USE_AESNI + else if (ctx->use_aesni) + { + aesni_prepare (); + + /* CFB decryption can be parallelized */ + for ( ;nblocks >= 4; nblocks -= 4) + { + asm volatile + ("movdqu (%[iv]), %%xmm1\n\t" /* load input blocks */ + "movdqu 0*16(%[inbuf]), %%xmm2\n\t" + "movdqu 1*16(%[inbuf]), %%xmm3\n\t" + "movdqu 2*16(%[inbuf]), %%xmm4\n\t" + + "movdqu 3*16(%[inbuf]), %%xmm0\n\t" /* update IV */ + "movdqu %%xmm0, (%[iv])\n\t" + : /* No output */ + : [inbuf] "r" (inbuf), [iv] "r" (iv) + : "memory"); + + do_aesni_enc_vec4 (ctx); + + asm volatile + ("movdqu 0*16(%[inbuf]), %%xmm5\n\t" + "pxor %%xmm5, %%xmm1\n\t" + "movdqu %%xmm1, 0*16(%[outbuf])\n\t" + + "movdqu 1*16(%[inbuf]), %%xmm5\n\t" + "pxor %%xmm5, %%xmm2\n\t" + "movdqu %%xmm2, 1*16(%[outbuf])\n\t" + + "movdqu 2*16(%[inbuf]), %%xmm5\n\t" + "pxor %%xmm5, %%xmm3\n\t" + "movdqu %%xmm3, 2*16(%[outbuf])\n\t" + + "movdqu 3*16(%[inbuf]), %%xmm5\n\t" + "pxor %%xmm5, %%xmm4\n\t" + "movdqu %%xmm4, 3*16(%[outbuf])\n\t" + + : /* No output */ + : [inbuf] "r" (inbuf), + [outbuf] "r" (outbuf) + : "memory"); + + outbuf += 4*BLOCKSIZE; + inbuf += 4*BLOCKSIZE; + } + + for ( ;nblocks; nblocks-- ) + { + do_aesni_cfb (ctx, 1, iv, outbuf, inbuf); + outbuf += BLOCKSIZE; + inbuf += BLOCKSIZE; + } + aesni_cleanup (); + aesni_cleanup_2_6 (); + + burn_depth = 0; /* No stack usage. */ + } +#endif /*USE_AESNI*/ + else { for ( ;nblocks; nblocks-- ) { do_encrypt_aligned (ctx, iv, iv); - for (ivp=iv,i=0; i < BLOCKSIZE; i++ ) - { - temp = *inbuf++; - *outbuf++ = *ivp ^ temp; - *ivp++ = temp; - } + buf_xor_n_copy(outbuf, iv, inbuf, BLOCKSIZE); + outbuf += BLOCKSIZE; + inbuf += BLOCKSIZE; } } - _gcry_burn_stack (48 + 2*sizeof(int)); + if (burn_depth) + _gcry_burn_stack (burn_depth); } @@ -766,38 +2202,133 @@ _gcry_aes_cfb_dec (void *context, unsigned char *iv, function is only intended for the bulk encryption feature of cipher.c. */ void -_gcry_aes_cbc_dec (void *context, unsigned char *iv, +_gcry_aes_cbc_dec (void *context, unsigned char *iv, void *outbuf_arg, const void *inbuf_arg, - unsigned int nblocks) + size_t nblocks) { RIJNDAEL_context *ctx = context; unsigned char *outbuf = outbuf_arg; const unsigned char *inbuf = inbuf_arg; - unsigned char *ivp; - int i; - unsigned char savebuf[BLOCKSIZE]; + unsigned int burn_depth = 48 + 2*sizeof(int) + 4*sizeof (char*); - for ( ;nblocks; nblocks-- ) + check_decryption_preparation (ctx); + + if (0) + ; +#ifdef USE_AESNI + else if (ctx->use_aesni) { - /* We need to save INBUF away because it may be identical to - OUTBUF. */ - memcpy (savebuf, inbuf, BLOCKSIZE); + aesni_prepare (); + + asm volatile + ("movdqu %[iv], %%xmm5\n\t" /* use xmm5 as fast IV storage */ + : /* No output */ + : [iv] "m" (*iv) + : "memory"); + for ( ;nblocks > 3 ; nblocks -= 4 ) + { + asm volatile + ("movdqu 0*16(%[inbuf]), %%xmm1\n\t" /* load input blocks */ + "movdqu 1*16(%[inbuf]), %%xmm2\n\t" + "movdqu 2*16(%[inbuf]), %%xmm3\n\t" + "movdqu 3*16(%[inbuf]), %%xmm4\n\t" + : /* No output */ + : [inbuf] "r" (inbuf) + : "memory"); + + do_aesni_dec_vec4 (ctx); + + asm volatile + ("pxor %%xmm5, %%xmm1\n\t" /* xor IV with output */ + "movdqu 0*16(%[inbuf]), %%xmm5\n\t" /* load new IV */ + "movdqu %%xmm1, 0*16(%[outbuf])\n\t" + + "pxor %%xmm5, %%xmm2\n\t" /* xor IV with output */ + "movdqu 1*16(%[inbuf]), %%xmm5\n\t" /* load new IV */ + "movdqu %%xmm2, 1*16(%[outbuf])\n\t" + + "pxor %%xmm5, %%xmm3\n\t" /* xor IV with output */ + "movdqu 2*16(%[inbuf]), %%xmm5\n\t" /* load new IV */ + "movdqu %%xmm3, 2*16(%[outbuf])\n\t" + + "pxor %%xmm5, %%xmm4\n\t" /* xor IV with output */ + "movdqu 3*16(%[inbuf]), %%xmm5\n\t" /* load new IV */ + "movdqu %%xmm4, 3*16(%[outbuf])\n\t" + + : /* No output */ + : [inbuf] "r" (inbuf), + [outbuf] "r" (outbuf) + : "memory"); + + outbuf += 4*BLOCKSIZE; + inbuf += 4*BLOCKSIZE; + } + + for ( ;nblocks; nblocks-- ) + { + asm volatile + ("movdqu %[inbuf], %%xmm2\n\t" /* use xmm2 as savebuf */ + : /* No output */ + : [inbuf] "m" (*inbuf) + : "memory"); + + /* uses only xmm0 and xmm1 */ + do_aesni_dec (ctx, outbuf, inbuf); + + asm volatile + ("movdqu %[outbuf], %%xmm0\n\t" + "pxor %%xmm5, %%xmm0\n\t" /* xor IV with output */ + "movdqu %%xmm0, %[outbuf]\n\t" + "movdqu %%xmm2, %%xmm5\n\t" /* store savebuf as new IV */ + : /* No output */ + : [outbuf] "m" (*outbuf) + : "memory"); + + outbuf += BLOCKSIZE; + inbuf += BLOCKSIZE; + } + + asm volatile + ("movdqu %%xmm5, %[iv]\n\t" /* store IV */ + : /* No output */ + : [iv] "m" (*iv) + : "memory"); + + aesni_cleanup (); + aesni_cleanup_2_6 (); + + burn_depth = 0; /* No stack usage. */ + } +#endif /*USE_AESNI*/ + else + { + unsigned char savebuf[BLOCKSIZE]; + + for ( ;nblocks; nblocks-- ) + { + /* INBUF is needed later and it may be identical to OUTBUF, so store + the intermediate result to SAVEBUF. */ + + if (0) + ; #ifdef USE_PADLOCK - if (ctx->use_padlock) - do_padlock (ctx, 1, outbuf, inbuf); - else + else if (ctx->use_padlock) + do_padlock (ctx, 1, savebuf, inbuf); #endif /*USE_PADLOCK*/ - do_decrypt (ctx, outbuf, inbuf); + else + do_decrypt (ctx, savebuf, inbuf); - for (ivp=iv, i=0; i < BLOCKSIZE; i++ ) - outbuf[i] ^= *ivp++; - memcpy (iv, savebuf, BLOCKSIZE); - inbuf += BLOCKSIZE; - outbuf += BLOCKSIZE; + buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, BLOCKSIZE); + inbuf += BLOCKSIZE; + outbuf += BLOCKSIZE; + } + + wipememory(savebuf, sizeof(savebuf)); } - _gcry_burn_stack (48 + 2*sizeof(int) + BLOCKSIZE + 4*sizeof (char*)); + if (burn_depth) + _gcry_burn_stack (burn_depth); } @@ -808,11 +2339,12 @@ static const char* selftest_basic_128 (void) { RIJNDAEL_context ctx; - unsigned char scratch[16]; + unsigned char scratch[16]; /* The test vectors are from the AES supplied ones; more or less randomly taken from ecb_tbl.txt (I=42,81,14) */ - static const unsigned char plaintext_128[16] = +#if 1 + static const unsigned char plaintext_128[16] = { 0x01,0x4B,0xAF,0x22,0x78,0xA6,0x9D,0x33, 0x1D,0x51,0x80,0x10,0x36,0x43,0xE9,0x9A @@ -827,7 +2359,28 @@ selftest_basic_128 (void) 0x67,0x43,0xC3,0xD1,0x51,0x9A,0xB4,0xF2, 0xCD,0x9A,0x78,0xAB,0x09,0xA5,0x11,0xBD }; - +#else + /* Test vectors from fips-197, appendix C. */ +# warning debug test vectors in use + static const unsigned char plaintext_128[16] = + { + 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77, + 0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff + }; + static const unsigned char key_128[16] = + { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f + /* 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, */ + /* 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c */ + }; + static const unsigned char ciphertext_128[16] = + { + 0x69,0xc4,0xe0,0xd8,0x6a,0x7b,0x04,0x30, + 0xd8,0xcd,0xb7,0x80,0x70,0xb4,0xc5,0x5a + }; +#endif + rijndael_setkey (&ctx, key_128, sizeof (key_128)); rijndael_encrypt (&ctx, scratch, plaintext_128); if (memcmp (scratch, ciphertext_128, sizeof (ciphertext_128))) @@ -835,7 +2388,7 @@ selftest_basic_128 (void) rijndael_decrypt (&ctx, scratch, scratch); if (memcmp (scratch, plaintext_128, sizeof (plaintext_128))) return "AES-128 test decryption failed."; - + return NULL; } @@ -844,14 +2397,14 @@ static const char* selftest_basic_192 (void) { RIJNDAEL_context ctx; - unsigned char scratch[16]; - - static unsigned char plaintext_192[16] = + unsigned char scratch[16]; + + static unsigned char plaintext_192[16] = { 0x76,0x77,0x74,0x75,0xF1,0xF2,0xF3,0xF4, 0xF8,0xF9,0xE6,0xE7,0x77,0x70,0x71,0x72 }; - static unsigned char key_192[24] = + static unsigned char key_192[24] = { 0x04,0x05,0x06,0x07,0x09,0x0A,0x0B,0x0C, 0x0E,0x0F,0x10,0x11,0x13,0x14,0x15,0x16, @@ -862,7 +2415,7 @@ selftest_basic_192 (void) 0x5D,0x1E,0xF2,0x0D,0xCE,0xD6,0xBC,0xBC, 0x12,0x13,0x1A,0xC7,0xC5,0x47,0x88,0xAA }; - + rijndael_setkey (&ctx, key_192, sizeof(key_192)); rijndael_encrypt (&ctx, scratch, plaintext_192); if (memcmp (scratch, ciphertext_192, sizeof (ciphertext_192))) @@ -870,7 +2423,7 @@ selftest_basic_192 (void) rijndael_decrypt (&ctx, scratch, scratch); if (memcmp (scratch, plaintext_192, sizeof (plaintext_192))) return "AES-192 test decryption failed."; - + return NULL; } @@ -880,21 +2433,21 @@ static const char* selftest_basic_256 (void) { RIJNDAEL_context ctx; - unsigned char scratch[16]; + unsigned char scratch[16]; - static unsigned char plaintext_256[16] = + static unsigned char plaintext_256[16] = { 0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21 }; - static unsigned char key_256[32] = + static unsigned char key_256[32] = { 0x08,0x09,0x0A,0x0B,0x0D,0x0E,0x0F,0x10, 0x12,0x13,0x14,0x15,0x17,0x18,0x19,0x1A, 0x1C,0x1D,0x1E,0x1F,0x21,0x22,0x23,0x24, 0x26,0x27,0x28,0x29,0x2B,0x2C,0x2D,0x2E }; - static const unsigned char ciphertext_256[16] = + static const unsigned char ciphertext_256[16] = { 0x08,0x0E,0x95,0x17,0xEB,0x16,0x77,0x71, 0x9A,0xCF,0x72,0x80,0x86,0x04,0x0A,0xE3 @@ -907,10 +2460,56 @@ selftest_basic_256 (void) rijndael_decrypt (&ctx, scratch, scratch); if (memcmp (scratch, plaintext_256, sizeof (plaintext_256))) return "AES-256 test decryption failed."; - + return NULL; } + +/* Run the self-tests for AES-CTR-128, tests IV increment of bulk CTR + encryption. Returns NULL on success. */ +static const char* +selftest_ctr_128 (void) +{ + const int nblocks = 8+1; + const int blocksize = BLOCKSIZE; + const int context_size = sizeof(RIJNDAEL_context); + + return _gcry_selftest_helper_ctr("AES", &rijndael_setkey, + &rijndael_encrypt, &_gcry_aes_ctr_enc, nblocks, blocksize, + context_size); +} + + +/* Run the self-tests for AES-CBC-128, tests bulk CBC decryption. + Returns NULL on success. */ +static const char* +selftest_cbc_128 (void) +{ + const int nblocks = 8+2; + const int blocksize = BLOCKSIZE; + const int context_size = sizeof(RIJNDAEL_context); + + return _gcry_selftest_helper_cbc("AES", &rijndael_setkey, + &rijndael_encrypt, &_gcry_aes_cbc_dec, nblocks, blocksize, + context_size); +} + + +/* Run the self-tests for AES-CFB-128, tests bulk CFB decryption. + Returns NULL on success. */ +static const char* +selftest_cfb_128 (void) +{ + const int nblocks = 8+2; + const int blocksize = BLOCKSIZE; + const int context_size = sizeof(RIJNDAEL_context); + + return _gcry_selftest_helper_cfb("AES", &rijndael_setkey, + &rijndael_encrypt, &_gcry_aes_cfb_dec, nblocks, blocksize, + context_size); +} + + /* Run all the self-tests and return NULL on success. This function is used for the on-the-fly self-tests. */ static const char * @@ -923,6 +2522,15 @@ selftest (void) || (r = selftest_basic_256 ()) ) return r; + if ( (r = selftest_ctr_128 ()) ) + return r; + + if ( (r = selftest_cbc_128 ()) ) + return r; + + if ( (r = selftest_cfb_128 ()) ) + return r; + return r; } @@ -931,12 +2539,12 @@ selftest (void) static const char * selftest_fips_128_38a (int requested_mode) { - struct tv + static const struct tv { int mode; const unsigned char key[16]; const unsigned char iv[16]; - struct + struct { const unsigned char input[16]; const unsigned char output[16]; @@ -947,24 +2555,24 @@ selftest_fips_128_38a (int requested_mode) GCRY_CIPHER_MODE_CFB, /* F.3.13, CFB128-AES128 */ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, - { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, { { { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a }, { 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a } }, - + { { 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51 }, { 0xc8, 0xa6, 0x45, 0x37, 0xa0, 0xb3, 0xa9, 0x3f, 0xcd, 0xe3, 0xcd, 0xad, 0x9f, 0x1c, 0xe5, 0x8b } }, - - { { 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + + { { 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef }, { 0x26, 0x75, 0x1f, 0x67, 0xa3, 0xcb, 0xb1, 0x40, 0xb1, 0x80, 0x8c, 0xf1, 0x87, 0xa4, 0xf4, 0xdf } }, - + { { 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 }, { 0xc0, 0x4b, 0x05, 0x35, 0x7c, 0x5d, 0x1c, 0x0e, @@ -975,7 +2583,7 @@ selftest_fips_128_38a (int requested_mode) GCRY_CIPHER_MODE_OFB, { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }, - { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, { { { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, @@ -987,7 +2595,7 @@ selftest_fips_128_38a (int requested_mode) 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51 }, { 0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03, 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25 } }, - + { { 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef }, { 0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6, @@ -1057,7 +2665,7 @@ selftest_fips_128_38a (int requested_mode) #undef Fail _gcry_cipher_close (hdenc); - _gcry_cipher_close (hddec); + _gcry_cipher_close (hddec); return NULL; } @@ -1068,7 +2676,7 @@ selftest_fips_128 (int extended, selftest_report_func_t report) { const char *what; const char *errtxt; - + what = "low-level"; errtxt = selftest_basic_128 (); if (errtxt) @@ -1080,7 +2688,7 @@ selftest_fips_128 (int extended, selftest_report_func_t report) errtxt = selftest_fips_128_38a (GCRY_CIPHER_MODE_CFB); if (errtxt) goto failed; - + what = "ofb"; errtxt = selftest_fips_128_38a (GCRY_CIPHER_MODE_OFB); if (errtxt) @@ -1125,7 +2733,7 @@ selftest_fips_256 (int extended, selftest_report_func_t report) { const char *what; const char *errtxt; - + (void)extended; /* No extended tests available. */ what = "low-level"; @@ -1163,7 +2771,7 @@ run_selftests (int algo, int extended, selftest_report_func_t report) default: ec = GPG_ERR_CIPHER_ALGO; break; - + } return ec; } @@ -1190,14 +2798,15 @@ static gcry_cipher_oid_spec_t rijndael_oids[] = gcry_cipher_spec_t _gcry_cipher_spec_aes = { - "AES", rijndael_names, rijndael_oids, 16, 128, sizeof (RIJNDAEL_context), - rijndael_setkey, rijndael_encrypt, rijndael_decrypt - }; -cipher_extra_spec_t _gcry_cipher_extraspec_aes = - { + GCRY_CIPHER_AES, {0, 1}, + "AES", rijndael_names, rijndael_oids, 16, 128, + sizeof (RIJNDAEL_context), + rijndael_setkey, rijndael_encrypt, rijndael_decrypt, + NULL, NULL, run_selftests }; + static const char *rijndael192_names[] = { "RIJNDAEL192", @@ -1216,14 +2825,15 @@ static gcry_cipher_oid_spec_t rijndael192_oids[] = gcry_cipher_spec_t _gcry_cipher_spec_aes192 = { - "AES192", rijndael192_names, rijndael192_oids, 16, 192, sizeof (RIJNDAEL_context), - rijndael_setkey, rijndael_encrypt, rijndael_decrypt - }; -cipher_extra_spec_t _gcry_cipher_extraspec_aes192 = - { + GCRY_CIPHER_AES192, {0, 1}, + "AES192", rijndael192_names, rijndael192_oids, 16, 192, + sizeof (RIJNDAEL_context), + rijndael_setkey, rijndael_encrypt, rijndael_decrypt, + NULL, NULL, run_selftests }; + static const char *rijndael256_names[] = { "RIJNDAEL256", @@ -1242,12 +2852,10 @@ static gcry_cipher_oid_spec_t rijndael256_oids[] = gcry_cipher_spec_t _gcry_cipher_spec_aes256 = { + GCRY_CIPHER_AES256, {0, 1}, "AES256", rijndael256_names, rijndael256_oids, 16, 256, sizeof (RIJNDAEL_context), - rijndael_setkey, rijndael_encrypt, rijndael_decrypt - }; - -cipher_extra_spec_t _gcry_cipher_extraspec_aes256 = - { + rijndael_setkey, rijndael_encrypt, rijndael_decrypt, + NULL, NULL, run_selftests }; diff --git a/plugins/MirOTR/Libgcrypt/cipher/rmd.h b/plugins/MirOTR/Libgcrypt/cipher/rmd.h index f4ce9c671f..a56ee49c2c 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/rmd.h +++ b/plugins/MirOTR/Libgcrypt/cipher/rmd.h @@ -20,18 +20,16 @@ #ifndef G10_RMD_H #define G10_RMD_H +#include "hash-common.h" /* We need this here because random.c must have direct access. */ -typedef struct +typedef struct { + gcry_md_block_ctx_t bctx; u32 h0,h1,h2,h3,h4; - u32 nblocks; - byte buf[64]; - int count; } RMD160_CONTEXT; void _gcry_rmd160_init ( void *context ); void _gcry_rmd160_mixblock ( RMD160_CONTEXT *hd, void *blockof64byte ); #endif /*G10_RMD_H*/ - diff --git a/plugins/MirOTR/Libgcrypt/cipher/rmd160.c b/plugins/MirOTR/Libgcrypt/cipher/rmd160.c index 7805bf53b0..08e8cb08a4 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/rmd160.c +++ b/plugins/MirOTR/Libgcrypt/cipher/rmd160.c @@ -24,11 +24,11 @@ #include <string.h> #include "g10lib.h" -#include "memory.h" #include "rmd.h" #include "cipher.h" /* Only used for the rmd160_hash_buffer() prototype. */ #include "bithelp.h" +#include "bufhelp.h" /********************************* * RIPEMD-160 is not patented, see (as of 25.10.97) @@ -140,56 +140,51 @@ * 1 million times "a" 52783243c1697bdbe16d37f97f68f08325dc1528 */ +static unsigned int +transform ( void *ctx, const unsigned char *data ); -void -_gcry_rmd160_init (void *context) +static void +rmd160_init (void *context, unsigned int flags) { RMD160_CONTEXT *hd = context; + (void)flags; + hd->h0 = 0x67452301; hd->h1 = 0xEFCDAB89; hd->h2 = 0x98BADCFE; hd->h3 = 0x10325476; hd->h4 = 0xC3D2E1F0; - hd->nblocks = 0; - hd->count = 0; + + hd->bctx.nblocks = 0; + hd->bctx.nblocks_high = 0; + hd->bctx.count = 0; + hd->bctx.blocksize = 64; + hd->bctx.bwrite = transform; } +void +_gcry_rmd160_init (void *context) +{ + rmd160_init (context, 0); +} + /**************** * Transform the message X which consists of 16 32-bit-words */ -static void -transform ( RMD160_CONTEXT *hd, const unsigned char *data ) +static unsigned int +transform ( void *ctx, const unsigned char *data ) { + RMD160_CONTEXT *hd = ctx; register u32 a,b,c,d,e; u32 aa,bb,cc,dd,ee,t; -#ifdef WORDS_BIGENDIAN - u32 x[16]; - { - int i; - byte *p2, *p1; - for (i=0, p1=data, p2=(byte*)x; i < 16; i++, p2 += 4 ) - { - p2[3] = *p1++; - p2[2] = *p1++; - p2[1] = *p1++; - p2[0] = *p1++; - } - } -#else - /* This version is better because it is always aligned; - * The performance penalty on a 586-100 is about 6% which - * is acceptable - because the data is more local it might - * also be possible that this is faster on some machines. - * This function (when compiled with -02 on gcc 2.7.2) - * executes on a 586-100 (39.73 bogomips) at about 1900kb/sec; - * [measured with a 4MB data and "gpgm --print-md rmd160"] */ u32 x[16]; - memcpy( x, data, 64 ); -#endif + int i; + for ( i = 0; i < 16; i++ ) + x[i] = buf_get_le32(data + i * 4); #define K0 0x00000000 #define K1 0x5A827999 @@ -394,49 +389,11 @@ transform ( RMD160_CONTEXT *hd, const unsigned char *data ) hd->h3 = hd->h4 + b + aa; hd->h4 = hd->h0 + c + bb; hd->h0 = t; -} - - -/* Update the message digest with the contents - * of INBUF with length INLEN. - */ -static void -rmd160_write ( void *context, const void *inbuf_arg, size_t inlen) -{ - const unsigned char *inbuf = inbuf_arg; - RMD160_CONTEXT *hd = context; - - if( hd->count == 64 ) /* flush the buffer */ - { - transform( hd, hd->buf ); - _gcry_burn_stack (108+5*sizeof(void*)); - hd->count = 0; - hd->nblocks++; - } - if( !inbuf ) - return; - if( hd->count ) - { - for( ; inlen && hd->count < 64; inlen-- ) - hd->buf[hd->count++] = *inbuf++; - rmd160_write( hd, NULL, 0 ); - if( !inlen ) - return; - } - while( inlen >= 64 ) - { - transform( hd, inbuf ); - hd->count = 0; - hd->nblocks++; - inlen -= 64; - inbuf += 64; - } - _gcry_burn_stack (108+5*sizeof(void*)); - for( ; inlen && hd->count < 64; inlen-- ) - hd->buf[hd->count++] = *inbuf++; + return /*burn_stack*/ 108+5*sizeof(void*); } + /**************** * Apply the rmd160 transform function on the buffer which must have * a length 64 bytes. Do not use this function together with the @@ -466,18 +423,24 @@ static void rmd160_final( void *context ) { RMD160_CONTEXT *hd = context; - u32 t, msb, lsb; + u32 t, th, msb, lsb; byte *p; - - rmd160_write(hd, NULL, 0); /* flush */; + unsigned int burn; + + _gcry_md_block_write(hd, NULL, 0); /* flush */; + + t = hd->bctx.nblocks; + if (sizeof t == sizeof hd->bctx.nblocks) + th = hd->bctx.nblocks_high; + else + th = hd->bctx.nblocks >> 32; - t = hd->nblocks; /* multiply by 64 to make a byte count */ lsb = t << 6; - msb = t >> 26; + msb = (th << 6) | (t >> 26); /* add the count */ t = lsb; - if( (lsb += hd->count) < t ) + if( (lsb += hd->bctx.count) < t ) msb++; /* multiply by 8 to make a bit count */ t = lsb; @@ -485,39 +448,28 @@ rmd160_final( void *context ) msb <<= 3; msb |= t >> 29; - if( hd->count < 56 ) /* enough room */ + if( hd->bctx.count < 56 ) /* enough room */ { - hd->buf[hd->count++] = 0x80; /* pad */ - while( hd->count < 56 ) - hd->buf[hd->count++] = 0; /* pad */ + hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad */ + while( hd->bctx.count < 56 ) + hd->bctx.buf[hd->bctx.count++] = 0; /* pad */ } else /* need one extra block */ { - hd->buf[hd->count++] = 0x80; /* pad character */ - while( hd->count < 64 ) - hd->buf[hd->count++] = 0; - rmd160_write(hd, NULL, 0); /* flush */; - memset(hd->buf, 0, 56 ); /* fill next block with zeroes */ + hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad character */ + while( hd->bctx.count < 64 ) + hd->bctx.buf[hd->bctx.count++] = 0; + _gcry_md_block_write(hd, NULL, 0); /* flush */; + memset(hd->bctx.buf, 0, 56 ); /* fill next block with zeroes */ } /* append the 64 bit count */ - hd->buf[56] = lsb ; - hd->buf[57] = lsb >> 8; - hd->buf[58] = lsb >> 16; - hd->buf[59] = lsb >> 24; - hd->buf[60] = msb ; - hd->buf[61] = msb >> 8; - hd->buf[62] = msb >> 16; - hd->buf[63] = msb >> 24; - transform( hd, hd->buf ); - _gcry_burn_stack (108+5*sizeof(void*)); - - p = hd->buf; -#ifdef WORDS_BIGENDIAN -#define X(a) do { *p++ = hd->h##a ; *p++ = hd->h##a >> 8; \ - *p++ = hd->h##a >> 16; *p++ = hd->h##a >> 24; } while(0) -#else /* little endian */ -#define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0) -#endif + buf_put_le32(hd->bctx.buf + 56, lsb); + buf_put_le32(hd->bctx.buf + 60, msb); + burn = transform( hd, hd->bctx.buf ); + _gcry_burn_stack (burn); + + p = hd->bctx.buf; +#define X(a) do { *(u32*)p = le_bswap32(hd->h##a) ; p += 4; } while(0) X(0); X(1); X(2); @@ -531,7 +483,7 @@ rmd160_read( void *context ) { RMD160_CONTEXT *hd = context; - return hd->buf; + return hd->bctx.buf; } @@ -546,9 +498,9 @@ _gcry_rmd160_hash_buffer (void *outbuf, const void *buffer, size_t length ) RMD160_CONTEXT hd; _gcry_rmd160_init ( &hd ); - rmd160_write ( &hd, buffer, length ); + _gcry_md_block_write ( &hd, buffer, length ); rmd160_final ( &hd ); - memcpy ( outbuf, hd.buf, 20 ); + memcpy ( outbuf, hd.bctx.buf, 20 ); } static byte asn[15] = /* Object ID is 1.3.36.3.2.1 */ @@ -566,7 +518,8 @@ static gcry_md_oid_spec_t oid_spec_rmd160[] = gcry_md_spec_t _gcry_digest_spec_rmd160 = { + GCRY_MD_RMD160, {0, 0}, "RIPEMD160", asn, DIM (asn), oid_spec_rmd160, 20, - _gcry_rmd160_init, rmd160_write, rmd160_final, rmd160_read, + rmd160_init, _gcry_md_block_write, rmd160_final, rmd160_read, sizeof (RMD160_CONTEXT) }; diff --git a/plugins/MirOTR/Libgcrypt/cipher/rndw32.c b/plugins/MirOTR/Libgcrypt/cipher/rndw32.c deleted file mode 100644 index b31b6382f4..0000000000 --- a/plugins/MirOTR/Libgcrypt/cipher/rndw32.c +++ /dev/null @@ -1,982 +0,0 @@ -/* rndw32.c - W32 entropy gatherer - * Copyright (C) 1999, 2000, 2002, 2003, 2007 Free Software Foundation, Inc. - * Copyright Peter Gutmann, Matt Thomlinson and Blake Coverett 1996-2006 - * - * This file is part of Libgcrypt. - * - ************************************************************************* - * The code here is based on code from Cryptlib 3.0 beta by Peter Gutmann. - * Source file misc/rndwin32.c "Win32 Randomness-Gathering Code" with this - * copyright notice: - * - * This module is part of the cryptlib continuously seeded pseudorandom - * number generator. For usage conditions, see lib_rand.c - * - * [Here is the notice from lib_rand.c, which is now called dev_sys.c] - * - * This module and the misc/rnd*.c modules represent the cryptlib - * continuously seeded pseudorandom number generator (CSPRNG) as described in - * my 1998 Usenix Security Symposium paper "The generation of random numbers - * for cryptographic purposes". - * - * The CSPRNG code is copyright Peter Gutmann (and various others) 1996, - * 1997, 1998, 1999, all rights reserved. Redistribution of the CSPRNG - * modules 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 - * and this permission notice in its entirety. - * - * 2. Redistributions in binary form must reproduce the copyright notice in - * the documentation and/or other materials provided with the distribution. - * - * 3. A copy of any bugfixes or enhancements made must be provided to the - * author, <pgut001@cs.auckland.ac.nz> to allow them to be added to the - * baseline version of the code. - * - * ALTERNATIVELY, the code may be distributed under the terms of the - * GNU Lesser General Public License, version 2.1 or any later version - * published by the Free Software Foundation, in which case the - * provisions of the GNU LGPL are required INSTEAD OF the above - * restrictions. - * - * Although not required under the terms of the LGPL, it would still - * be nice if you could make any changes available to the author to - * allow a consistent code base to be maintained. - ************************************************************************* - * The above alternative was changed from GPL to LGPL on 2007-08-22 with - * permission from Peter Gutmann: - *========== - From: pgut001 <pgut001@cs.auckland.ac.nz> - Subject: Re: LGPL for the windows entropy gatherer - To: wk@gnupg.org - Date: Wed, 22 Aug 2007 03:05:42 +1200 - - Hi, - - >As of now libgcrypt is GPL under Windows due to that module and some people - >would really like to see it under LGPL too. Can you do such a license change - >to LGPL version 2? Note that LGPL give the user the option to relicense it - >under GPL, so the change would be pretty easy and backwar compatible. - - Sure. I assumed that since GPG was GPLd, you'd prefer the GPL for the entropy - code as well, but Ian asked for LGPL as an option so as of the next release - I'll have LGPL in there. You can consider it to be retroactive, so your - current version will be LGPLd as well. - - Peter. - *========== - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <string.h> -#ifdef __GNUC__ -#include <stdint.h> -#endif - -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <winperf.h> - - -#include "types.h" -#include "g10lib.h" -#include "rand-internal.h" - - -/* Definitions which are missing from the current GNU Windows32Api. */ -#ifndef IOCTL_DISK_PERFORMANCE -#define IOCTL_DISK_PERFORMANCE 0x00070020 -#endif - -/* This used to be (6*8+5*4+8*2), but Peter Gutmann figured a larger - value in a newer release. So we use a far larger value. */ -#define SIZEOF_DISK_PERFORMANCE_STRUCT 256 - -/* We don't include wincrypt.h so define it here. */ -#define HCRYPTPROV HANDLE - - -/* When we query the performance counters, we allocate an initial buffer and - * then reallocate it as required until RegQueryValueEx() stops returning - * ERROR_MORE_DATA. The following values define the initial buffer size and - * step size by which the buffer is increased - */ -#define PERFORMANCE_BUFFER_SIZE 65536 /* Start at 64K */ -#define PERFORMANCE_BUFFER_STEP 16384 /* Step by 16K */ - - -/* The number of bytes to read from the system RNG on each slow poll. */ -#define SYSTEMRNG_BYTES 64 - -/* Intel Chipset CSP type and name */ -#define PROV_INTEL_SEC 22 -#define INTEL_DEF_PROV "Intel Hardware Cryptographic Service Provider" - - - - -/* Type definitions for function pointers to call NetAPI32 functions. */ -typedef DWORD (WINAPI *NETSTATISTICSGET)(LPWSTR szServer, LPWSTR szService, - DWORD dwLevel, DWORD dwOptions, - LPBYTE *lpBuffer); -typedef DWORD (WINAPI *NETAPIBUFFERSIZE)(LPVOID lpBuffer, LPDWORD cbBuffer); -typedef DWORD (WINAPI *NETAPIBUFFERFREE)(LPVOID lpBuffer); - -/* Type definitions for function pointers to call native NT functions. */ -typedef DWORD (WINAPI *NTQUERYSYSTEMINFORMATION)(DWORD systemInformationClass, - PVOID systemInformation, - ULONG systemInformationLength, - PULONG returnLength); -typedef DWORD (WINAPI *NTQUERYINFORMATIONPROCESS) - (HANDLE processHandle, DWORD processInformationClass, - PVOID processInformation, ULONG processInformationLength, - PULONG returnLength); -typedef DWORD (WINAPI *NTPOWERINFORMATION) - (DWORD powerInformationClass, PVOID inputBuffer, - ULONG inputBufferLength, PVOID outputBuffer, ULONG outputBufferLength ); - -/* Type definitions for function pointers to call CryptoAPI functions. */ -typedef BOOL (WINAPI *CRYPTACQUIRECONTEXT)(HCRYPTPROV *phProv, - LPCTSTR pszContainer, - LPCTSTR pszProvider, - DWORD dwProvType, - DWORD dwFlags); -typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen, - BYTE *pbBuffer); -typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV hProv, DWORD dwFlags); - -/* Somewhat alternative functionality available as a direct call, for - Windows XP and newer. This is the CryptoAPI RNG, which isn't anywhere - near as good as the HW RNG, but we use it if it's present on the basis - that at least it can't make things any worse. This direct access version - is only available under Windows XP, we don't go out of our way to access - the more general CryptoAPI one since the main purpose of using it is to - take advantage of any possible future hardware RNGs that may be added, - for example via TCPA devices. */ -typedef BOOL (WINAPI *RTLGENRANDOM)(PVOID RandomBuffer, - ULONG RandomBufferLength); - - - -/* MBM data structures, originally by Alexander van Kaam, converted to C by - Anders@Majland.org, finally updated by Chris Zahrt <techn0@iastate.edu> */ -#define BusType char -#define SMBType char -#define SensorType char - -typedef struct -{ - SensorType iType; /* Type of sensor. */ - int Count; /* Number of sensor for that type. */ -} SharedIndex; - -typedef struct -{ - SensorType ssType; /* Type of sensor */ - unsigned char ssName[12]; /* Name of sensor */ - char sspadding1[3]; /* Padding of 3 bytes */ - double ssCurrent; /* Current value */ - double ssLow; /* Lowest readout */ - double ssHigh; /* Highest readout */ - long ssCount; /* Total number of readout */ - char sspadding2[4]; /* Padding of 4 bytes */ - long double ssTotal; /* Total amout of all readouts */ - char sspadding3[6]; /* Padding of 6 bytes */ - double ssAlarm1; /* Temp & fan: high alarm; voltage: % off */ - double ssAlarm2; /* Temp: low alarm */ -} SharedSensor; - -typedef struct -{ - short siSMB_Base; /* SMBus base address */ - BusType siSMB_Type; /* SMBus/Isa bus used to access chip */ - SMBType siSMB_Code; /* SMBus sub type, Intel, AMD or ALi */ - char siSMB_Addr; /* Address of sensor chip on SMBus */ - unsigned char siSMB_Name[41]; /* Nice name for SMBus */ - short siISA_Base; /* ISA base address of sensor chip on ISA */ - int siChipType; /* Chip nr, connects with Chipinfo.ini */ - char siVoltageSubType; /* Subvoltage option selected */ -} SharedInfo; - -typedef struct -{ - double sdVersion; /* Version number (example: 51090) */ - SharedIndex sdIndex[10]; /* Sensor index */ - SharedSensor sdSensor[100]; /* Sensor info */ - SharedInfo sdInfo; /* Misc.info */ - unsigned char sdStart[41]; /* Start time */ - - /* We don't use the next two fields both because they're not random - and because it provides a nice safety margin in case of data size - mis- estimates (we always under-estimate the buffer size). */ -#if 0 - unsigned char sdCurrent[41]; /* Current time */ - unsigned char sdPath[256]; /* MBM path */ -#endif /*0*/ -} SharedData; - - - -/* One time intialized handles and function pointers. We use dynamic - loading of the DLLs to do without them in case libgcrypt does not - need any random. */ -static HANDLE hNetAPI32; -static NETSTATISTICSGET pNetStatisticsGet; -static NETAPIBUFFERSIZE pNetApiBufferSize; -static NETAPIBUFFERFREE pNetApiBufferFree; - -static HANDLE hNTAPI; -static NTQUERYSYSTEMINFORMATION pNtQuerySystemInformation; -static NTQUERYINFORMATIONPROCESS pNtQueryInformationProcess; -static NTPOWERINFORMATION pNtPowerInformation; - -static HANDLE hAdvAPI32; -static CRYPTACQUIRECONTEXT pCryptAcquireContext; -static CRYPTGENRANDOM pCryptGenRandom; -static CRYPTRELEASECONTEXT pCryptReleaseContext; -static RTLGENRANDOM pRtlGenRandom; - - -/* Other module global variables. */ -static int system_rng_available; /* Whether a system RNG is available. */ -static HCRYPTPROV hRNGProv; /* Handle to Intel RNG CSP. */ - -static int debug_me; /* Debug flag. */ - -static int system_is_w2000; /* True if running on W2000. */ - - - - -/* Try and connect to the system RNG if there's one present. */ -static void -init_system_rng (void) -{ - system_rng_available = 0; - hRNGProv = NULL; - - hAdvAPI32 = GetModuleHandle ("AdvAPI32.dll"); - if (!hAdvAPI32) - return; - - pCryptAcquireContext = (CRYPTACQUIRECONTEXT) - GetProcAddress (hAdvAPI32, "CryptAcquireContextA"); - pCryptGenRandom = (CRYPTGENRANDOM) - GetProcAddress (hAdvAPI32, "CryptGenRandom"); - pCryptReleaseContext = (CRYPTRELEASECONTEXT) - GetProcAddress (hAdvAPI32, "CryptReleaseContext"); - - /* Get a pointer to the native randomness function if it's available. - This isn't exported by name, so we have to get it by ordinal. */ - pRtlGenRandom = (RTLGENRANDOM) - GetProcAddress (hAdvAPI32, "SystemFunction036"); - - /* Try and connect to the PIII RNG CSP. The AMD 768 southbridge (from - the 760 MP chipset) also has a hardware RNG, but there doesn't appear - to be any driver support for this as there is for the Intel RNG so we - can't do much with it. OTOH the Intel RNG is also effectively dead - as well, mostly due to virtually nonexistant support/marketing by - Intel, it's included here mostly for form's sake. */ - if ( (!pCryptAcquireContext || !pCryptGenRandom || !pCryptReleaseContext - || !pCryptAcquireContext (&hRNGProv, NULL, INTEL_DEF_PROV, - PROV_INTEL_SEC, 0) ) - && !pRtlGenRandom) - { - hAdvAPI32 = NULL; - } - else - system_rng_available = 1; -} - - -/* Read data from the system RNG if availavle. */ -static void -read_system_rng (void (*add)(const void*, size_t, enum random_origins), - enum random_origins requester) -{ - BYTE buffer[ SYSTEMRNG_BYTES + 8 ]; - int quality = 0; - - if (!system_rng_available) - return; - - /* Read SYSTEMRNG_BYTES bytes from the system RNG. We don't rely on - this for all our randomness requirements (particularly the - software RNG) in case it's broken in some way. */ - if (hRNGProv) - { - if (pCryptGenRandom (hRNGProv, SYSTEMRNG_BYTES, buffer)) - quality = 80; - } - else if (pRtlGenRandom) - { - if ( pRtlGenRandom (buffer, SYSTEMRNG_BYTES)) - quality = 50; - } - if (quality > 0) - { - if (debug_me) - log_debug ("rndw32#read_system_rng: got %d bytes of quality %d\n", - SYSTEMRNG_BYTES, quality); - (*add) (buffer, SYSTEMRNG_BYTES, requester); - wipememory (buffer, SYSTEMRNG_BYTES); - } -} - - -/* Read data from MBM. This communicates via shared memory, so all we - need to do is map a file and read the data out. */ -static void -read_mbm_data (void (*add)(const void*, size_t, enum random_origins), - enum random_origins requester) -{ - HANDLE hMBMData; - SharedData *mbmDataPtr; - - hMBMData = OpenFileMapping (FILE_MAP_READ, FALSE, "$M$B$M$5$S$D$" ); - if (hMBMData) - { - mbmDataPtr = (SharedData*)MapViewOfFile (hMBMData, FILE_MAP_READ,0,0,0); - if (mbmDataPtr) - { - if (debug_me) - log_debug ("rndw32#read_mbm_data: got %d bytes\n", - (int)sizeof (SharedData)); - (*add) (mbmDataPtr, sizeof (SharedData), requester); - UnmapViewOfFile (mbmDataPtr); - } - CloseHandle (hMBMData); - } -} - - -/* Fallback method using the registry to poll the statistics. */ -static void -registry_poll (void (*add)(const void*, size_t, enum random_origins), - enum random_origins requester) -{ - static int cbPerfData = PERFORMANCE_BUFFER_SIZE; - int iterations; - DWORD dwSize, status; - PERF_DATA_BLOCK *pPerfData; - - /* Get information from the system performance counters. This can take a - few seconds to do. In some environments the call to RegQueryValueEx() - can produce an access violation at some random time in the future, in - some cases adding a short delay after the following code block makes - the problem go away. This problem is extremely difficult to - reproduce, I haven't been able to get it to occur despite running it - on a number of machines. MS knowledge base article Q178887 covers - this type of problem, it's typically caused by an external driver or - other program that adds its own values under the - HKEY_PERFORMANCE_DATA key. The NT kernel, via Advapi32.dll, calls the - required external module to map in the data inside an SEH try/except - block, so problems in the module's collect function don't pop up until - after it has finished, so the fault appears to occur in Advapi32.dll. - There may be problems in the NT kernel as well though, a low-level - memory checker indicated that ExpandEnvironmentStrings() in - Kernel32.dll, called an interminable number of calls down inside - RegQueryValueEx(), was overwriting memory (it wrote twice the - allocated size of a buffer to a buffer allocated by the NT kernel). - OTOH this could be coming from the external module calling back into - the kernel, which eventually causes the problem described above. - - Possibly as an extension of the problem that the krnlWaitSemaphore() - call above works around, running two instances of cryptlib (e.g. two - applications that use it) under NT4 can result in one of them hanging - in the RegQueryValueEx() call. This happens only under NT4 and is - hard to reproduce in any consistent manner. - - One workaround that helps a bit is to read the registry as a remote - (rather than local) registry, it's possible that the use of a network - RPC call isolates the calling app from the problem in that whatever - service handles the RPC is taking the hit and not affecting the - calling app. Since this would require another round of extensive - testing to verify and the NT native API call is working fine, we'll - stick with the native API call for now. - - Some versions of NT4 had a problem where the amount of data returned - was mis-reported and would never settle down, because of this the code - below includes a safety-catch that bails out after 10 attempts have - been made, this results in no data being returned but at does ensure - that the thread will terminate. - - In addition to these problems the code in RegQueryValueEx() that - estimates the amount of memory required to return the performance - counter information isn't very accurate (it's much worse than the - "slightly-inaccurate" level that the MS docs warn about, it's usually - wildly off) since it always returns a worst-case estimate which is - usually nowhere near the actual amount required. For example it may - report that 128K of memory is required, but only return 64K of data. - - Even worse than the registry-based performance counters is the - performance data helper (PDH) shim that tries to make the counters - look like the old Win16 API (which is also used by Win95). Under NT - this can consume tens of MB of memory and huge amounts of CPU time - while it gathers its data, and even running once can still consume - about 1/2MB of memory */ - pPerfData = gcry_xmalloc (cbPerfData); - for (iterations=0; iterations < 10; iterations++) - { - dwSize = cbPerfData; - if ( debug_me ) - log_debug ("rndw32#slow_gatherer_nt: get perf data\n" ); - - status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL, - NULL, (LPBYTE) pPerfData, &dwSize); - if (status == ERROR_SUCCESS) - { - if (!memcmp (pPerfData->Signature, L"PERF", 8)) - (*add) ( pPerfData, dwSize, requester ); - else - log_debug ("rndw32: no PERF signature\n"); - break; - } - else if (status == ERROR_MORE_DATA) - { - cbPerfData += PERFORMANCE_BUFFER_STEP; - pPerfData = gcry_xrealloc (pPerfData, cbPerfData); - } - else - { - static int been_here; - - /* Silence the error message. In particular under Wine (as - of 2008) we would get swamped with such diagnotiscs. One - such diagnotiscs should be enough. */ - if (been_here != status) - { - been_here = status; - log_debug ("rndw32: get performance data problem: ec=%ld\n", - status); - } - break; - } - } - gcry_free (pPerfData); - - /* Although this isn't documented in the Win32 API docs, it's necessary - to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's - implicitly opened on the first call to RegQueryValueEx()). If this - isn't done then any system components which provide performance data - can't be removed or changed while the handle remains active. */ - RegCloseKey (HKEY_PERFORMANCE_DATA); -} - - -static void -slow_gatherer ( void (*add)(const void*, size_t, enum random_origins), - enum random_origins requester ) -{ - static int is_initialized = 0; - static int is_workstation = 1; - HANDLE hDevice; - DWORD dwType, dwSize, dwResult; - ULONG ulSize; - int drive_no, status; - int no_results = 0; - void *buffer; - - if ( !is_initialized ) - { - HKEY hKey; - - if ( debug_me ) - log_debug ("rndw32#slow_gatherer: init toolkit\n" ); - /* Find out whether this is an NT server or workstation if necessary */ - if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, - "SYSTEM\\CurrentControlSet\\Control\\ProductOptions", - 0, KEY_READ, &hKey) == ERROR_SUCCESS) - { - BYTE szValue[32 + 8]; - dwSize = 32; - - if ( debug_me ) - log_debug ("rndw32#slow_gatherer: check product options\n" ); - - status = RegQueryValueEx (hKey, "ProductType", 0, NULL, - szValue, &dwSize); - if (status == ERROR_SUCCESS && stricmp (szValue, "WinNT")) - { - /* Note: There are (at least) three cases for ProductType: - WinNT = NT Workstation, ServerNT = NT Server, LanmanNT = - NT Server acting as a Domain Controller. */ - is_workstation = 0; - if ( debug_me ) - log_debug ("rndw32: this is a NT server\n"); - } - RegCloseKey (hKey); - } - - /* The following are fixed for the lifetime of the process so we - only add them once */ - /* readPnPData (); - we have not implemented that. */ - - /* Initialize the NetAPI32 function pointers if necessary */ - hNetAPI32 = LoadLibrary ("NETAPI32.DLL"); - if (hNetAPI32) - { - if (debug_me) - log_debug ("rndw32#slow_gatherer: netapi32 loaded\n" ); - pNetStatisticsGet = (NETSTATISTICSGET) - GetProcAddress (hNetAPI32, "NetStatisticsGet"); - pNetApiBufferSize = (NETAPIBUFFERSIZE) - GetProcAddress (hNetAPI32, "NetApiBufferSize"); - pNetApiBufferFree = (NETAPIBUFFERFREE) - GetProcAddress (hNetAPI32, "NetApiBufferFree"); - - if (!pNetStatisticsGet || !pNetApiBufferSize || !pNetApiBufferFree) - { - FreeLibrary (hNetAPI32); - hNetAPI32 = NULL; - log_debug ("rndw32: No NETAPI found\n" ); - } - } - - /* Initialize the NT kernel native API function pointers if necessary */ - hNTAPI = GetModuleHandle ("NTDll.dll"); - if (hNTAPI) - { - /* Get a pointer to the NT native information query functions */ - pNtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION) - GetProcAddress (hNTAPI, "NtQuerySystemInformation"); - pNtQueryInformationProcess = (NTQUERYINFORMATIONPROCESS) - GetProcAddress (hNTAPI, "NtQueryInformationProcess"); - pNtPowerInformation = (NTPOWERINFORMATION) - GetProcAddress(hNTAPI, "NtPowerInformation"); - - if (!pNtQuerySystemInformation || !pNtQueryInformationProcess) - hNTAPI = NULL; - } - - - is_initialized = 1; - } - - read_system_rng ( add, requester ); - read_mbm_data ( add, requester ); - - /* Get network statistics. Note: Both NT Workstation and NT Server by - default will be running both the workstation and server services. The - heuristic below is probably useful though on the assumption that the - majority of the network traffic will be via the appropriate service. - In any case the network statistics return almost no randomness. */ - { - LPBYTE lpBuffer; - - if (hNetAPI32 - && !pNetStatisticsGet (NULL, - is_workstation ? L"LanmanWorkstation" : - L"LanmanServer", 0, 0, &lpBuffer)) - { - if ( debug_me ) - log_debug ("rndw32#slow_gatherer: get netstats\n" ); - pNetApiBufferSize (lpBuffer, &dwSize); - (*add) ( lpBuffer, dwSize, requester ); - pNetApiBufferFree (lpBuffer); - } - } - - /* Get disk I/O statistics for all the hard drives. 100 is an - arbitrary failsafe limit. */ - for (drive_no = 0; drive_no < 100 ; drive_no++) - { - char diskPerformance[SIZEOF_DISK_PERFORMANCE_STRUCT + 8]; - char szDevice[50]; - - /* Check whether we can access this device. */ - snprintf (szDevice, sizeof szDevice, "\\\\.\\PhysicalDrive%d", - drive_no); - hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, 0, NULL); - if (hDevice == INVALID_HANDLE_VALUE) - break; /* No more drives. */ - - /* Note: This only works if you have turned on the disk performance - counters with 'diskperf -y'. These counters are off by default. */ - dwSize = sizeof diskPerformance; - if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, - diskPerformance, SIZEOF_DISK_PERFORMANCE_STRUCT, - &dwSize, NULL)) - { - if ( debug_me ) - log_debug ("rndw32#slow_gatherer: iostat drive %d\n", - drive_no); - (*add) (diskPerformance, dwSize, requester); - } - else - { - log_info ("NOTE: you should run 'diskperf -y' " - "to enable the disk statistics\n"); - } - CloseHandle (hDevice); - } - - /* In theory we should be using the Win32 performance query API to obtain - unpredictable data from the system, however this is so unreliable (see - the multiple sets of comments in registryPoll()) that it's too risky - to rely on it except as a fallback in emergencies. Instead, we rely - mostly on the NT native API function NtQuerySystemInformation(), which - has the dual advantages that it doesn't have as many (known) problems - as the Win32 equivalent and that it doesn't access the data indirectly - via pseudo-registry keys, which means that it's much faster. Note - that the Win32 equivalent actually works almost all of the time, the - problem is that on one or two systems it can fail in strange ways that - are never the same and can't be reproduced on any other system, which - is why we use the native API here. Microsoft officially documented - this function in early 2003, so it'll be fairly safe to use. */ - if ( !hNTAPI ) - { - registry_poll (add, requester); - return; - } - - - /* Scan the first 64 possible information types (we don't bother with - increasing the buffer size as we do with the Win32 version of the - performance data read, we may miss a few classes but it's no big deal). - This scan typically yields around 20 pieces of data, there's nothing - in the range 65...128 so chances are there won't be anything above - there either. */ - buffer = gcry_xmalloc (PERFORMANCE_BUFFER_SIZE); - for (dwType = 0; dwType < 64; dwType++) - { - switch (dwType) - { - /* ID 17 = SystemObjectInformation hangs on some win2k systems. */ - case 17: - if (system_is_w2000) - continue; - break; - - /* Some information types are write-only (the IDs are shared with - a set-information call), we skip these. */ - case 26: case 27: case 38: case 46: case 47: case 48: case 52: - continue; - - /* ID 53 = SystemSessionProcessInformation reads input from the - output buffer, which has to contain a session ID and pointer - to the actual buffer in which to store the session information. - Because this isn't a standard query, we skip this. */ - case 53: - continue; - } - - /* Query the info for this ID. Some results (for example for - ID = 6, SystemCallCounts) are only available in checked builds - of the kernel. A smaller subcless of results require that - certain system config flags be set, for example - SystemObjectInformation requires that the - FLG_MAINTAIN_OBJECT_TYPELIST be set in NtGlobalFlags. To avoid - having to special-case all of these, we try reading each one and - only use those for which we get a success status. */ - dwResult = pNtQuerySystemInformation (dwType, buffer, - PERFORMANCE_BUFFER_SIZE - 2048, - &ulSize); - if (dwResult != ERROR_SUCCESS) - continue; - - /* Some calls (e.g. ID = 23, SystemProcessorStatistics, and ID = 24, - SystemDpcInformation) incorrectly return a length of zero, so we - manually adjust the length to the correct value. */ - if ( !ulSize ) - { - if (dwType == 23) - ulSize = 6 * sizeof (ULONG); - else if (dwType == 24) - ulSize = 5 * sizeof (ULONG); - } - - /* If we got some data back, add it to the entropy pool. */ - if (ulSize > 0 && ulSize <= PERFORMANCE_BUFFER_SIZE - 2048) - { - if (debug_me) - log_debug ("rndw32#slow_gatherer: %lu bytes from sysinfo %ld\n", - ulSize, dwType); - (*add) (buffer, ulSize, requester); - no_results++; - } - } - - /* Now we would do the same for the process information. This - call would rather ugly in that it requires an exact length - match for the data returned, failing with a - STATUS_INFO_LENGTH_MISMATCH error code (0xC0000004) if the - length isn't an exact match. It requires a compiler to handle - complex nested structs, alignment issues, and so on, and - without the headers in which the entries are declared it's - almost impossible to do. Thus we don't. */ - - - /* Finally, do the same for the system power status information. There - are only a limited number of useful information types available so we - restrict ourselves to the useful types. In addition since this - function doesn't return length information, we have to hardcode in - length data. */ - if (pNtPowerInformation) - { - static const struct { int type; int size; } powerInfo[] = { - { 0, 128 }, /* SystemPowerPolicyAc */ - { 1, 128 }, /* SystemPowerPolicyDc */ - { 4, 64 }, /* SystemPowerCapabilities */ - { 5, 48 }, /* SystemBatteryState */ - { 11, 48 }, /* ProcessorInformation */ - { 12, 24 }, /* SystemPowerInformation */ - { -1, -1 } - }; - int i; - - /* The 100 is a failsafe limit. */ - for (i = 0; powerInfo[i].type != -1 && i < 100; i++ ) - { - /* Query the info for this ID */ - dwResult = pNtPowerInformation (powerInfo[i].type, NULL, 0, buffer, - PERFORMANCE_BUFFER_SIZE - 2048); - if (dwResult != ERROR_SUCCESS) - continue; - if (debug_me) - log_debug ("rndw32#slow_gatherer: %u bytes from powerinfo %d\n", - powerInfo[i].size, i); - (*add) (buffer, powerInfo[i].size, requester); - no_results++; - } - gcry_assert (i < 100); - } - gcry_free (buffer); - - /* We couldn't get enough results from the kernel, fall back to the - somewhat troublesome registry poll. */ - if (no_results < 15) - registry_poll (add, requester); -} - - -int -_gcry_rndw32_gather_random (void (*add)(const void*, size_t, - enum random_origins), - enum random_origins origin, - size_t length, int level ) -{ - static int is_initialized; - - if (!level) - return 0; - - /* We don't differentiate between level 1 and 2 here because there - is no internal entropy pool as a scary resource. It may all work - slower, but because our entropy source will never block but - deliver some not easy to measure entropy, we assume level 2. */ - - if (!is_initialized) - { - OSVERSIONINFO osvi = { sizeof( osvi ) }; - - GetVersionEx( &osvi ); - if ( osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) - log_fatal ("can only run on a Windows NT platform\n" ); - system_is_w2000 = (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0); - init_system_rng (); - is_initialized = 1; - } - - if (debug_me) - log_debug ("rndw32#gather_random: ori=%d len=%u lvl=%d\n", - origin, (unsigned int)length, level ); - - slow_gatherer (add, origin); - - return 0; -} - - - -void -_gcry_rndw32_gather_random_fast (void (*add)(const void*, size_t, - enum random_origins), - enum random_origins origin) -{ - static int addedFixedItems = 0; - - if ( debug_me ) - log_debug ("rndw32#gather_random_fast: ori=%d\n", origin ); - - /* Get various basic pieces of system information: Handle of active - window, handle of window with mouse capture, handle of clipboard - owner handle of start of clpboard viewer list, pseudohandle of - current process, current process ID, pseudohandle of current - thread, current thread ID, handle of desktop window, handle of - window with keyboard focus, whether system queue has any events, - cursor position for last message, 1 ms time for last message, - handle of window with clipboard open, handle of process heap, - handle of procs window station, types of events in input queue, - and milliseconds since Windows was started. */ - - { - byte buffer[20*sizeof(ulong)], *bufptr; - - bufptr = buffer; -#define ADD(f) do { ulong along = (ulong)(f); \ - memcpy (bufptr, &along, sizeof (along) ); \ - bufptr += sizeof (along); \ - } while (0) - - ADD ( GetActiveWindow ()); - ADD ( GetCapture ()); - ADD ( GetClipboardOwner ()); - ADD ( GetClipboardViewer ()); - ADD ( GetCurrentProcess ()); - ADD ( GetCurrentProcessId ()); - ADD ( GetCurrentThread ()); - ADD ( GetCurrentThreadId ()); - ADD ( GetDesktopWindow ()); - ADD ( GetFocus ()); - ADD ( GetInputState ()); - ADD ( GetMessagePos ()); - ADD ( GetMessageTime ()); - ADD ( GetOpenClipboardWindow ()); - ADD ( GetProcessHeap ()); - ADD ( GetProcessWindowStation ()); - ADD ( GetQueueStatus (QS_ALLEVENTS)); - ADD ( GetTickCount ()); - - gcry_assert ( bufptr-buffer < sizeof (buffer) ); - (*add) ( buffer, bufptr-buffer, origin ); -#undef ADD - } - - /* Get multiword system information: Current caret position, current - mouse cursor position. */ - { - POINT point; - - GetCaretPos (&point); - (*add) ( &point, sizeof (point), origin ); - GetCursorPos (&point); - (*add) ( &point, sizeof (point), origin ); - } - - /* Get percent of memory in use, bytes of physical memory, bytes of - free physical memory, bytes in paging file, free bytes in paging - file, user bytes of address space, and free user bytes. */ - { - MEMORYSTATUS memoryStatus; - - memoryStatus.dwLength = sizeof (MEMORYSTATUS); - GlobalMemoryStatus (&memoryStatus); - (*add) ( &memoryStatus, sizeof (memoryStatus), origin ); - } - - /* Get thread and process creation time, exit time, time in kernel - mode, and time in user mode in 100ns intervals. */ - { - HANDLE handle; - FILETIME creationTime, exitTime, kernelTime, userTime; - DWORD minimumWorkingSetSize, maximumWorkingSetSize; - - handle = GetCurrentThread (); - GetThreadTimes (handle, &creationTime, &exitTime, - &kernelTime, &userTime); - (*add) ( &creationTime, sizeof (creationTime), origin ); - (*add) ( &exitTime, sizeof (exitTime), origin ); - (*add) ( &kernelTime, sizeof (kernelTime), origin ); - (*add) ( &userTime, sizeof (userTime), origin ); - - handle = GetCurrentProcess (); - GetProcessTimes (handle, &creationTime, &exitTime, - &kernelTime, &userTime); - (*add) ( &creationTime, sizeof (creationTime), origin ); - (*add) ( &exitTime, sizeof (exitTime), origin ); - (*add) ( &kernelTime, sizeof (kernelTime), origin ); - (*add) ( &userTime, sizeof (userTime), origin ); - - /* Get the minimum and maximum working set size for the current - process. */ - GetProcessWorkingSetSize (handle, &minimumWorkingSetSize, - &maximumWorkingSetSize); - (*add) ( &minimumWorkingSetSize, - sizeof (minimumWorkingSetSize), origin ); - (*add) ( &maximumWorkingSetSize, - sizeof (maximumWorkingSetSize), origin ); - } - - - /* The following are fixed for the lifetime of the process so we only - * add them once */ - if (!addedFixedItems) - { - STARTUPINFO startupInfo; - - /* Get name of desktop, console window title, new window - position and size, window flags, and handles for stdin, - stdout, and stderr. */ - startupInfo.cb = sizeof (STARTUPINFO); - GetStartupInfo (&startupInfo); - (*add) ( &startupInfo, sizeof (STARTUPINFO), origin ); - addedFixedItems = 1; - } - - /* The performance of QPC varies depending on the architecture it's - running on and on the OS, the MS documentation is vague about the - details because it varies so much. Under Win9x/ME it reads the - 1.193180 MHz PIC timer. Under NT/Win2K/XP it may or may not read the - 64-bit TSC depending on the HAL and assorted other circumstances, - generally on machines with a uniprocessor HAL - KeQueryPerformanceCounter() uses a 3.579545MHz timer and on machines - with a multiprocessor or APIC HAL it uses the TSC (the exact time - source is controlled by the HalpUse8254 flag in the kernel). That - choice of time sources is somewhat peculiar because on a - multiprocessor machine it's theoretically possible to get completely - different TSC readings depending on which CPU you're currently - running on, while for uniprocessor machines it's not a problem. - However, the kernel appears to synchronise the TSCs across CPUs at - boot time (it resets the TSC as part of its system init), so this - shouldn't really be a problem. Under WinCE it's completely platform- - dependant, if there's no hardware performance counter available, it - uses the 1ms system timer. - - Another feature of the TSC (although it doesn't really affect us here) - is that mobile CPUs will turn off the TSC when they idle, Pentiums - will change the rate of the counter when they clock-throttle (to - match the current CPU speed), and hyperthreading Pentiums will turn - it off when both threads are idle (this more or less makes sense, - since the CPU will be in the halted state and not executing any - instructions to count). - - To make things unambiguous, we detect a CPU new enough to call RDTSC - directly by checking for CPUID capabilities, and fall back to QPC if - this isn't present. */ -#ifdef __GNUC__ -/* FIXME: We would need to implement the CPU feature tests first. */ -/* if (cpu_has_feature_rdtsc) */ -/* { */ -/* uint32_t lo, hi; */ - /* We cannot use "=A", since this would use %rax on x86_64. */ -/* __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); */ - /* Ignore high 32 bits, hwich are >1s res. */ -/* (*add) (&lo, 4, origin ); */ -/* } */ -/* else */ -#endif /*!__GNUC__*/ - { - LARGE_INTEGER performanceCount; - - if (QueryPerformanceCounter (&performanceCount)) - { - if ( debug_me ) - log_debug ("rndw32#gather_random_fast: perf data\n"); - (*add) (&performanceCount, sizeof (performanceCount), origin); - } - else - { - /* Millisecond accuracy at best... */ - DWORD aword = GetTickCount (); - (*add) (&aword, sizeof (aword), origin ); - } - } - - -} diff --git a/plugins/MirOTR/Libgcrypt/cipher/rsa-common.c b/plugins/MirOTR/Libgcrypt/cipher/rsa-common.c new file mode 100644 index 0000000000..4f5a6594a8 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/rsa-common.c @@ -0,0 +1,973 @@ +/* rsa-common.c - Supporting functions for RSA + * Copyright (C) 2011 Free Software Foundation, Inc. + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "g10lib.h" +#include "mpi.h" +#include "cipher.h" +#include "pubkey-internal.h" + + +/* Turn VALUE into an octet string and store it in an allocated buffer + at R_FRAME or - if R_RAME is NULL - copy it into the caller + provided buffer SPACE; either SPACE or R_FRAME may be used. If + SPACE if not NULL, the caller must provide a buffer of at least + NBYTES. If the resulting octet string is shorter than NBYTES pad + it to the left with zeroes. If VALUE does not fit into NBYTES + return an error code. */ +static gpg_err_code_t +octet_string_from_mpi (unsigned char **r_frame, void *space, + gcry_mpi_t value, size_t nbytes) +{ + return _gcry_mpi_to_octet_string (r_frame, space, value, nbytes); +} + + + +/* Encode {VALUE,VALUELEN} for an NBITS keys using the pkcs#1 block + type 2 padding. On sucess the result is stored as a new MPI at + R_RESULT. On error the value at R_RESULT is undefined. + + If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as + the seed instead of using a random string for it. This feature is + only useful for regression tests. Note that this value may not + contain zero bytes. + + We encode the value in this way: + + 0 2 RND(n bytes) 0 VALUE + + 0 is a marker we unfortunately can't encode because we return an + MPI which strips all leading zeroes. + 2 is the block type. + RND are non-zero random bytes. + + (Note that OpenPGP includes the cipher algorithm and a checksum in + VALUE; the caller needs to prepare the value accordingly.) + */ +gpg_err_code_t +_gcry_rsa_pkcs1_encode_for_enc (gcry_mpi_t *r_result, unsigned int nbits, + const unsigned char *value, size_t valuelen, + const unsigned char *random_override, + size_t random_override_len) +{ + gcry_err_code_t rc = 0; + unsigned char *frame = NULL; + size_t nframe = (nbits+7) / 8; + int i; + size_t n; + unsigned char *p; + + if (valuelen + 7 > nframe || !nframe) + { + /* Can't encode a VALUELEN value in a NFRAME bytes frame. */ + return GPG_ERR_TOO_SHORT; /* The key is too short. */ + } + + if ( !(frame = xtrymalloc_secure (nframe))) + return gpg_err_code_from_syserror (); + + n = 0; + frame[n++] = 0; + frame[n++] = 2; /* block type */ + i = nframe - 3 - valuelen; + gcry_assert (i > 0); + + if (random_override) + { + int j; + + if (random_override_len != i) + { + xfree (frame); + return GPG_ERR_INV_ARG; + } + /* Check that random does not include a zero byte. */ + for (j=0; j < random_override_len; j++) + if (!random_override[j]) + { + xfree (frame); + return GPG_ERR_INV_ARG; + } + memcpy (frame + n, random_override, random_override_len); + n += random_override_len; + } + else + { + p = _gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM); + /* Replace zero bytes by new values. */ + for (;;) + { + int j, k; + unsigned char *pp; + + /* Count the zero bytes. */ + for (j=k=0; j < i; j++) + { + if (!p[j]) + k++; + } + if (!k) + break; /* Okay: no (more) zero bytes. */ + + k += k/128 + 3; /* Better get some more. */ + pp = _gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM); + for (j=0; j < i && k; ) + { + if (!p[j]) + p[j] = pp[--k]; + if (p[j]) + j++; + } + xfree (pp); + } + memcpy (frame+n, p, i); + n += i; + xfree (p); + } + + frame[n++] = 0; + memcpy (frame+n, value, valuelen); + n += valuelen; + gcry_assert (n == nframe); + + rc = _gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, n, &nframe); + if (!rc &&DBG_CIPHER) + log_mpidump ("PKCS#1 block type 2 encoded data", *r_result); + xfree (frame); + + return rc; +} + + +/* Decode a plaintext in VALUE assuming pkcs#1 block type 2 padding. + NBITS is the size of the secret key. On success the result is + stored as a newly allocated buffer at R_RESULT and its valid length at + R_RESULTLEN. On error NULL is stored at R_RESULT. */ +gpg_err_code_t +_gcry_rsa_pkcs1_decode_for_enc (unsigned char **r_result, size_t *r_resultlen, + unsigned int nbits, gcry_mpi_t value) +{ + gcry_error_t err; + unsigned char *frame = NULL; + size_t nframe = (nbits+7) / 8; + size_t n; + + *r_result = NULL; + + if ( !(frame = xtrymalloc_secure (nframe))) + return gpg_err_code_from_syserror (); + + err = _gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &n, value); + if (err) + { + xfree (frame); + return gcry_err_code (err); + } + + nframe = n; /* Set NFRAME to the actual length. */ + + /* FRAME = 0x00 || 0x02 || PS || 0x00 || M + + pkcs#1 requires that the first byte is zero. Our MPIs usually + strip leading zero bytes; thus we are not able to detect them. + However due to the way gcry_mpi_print is implemented we may see + leading zero bytes nevertheless. We handle this by making the + first zero byte optional. */ + if (nframe < 4) + { + xfree (frame); + return GPG_ERR_ENCODING_PROBLEM; /* Too short. */ + } + n = 0; + if (!frame[0]) + n++; + if (frame[n++] != 0x02) + { + xfree (frame); + return GPG_ERR_ENCODING_PROBLEM; /* Wrong block type. */ + } + + /* Skip the non-zero random bytes and the terminating zero byte. */ + for (; n < nframe && frame[n] != 0x00; n++) + ; + if (n+1 >= nframe) + { + xfree (frame); + return GPG_ERR_ENCODING_PROBLEM; /* No zero byte. */ + } + n++; /* Skip the zero byte. */ + + /* To avoid an extra allocation we reuse the frame buffer. The only + caller of this function will anyway free the result soon. */ + memmove (frame, frame + n, nframe - n); + *r_result = frame; + *r_resultlen = nframe - n; + + if (DBG_CIPHER) + log_printhex ("value extracted from PKCS#1 block type 2 encoded data", + *r_result, *r_resultlen); + + return 0; +} + + +/* Encode {VALUE,VALUELEN} for an NBITS keys and hash algorith ALGO + using the pkcs#1 block type 1 padding. On success the result is + stored as a new MPI at R_RESULT. On error the value at R_RESULT is + undefined. + + We encode the value in this way: + + 0 1 PAD(n bytes) 0 ASN(asnlen bytes) VALUE(valuelen bytes) + + 0 is a marker we unfortunately can't encode because we return an + MPI which strips all leading zeroes. + 1 is the block type. + PAD consists of 0xff bytes. + 0 marks the end of the padding. + ASN is the DER encoding of the hash algorithm; along with the VALUE + it yields a valid DER encoding. + + (Note that PGP prior to version 2.3 encoded the message digest as: + 0 1 MD(16 bytes) 0 PAD(n bytes) 1 + The MD is always 16 bytes here because it's always MD5. GnuPG + does not not support pre-v2.3 signatures, but I'm including this + comment so the information is easily found if needed.) +*/ +gpg_err_code_t +_gcry_rsa_pkcs1_encode_for_sig (gcry_mpi_t *r_result, unsigned int nbits, + const unsigned char *value, size_t valuelen, + int algo) +{ + gcry_err_code_t rc = 0; + byte asn[100]; + byte *frame = NULL; + size_t nframe = (nbits+7) / 8; + int i; + size_t n; + size_t asnlen, dlen; + + asnlen = DIM(asn); + dlen = _gcry_md_get_algo_dlen (algo); + + if (_gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen)) + { + /* We don't have yet all of the above algorithms. */ + return GPG_ERR_NOT_IMPLEMENTED; + } + + if ( valuelen != dlen ) + { + /* Hash value does not match the length of digest for + the given algorithm. */ + return GPG_ERR_CONFLICT; + } + + if ( !dlen || dlen + asnlen + 4 > nframe) + { + /* Can't encode an DLEN byte digest MD into an NFRAME byte + frame. */ + return GPG_ERR_TOO_SHORT; + } + + if ( !(frame = xtrymalloc (nframe)) ) + return gpg_err_code_from_syserror (); + + /* Assemble the pkcs#1 block type 1. */ + n = 0; + frame[n++] = 0; + frame[n++] = 1; /* block type */ + i = nframe - valuelen - asnlen - 3 ; + gcry_assert (i > 1); + memset (frame+n, 0xff, i ); + n += i; + frame[n++] = 0; + memcpy (frame+n, asn, asnlen); + n += asnlen; + memcpy (frame+n, value, valuelen ); + n += valuelen; + gcry_assert (n == nframe); + + /* Convert it into an MPI. */ + rc = _gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, n, &nframe); + if (!rc && DBG_CIPHER) + log_mpidump ("PKCS#1 block type 1 encoded data", *r_result); + xfree (frame); + + return rc; +} + + +/* Mask generation function for OAEP. See RFC-3447 B.2.1. */ +static gcry_err_code_t +mgf1 (unsigned char *output, size_t outlen, unsigned char *seed, size_t seedlen, + int algo) +{ + size_t dlen, nbytes, n; + int idx; + gcry_md_hd_t hd; + gcry_error_t err; + + err = _gcry_md_open (&hd, algo, 0); + if (err) + return err; + + dlen = _gcry_md_get_algo_dlen (algo); + + /* We skip step 1 which would be assert(OUTLEN <= 2^32). The loop + in step 3 is merged with step 4 by concatenating no more octets + than what would fit into OUTPUT. The ceiling for the counter IDX + is implemented indirectly. */ + nbytes = 0; /* Step 2. */ + idx = 0; + while ( nbytes < outlen ) + { + unsigned char c[4], *digest; + + if (idx) + _gcry_md_reset (hd); + + c[0] = (idx >> 24) & 0xFF; + c[1] = (idx >> 16) & 0xFF; + c[2] = (idx >> 8) & 0xFF; + c[3] = idx & 0xFF; + idx++; + + _gcry_md_write (hd, seed, seedlen); + _gcry_md_write (hd, c, 4); + digest = _gcry_md_read (hd, 0); + + n = (outlen - nbytes < dlen)? (outlen - nbytes) : dlen; + memcpy (output+nbytes, digest, n); + nbytes += n; + } + + _gcry_md_close (hd); + return GPG_ERR_NO_ERROR; +} + + +/* RFC-3447 (pkcs#1 v2.1) OAEP encoding. NBITS is the length of the + key measured in bits. ALGO is the hash function; it must be a + valid and usable algorithm. {VALUE,VALUELEN} is the message to + encrypt. {LABEL,LABELLEN} is the optional label to be associated + with the message, if LABEL is NULL the default is to use the empty + string as label. On success the encoded ciphertext is returned at + R_RESULT. + + If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as + the seed instead of using a random string for it. This feature is + only useful for regression tests. + + Here is figure 1 from the RFC depicting the process: + + +----------+---------+-------+ + DB = | lHash | PS | M | + +----------+---------+-------+ + | + +----------+ V + | seed |--> MGF ---> xor + +----------+ | + | | + +--+ V | + |00| xor <----- MGF <-----| + +--+ | | + | | | + V V V + +--+----------+----------------------------+ + EM = |00|maskedSeed| maskedDB | + +--+----------+----------------------------+ + */ +gpg_err_code_t +_gcry_rsa_oaep_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo, + const unsigned char *value, size_t valuelen, + const unsigned char *label, size_t labellen, + const void *random_override, size_t random_override_len) +{ + gcry_err_code_t rc = 0; + unsigned char *frame = NULL; + size_t nframe = (nbits+7) / 8; + unsigned char *p; + size_t hlen; + size_t n; + + *r_result = NULL; + + /* Set defaults for LABEL. */ + if (!label || !labellen) + { + label = (const unsigned char*)""; + labellen = 0; + } + + hlen = _gcry_md_get_algo_dlen (algo); + + /* We skip step 1a which would be to check that LABELLEN is not + greater than 2^61-1. See rfc-3447 7.1.1. */ + + /* Step 1b. Note that the obsolete rfc-2437 uses the check: + valuelen > nframe - 2 * hlen - 1 . */ + if (valuelen > nframe - 2 * hlen - 2 || !nframe) + { + /* Can't encode a VALUELEN value in a NFRAME bytes frame. */ + return GPG_ERR_TOO_SHORT; /* The key is too short. */ + } + + /* Allocate the frame. */ + frame = xtrycalloc_secure (1, nframe); + if (!frame) + return gpg_err_code_from_syserror (); + + /* Step 2a: Compute the hash of the label. We store it in the frame + where later the maskedDB will commence. */ + _gcry_md_hash_buffer (algo, frame + 1 + hlen, label, labellen); + + /* Step 2b: Set octet string to zero. */ + /* This has already been done while allocating FRAME. */ + + /* Step 2c: Create DB by concatenating lHash, PS, 0x01 and M. */ + n = nframe - valuelen - 1; + frame[n] = 0x01; + memcpy (frame + n + 1, value, valuelen); + + /* Step 3d: Generate seed. We store it where the maskedSeed will go + later. */ + if (random_override) + { + if (random_override_len != hlen) + { + xfree (frame); + return GPG_ERR_INV_ARG; + } + memcpy (frame + 1, random_override, hlen); + } + else + _gcry_randomize (frame + 1, hlen, GCRY_STRONG_RANDOM); + + /* Step 2e and 2f: Create maskedDB. */ + { + unsigned char *dmask; + + dmask = xtrymalloc_secure (nframe - hlen - 1); + if (!dmask) + { + rc = gpg_err_code_from_syserror (); + xfree (frame); + return rc; + } + rc = mgf1 (dmask, nframe - hlen - 1, frame+1, hlen, algo); + if (rc) + { + xfree (dmask); + xfree (frame); + return rc; + } + for (n = 1 + hlen, p = dmask; n < nframe; n++) + frame[n] ^= *p++; + xfree (dmask); + } + + /* Step 2g and 2h: Create maskedSeed. */ + { + unsigned char *smask; + + smask = xtrymalloc_secure (hlen); + if (!smask) + { + rc = gpg_err_code_from_syserror (); + xfree (frame); + return rc; + } + rc = mgf1 (smask, hlen, frame + 1 + hlen, nframe - hlen - 1, algo); + if (rc) + { + xfree (smask); + xfree (frame); + return rc; + } + for (n = 1, p = smask; n < 1 + hlen; n++) + frame[n] ^= *p++; + xfree (smask); + } + + /* Step 2i: Concatenate 0x00, maskedSeed and maskedDB. */ + /* This has already been done by using in-place operations. */ + + /* Convert the stuff into an MPI as expected by the caller. */ + rc = _gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, nframe, NULL); + if (!rc && DBG_CIPHER) + log_mpidump ("OAEP encoded data", *r_result); + xfree (frame); + + return rc; +} + + +/* RFC-3447 (pkcs#1 v2.1) OAEP decoding. NBITS is the length of the + key measured in bits. ALGO is the hash function; it must be a + valid and usable algorithm. VALUE is the raw decrypted message + {LABEL,LABELLEN} is the optional label to be associated with the + message, if LABEL is NULL the default is to use the empty string as + label. On success the plaintext is returned as a newly allocated + buffer at R_RESULT; its valid length is stored at R_RESULTLEN. On + error NULL is stored at R_RESULT. */ +gpg_err_code_t +_gcry_rsa_oaep_decode (unsigned char **r_result, size_t *r_resultlen, + unsigned int nbits, int algo, + gcry_mpi_t value, + const unsigned char *label, size_t labellen) +{ + gcry_err_code_t rc; + unsigned char *frame = NULL; /* Encoded messages (EM). */ + unsigned char *masked_seed; /* Points into FRAME. */ + unsigned char *masked_db; /* Points into FRAME. */ + unsigned char *seed = NULL; /* Allocated space for the seed and DB. */ + unsigned char *db; /* Points into SEED. */ + unsigned char *lhash = NULL; /* Hash of the label. */ + size_t nframe; /* Length of the ciphertext (EM). */ + size_t hlen; /* Length of the hash digest. */ + size_t db_len; /* Length of DB and masked_db. */ + size_t nkey = (nbits+7)/8; /* Length of the key in bytes. */ + int failed = 0; /* Error indicator. */ + size_t n; + + *r_result = NULL; + + /* This code is implemented as described by rfc-3447 7.1.2. */ + + /* Set defaults for LABEL. */ + if (!label || !labellen) + { + label = (const unsigned char*)""; + labellen = 0; + } + + /* Get the length of the digest. */ + hlen = _gcry_md_get_algo_dlen (algo); + + /* Hash the label right away. */ + lhash = xtrymalloc (hlen); + if (!lhash) + return gpg_err_code_from_syserror (); + _gcry_md_hash_buffer (algo, lhash, label, labellen); + + /* Turn the MPI into an octet string. If the octet string is + shorter than the key we pad it to the left with zeroes. This may + happen due to the leading zero in OAEP frames and due to the + following random octets (seed^mask) which may have leading zero + bytes. This all is needed to cope with our leading zeroes + suppressing MPI implementation. The code implictly implements + Step 1b (bail out if NFRAME != N). */ + rc = octet_string_from_mpi (&frame, NULL, value, nkey); + if (rc) + { + xfree (lhash); + return GPG_ERR_ENCODING_PROBLEM; + } + nframe = nkey; + + /* Step 1c: Check that the key is long enough. */ + if ( nframe < 2 * hlen + 2 ) + { + xfree (frame); + xfree (lhash); + return GPG_ERR_ENCODING_PROBLEM; + } + + /* Step 2 has already been done by the caller and the + gcry_mpi_aprint above. */ + + /* Allocate space for SEED and DB. */ + seed = xtrymalloc_secure (nframe - 1); + if (!seed) + { + rc = gpg_err_code_from_syserror (); + xfree (frame); + xfree (lhash); + return rc; + } + db = seed + hlen; + + /* To avoid choosen ciphertext attacks from now on we make sure to + run all code even in the error case; this avoids possible timing + attacks as described by Manger. */ + + /* Step 3a: Hash the label. */ + /* This has already been done. */ + + /* Step 3b: Separate the encoded message. */ + masked_seed = frame + 1; + masked_db = frame + 1 + hlen; + db_len = nframe - 1 - hlen; + + /* Step 3c and 3d: seed = maskedSeed ^ mgf(maskedDB, hlen). */ + if (mgf1 (seed, hlen, masked_db, db_len, algo)) + failed = 1; + for (n = 0; n < hlen; n++) + seed[n] ^= masked_seed[n]; + + /* Step 3e and 3f: db = maskedDB ^ mgf(seed, db_len). */ + if (mgf1 (db, db_len, seed, hlen, algo)) + failed = 1; + for (n = 0; n < db_len; n++) + db[n] ^= masked_db[n]; + + /* Step 3g: Check lhash, an possible empty padding string terminated + by 0x01 and the first byte of EM being 0. */ + if (memcmp (lhash, db, hlen)) + failed = 1; + for (n = hlen; n < db_len; n++) + if (db[n] == 0x01) + break; + if (n == db_len) + failed = 1; + if (frame[0]) + failed = 1; + + xfree (lhash); + xfree (frame); + if (failed) + { + xfree (seed); + return GPG_ERR_ENCODING_PROBLEM; + } + + /* Step 4: Output M. */ + /* To avoid an extra allocation we reuse the seed buffer. The only + caller of this function will anyway free the result soon. */ + n++; + memmove (seed, db + n, db_len - n); + *r_result = seed; + *r_resultlen = db_len - n; + seed = NULL; + + if (DBG_CIPHER) + log_printhex ("value extracted from OAEP encoded data", + *r_result, *r_resultlen); + + return 0; +} + + +/* RFC-3447 (pkcs#1 v2.1) PSS encoding. Encode {VALUE,VALUELEN} for + an NBITS key. Note that VALUE is already the mHash from the + picture below. ALGO is a valid hash algorithm and SALTLEN is the + length of salt to be used. On success the result is stored as a + new MPI at R_RESULT. On error the value at R_RESULT is undefined. + + If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as + the salt instead of using a random string for the salt. This + feature is only useful for regression tests. + + Here is figure 2 from the RFC (errata 595 applied) depicting the + process: + + +-----------+ + | M | + +-----------+ + | + V + Hash + | + V + +--------+----------+----------+ + M' = |Padding1| mHash | salt | + +--------+----------+----------+ + | + +--------+----------+ V + DB = |Padding2| salt | Hash + +--------+----------+ | + | | + V | +----+ + xor <--- MGF <---| |0xbc| + | | +----+ + | | | + V V V + +-------------------+----------+----+ + EM = | maskedDB | H |0xbc| + +-------------------+----------+----+ + + */ +gpg_err_code_t +_gcry_rsa_pss_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo, + const unsigned char *value, size_t valuelen, int saltlen, + const void *random_override, size_t random_override_len) +{ + gcry_err_code_t rc = 0; + size_t hlen; /* Length of the hash digest. */ + unsigned char *em = NULL; /* Encoded message. */ + size_t emlen = (nbits+7)/8; /* Length in bytes of EM. */ + unsigned char *h; /* Points into EM. */ + unsigned char *buf = NULL; /* Help buffer. */ + size_t buflen; /* Length of BUF. */ + unsigned char *mhash; /* Points into BUF. */ + unsigned char *salt; /* Points into BUF. */ + unsigned char *dbmask; /* Points into BUF. */ + unsigned char *p; + size_t n; + + /* This code is implemented as described by rfc-3447 9.1.1. */ + + /* Get the length of the digest. */ + hlen = _gcry_md_get_algo_dlen (algo); + gcry_assert (hlen); /* We expect a valid ALGO here. */ + + /* Allocate a help buffer and setup some pointers. */ + buflen = 8 + hlen + saltlen + (emlen - hlen - 1); + buf = xtrymalloc (buflen); + if (!buf) + { + rc = gpg_err_code_from_syserror (); + goto leave; + } + mhash = buf + 8; + salt = mhash + hlen; + dbmask= salt + saltlen; + + /* Step 2: That would be: mHash = Hash(M) but our input is already + mHash thus we do only a consistency check and copy to MHASH. */ + if (valuelen != hlen) + { + rc = GPG_ERR_INV_LENGTH; + goto leave; + } + memcpy (mhash, value, hlen); + + /* Step 3: Check length constraints. */ + if (emlen < hlen + saltlen + 2) + { + rc = GPG_ERR_TOO_SHORT; + goto leave; + } + + /* Allocate space for EM. */ + em = xtrymalloc (emlen); + if (!em) + { + rc = gpg_err_code_from_syserror (); + goto leave; + } + h = em + emlen - 1 - hlen; + + /* Step 4: Create a salt. */ + if (saltlen) + { + if (random_override) + { + if (random_override_len != saltlen) + { + rc = GPG_ERR_INV_ARG; + goto leave; + } + memcpy (salt, random_override, saltlen); + } + else + _gcry_randomize (salt, saltlen, GCRY_STRONG_RANDOM); + } + + /* Step 5 and 6: M' = Hash(Padding1 || mHash || salt). */ + memset (buf, 0, 8); /* Padding. */ + _gcry_md_hash_buffer (algo, h, buf, 8 + hlen + saltlen); + + /* Step 7 and 8: DB = PS || 0x01 || salt. */ + /* Note that we use EM to store DB and later Xor in-place. */ + p = em + emlen - 1 - hlen - saltlen - 1; + memset (em, 0, p - em); + *p++ = 0x01; + memcpy (p, salt, saltlen); + + /* Step 9: dbmask = MGF(H, emlen - hlen - 1). */ + mgf1 (dbmask, emlen - hlen - 1, h, hlen, algo); + + /* Step 10: maskedDB = DB ^ dbMask */ + for (n = 0, p = dbmask; n < emlen - hlen - 1; n++, p++) + em[n] ^= *p; + + /* Step 11: Set the leftmost bits to zero. */ + em[0] &= 0xFF >> (8 * emlen - nbits); + + /* Step 12: EM = maskedDB || H || 0xbc. */ + em[emlen-1] = 0xbc; + + /* Convert EM into an MPI. */ + rc = _gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, em, emlen, NULL); + if (!rc && DBG_CIPHER) + log_mpidump ("PSS encoded data", *r_result); + + leave: + if (em) + { + wipememory (em, emlen); + xfree (em); + } + if (buf) + { + wipememory (buf, buflen); + xfree (buf); + } + return rc; +} + + +/* Verify a signature assuming PSS padding. VALUE is the hash of the + message (mHash) encoded as an MPI; its length must match the digest + length of ALGO. ENCODED is the output of the RSA public key + function (EM). NBITS is the size of the public key. ALGO is the + hash algorithm and SALTLEN is the length of the used salt. The + function returns 0 on success or on error code. */ +gpg_err_code_t +_gcry_rsa_pss_verify (gcry_mpi_t value, gcry_mpi_t encoded, + unsigned int nbits, int algo, size_t saltlen) +{ + gcry_err_code_t rc = 0; + size_t hlen; /* Length of the hash digest. */ + unsigned char *em = NULL; /* Encoded message. */ + size_t emlen = (nbits+7)/8; /* Length in bytes of EM. */ + unsigned char *salt; /* Points into EM. */ + unsigned char *h; /* Points into EM. */ + unsigned char *buf = NULL; /* Help buffer. */ + size_t buflen; /* Length of BUF. */ + unsigned char *dbmask; /* Points into BUF. */ + unsigned char *mhash; /* Points into BUF. */ + unsigned char *p; + size_t n; + + /* This code is implemented as described by rfc-3447 9.1.2. */ + + /* Get the length of the digest. */ + hlen = _gcry_md_get_algo_dlen (algo); + gcry_assert (hlen); /* We expect a valid ALGO here. */ + + /* Allocate a help buffer and setup some pointers. + This buffer is used for two purposes: + +------------------------------+-------+ + 1. | dbmask | mHash | + +------------------------------+-------+ + emlen - hlen - 1 hlen + + +----------+-------+---------+-+-------+ + 2. | padding1 | mHash | salt | | mHash | + +----------+-------+---------+-+-------+ + 8 hlen saltlen hlen + */ + buflen = 8 + hlen + saltlen; + if (buflen < emlen - hlen - 1) + buflen = emlen - hlen - 1; + buflen += hlen; + buf = xtrymalloc (buflen); + if (!buf) + { + rc = gpg_err_code_from_syserror (); + goto leave; + } + dbmask = buf; + mhash = buf + buflen - hlen; + + /* Step 2: That would be: mHash = Hash(M) but our input is already + mHash thus we only need to convert VALUE into MHASH. */ + rc = octet_string_from_mpi (NULL, mhash, value, hlen); + if (rc) + goto leave; + + /* Convert the signature into an octet string. */ + rc = octet_string_from_mpi (&em, NULL, encoded, emlen); + if (rc) + goto leave; + + /* Step 3: Check length of EM. Because we internally use MPI + functions we can't do this properly; EMLEN is always the length + of the key because octet_string_from_mpi needs to left pad the + result with zero to cope with the fact that our MPIs suppress all + leading zeroes. Thus what we test here are merely the digest and + salt lengths to the key. */ + if (emlen < hlen + saltlen + 2) + { + rc = GPG_ERR_TOO_SHORT; /* For the hash and saltlen. */ + goto leave; + } + + /* Step 4: Check last octet. */ + if (em[emlen - 1] != 0xbc) + { + rc = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + + /* Step 5: Split EM. */ + h = em + emlen - 1 - hlen; + + /* Step 6: Check the leftmost bits. */ + if ((em[0] & ~(0xFF >> (8 * emlen - nbits)))) + { + rc = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + + /* Step 7: dbmask = MGF(H, emlen - hlen - 1). */ + mgf1 (dbmask, emlen - hlen - 1, h, hlen, algo); + + /* Step 8: maskedDB = DB ^ dbMask. */ + for (n = 0, p = dbmask; n < emlen - hlen - 1; n++, p++) + em[n] ^= *p; + + /* Step 9: Set leftmost bits in DB to zero. */ + em[0] &= 0xFF >> (8 * emlen - nbits); + + /* Step 10: Check the padding of DB. */ + for (n = 0; n < emlen - hlen - saltlen - 2 && !em[n]; n++) + ; + if (n != emlen - hlen - saltlen - 2 || em[n++] != 1) + { + rc = GPG_ERR_BAD_SIGNATURE; + goto leave; + } + + /* Step 11: Extract salt from DB. */ + salt = em + n; + + /* Step 12: M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt */ + memset (buf, 0, 8); + memcpy (buf+8, mhash, hlen); + memcpy (buf+8+hlen, salt, saltlen); + + /* Step 13: H' = Hash(M'). */ + _gcry_md_hash_buffer (algo, buf, buf, 8 + hlen + saltlen); + + /* Step 14: Check H == H'. */ + rc = memcmp (h, buf, hlen) ? GPG_ERR_BAD_SIGNATURE : GPG_ERR_NO_ERROR; + + leave: + if (em) + { + wipememory (em, emlen); + xfree (em); + } + if (buf) + { + wipememory (buf, buflen); + xfree (buf); + } + return rc; +} diff --git a/plugins/MirOTR/Libgcrypt/cipher/rsa.c b/plugins/MirOTR/Libgcrypt/cipher/rsa.c index cf278c2532..9a8d235b9a 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/rsa.c +++ b/plugins/MirOTR/Libgcrypt/cipher/rsa.c @@ -32,6 +32,7 @@ #include "g10lib.h" #include "mpi.h" #include "cipher.h" +#include "pubkey-internal.h" typedef struct @@ -52,6 +53,15 @@ typedef struct } RSA_secret_key; +static const char *rsa_names[] = + { + "rsa", + "openpgp-rsa", + "oid.1.2.840.113549.1.1.1", + NULL, + }; + + /* A sample 1024 bit RSA key used for the selftests. */ static const char sample_secret_key[] = "(private-key" @@ -72,7 +82,7 @@ static const char sample_secret_key[] = " (u #304559a9ead56d2309d203811a641bb1a09626bc8eb36fffa23c968ec5bd891e" " ebbafc73ae666e01ba7c8990bae06cc2bbe10b75e69fcacb353a6473079d8e9b#)))"; /* A sample 1024 bit RSA key used for the selftests (public only). */ -static const char sample_public_key[] = +static const char sample_public_key[] = "(public-key" " (rsa" " (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa" @@ -88,6 +98,7 @@ static int test_keys (RSA_secret_key *sk, unsigned nbits); static int check_secret_key (RSA_secret_key *sk); static void public (gcry_mpi_t output, gcry_mpi_t input, RSA_public_key *skey); static void secret (gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey); +static unsigned int rsa_get_nbits (gcry_sexp_t parms); /* Check that a freshly generated key actually works. Returns 0 on success. */ @@ -96,56 +107,56 @@ test_keys (RSA_secret_key *sk, unsigned int nbits) { int result = -1; /* Default to failure. */ RSA_public_key pk; - gcry_mpi_t plaintext = gcry_mpi_new (nbits); - gcry_mpi_t ciphertext = gcry_mpi_new (nbits); - gcry_mpi_t decr_plaintext = gcry_mpi_new (nbits); - gcry_mpi_t signature = gcry_mpi_new (nbits); + gcry_mpi_t plaintext = mpi_new (nbits); + gcry_mpi_t ciphertext = mpi_new (nbits); + gcry_mpi_t decr_plaintext = mpi_new (nbits); + gcry_mpi_t signature = mpi_new (nbits); /* Put the relevant parameters into a public key structure. */ pk.n = sk->n; pk.e = sk->e; /* Create a random plaintext. */ - gcry_mpi_randomize (plaintext, nbits, GCRY_WEAK_RANDOM); + _gcry_mpi_randomize (plaintext, nbits, GCRY_WEAK_RANDOM); /* Encrypt using the public key. */ public (ciphertext, plaintext, &pk); /* Check that the cipher text does not match the plaintext. */ - if (!gcry_mpi_cmp (ciphertext, plaintext)) + if (!mpi_cmp (ciphertext, plaintext)) goto leave; /* Ciphertext is identical to the plaintext. */ /* Decrypt using the secret key. */ secret (decr_plaintext, ciphertext, sk); /* Check that the decrypted plaintext matches the original plaintext. */ - if (gcry_mpi_cmp (decr_plaintext, plaintext)) + if (mpi_cmp (decr_plaintext, plaintext)) goto leave; /* Plaintext does not match. */ /* Create another random plaintext as data for signature checking. */ - gcry_mpi_randomize (plaintext, nbits, GCRY_WEAK_RANDOM); + _gcry_mpi_randomize (plaintext, nbits, GCRY_WEAK_RANDOM); /* Use the RSA secret function to create a signature of the plaintext. */ secret (signature, plaintext, sk); - + /* Use the RSA public function to verify this signature. */ public (decr_plaintext, signature, &pk); - if (gcry_mpi_cmp (decr_plaintext, plaintext)) + if (mpi_cmp (decr_plaintext, plaintext)) goto leave; /* Signature does not match. */ /* Modify the signature and check that the signing fails. */ - gcry_mpi_add_ui (signature, signature, 1); + mpi_add_ui (signature, signature, 1); public (decr_plaintext, signature, &pk); - if (!gcry_mpi_cmp (decr_plaintext, plaintext)) + if (!mpi_cmp (decr_plaintext, plaintext)) goto leave; /* Signature matches but should not. */ result = 0; /* All tests succeeded. */ leave: - gcry_mpi_release (signature); - gcry_mpi_release (decr_plaintext); - gcry_mpi_release (ciphertext); - gcry_mpi_release (plaintext); + _gcry_mpi_release (signature); + _gcry_mpi_release (decr_plaintext); + _gcry_mpi_release (ciphertext); + _gcry_mpi_release (plaintext); return result; } @@ -158,22 +169,22 @@ check_exponent (void *arg, gcry_mpi_t a) gcry_mpi_t e = arg; gcry_mpi_t tmp; int result; - + mpi_sub_ui (a, a, 1); tmp = _gcry_mpi_alloc_like (a); - result = !gcry_mpi_gcd(tmp, e, a); /* GCD is not 1. */ - gcry_mpi_release (tmp); + result = !mpi_gcd(tmp, e, a); /* GCD is not 1. */ + _gcry_mpi_release (tmp); mpi_add_ui (a, a, 1); return result; } /**************** - * Generate a key pair with a key of size NBITS. + * Generate a key pair with a key of size NBITS. * USE_E = 0 let Libcgrypt decide what exponent to use. - * = 1 request the use of a "secure" exponent; this is required by some + * = 1 request the use of a "secure" exponent; this is required by some * specification to be 65537. * > 2 Use this public exponent. If the given exponent - * is not odd one is internally added to it. + * is not odd one is internally added to it. * TRANSIENT_KEY: If true, generate the primes using the standard RNG. * Returns: 2 structures filled with all needed values */ @@ -205,7 +216,7 @@ generate_std (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e, /* Make sure that nbits is even so that we generate p, q of equal size. */ if ( (nbits&1) ) - nbits++; + nbits++; if (use_e == 1) /* Alias for a secure value */ use_e = 65537; /* as demanded by Sphinx. */ @@ -213,7 +224,7 @@ generate_std (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e, /* Public exponent: In general we use 41 as this is quite fast and more secure than the commonly used 17. Benchmarking the RSA verify function - with a 1024 bit key yields (2001-11-08): + with a 1024 bit key yields (2001-11-08): e=17 0.54 ms e=41 0.75 ms e=257 0.95 ms @@ -222,22 +233,22 @@ generate_std (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e, e = mpi_alloc( (32+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB ); if (!use_e) mpi_set_ui (e, 41); /* This is a reasonable secure and fast value */ - else + else { use_e |= 1; /* make sure this is odd */ - mpi_set_ui (e, use_e); + mpi_set_ui (e, use_e); } - - n = gcry_mpi_new (nbits); + + n = mpi_new (nbits); p = q = NULL; do { /* select two (very secret) primes */ if (p) - gcry_mpi_release (p); + _gcry_mpi_release (p); if (q) - gcry_mpi_release (q); + _gcry_mpi_release (q); if (use_e) { /* Do an extra test to ensure that the given exponent is suitable. */ @@ -261,16 +272,16 @@ generate_std (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e, /* calculate Euler totient: phi = (p-1)(q-1) */ t1 = mpi_alloc_secure( mpi_get_nlimbs(p) ); t2 = mpi_alloc_secure( mpi_get_nlimbs(p) ); - phi = gcry_mpi_snew ( nbits ); - g = gcry_mpi_snew ( nbits ); - f = gcry_mpi_snew ( nbits ); + phi = mpi_snew ( nbits ); + g = mpi_snew ( nbits ); + f = mpi_snew ( nbits ); mpi_sub_ui( t1, p, 1 ); mpi_sub_ui( t2, q, 1 ); mpi_mul( phi, t1, t2 ); - gcry_mpi_gcd(g, t1, t2); + mpi_gcd (g, t1, t2); mpi_fdiv_q(f, phi, g); - while (!gcry_mpi_gcd(t1, e, phi)) /* (while gcd is not 1) */ + while (!mpi_gcd(t1, e, phi)) /* (while gcd is not 1) */ { if (use_e) BUG (); /* The prime generator already made sure that we @@ -279,10 +290,10 @@ generate_std (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e, } /* calculate the secret key d = e^1 mod phi */ - d = gcry_mpi_snew ( nbits ); - mpi_invm(d, e, f ); + d = mpi_snew ( nbits ); + mpi_invm (d, e, f ); /* calculate the inverse of p and q (used for chinese remainder theorem)*/ - u = gcry_mpi_snew ( nbits ); + u = mpi_snew ( nbits ); mpi_invm(u, p, q ); if( DBG_CIPHER ) @@ -298,11 +309,11 @@ generate_std (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e, log_mpidump(" u= ", u ); } - gcry_mpi_release (t1); - gcry_mpi_release (t2); - gcry_mpi_release (phi); - gcry_mpi_release (f); - gcry_mpi_release (g); + _gcry_mpi_release (t1); + _gcry_mpi_release (t2); + _gcry_mpi_release (phi); + _gcry_mpi_release (f); + _gcry_mpi_release (g); sk->n = n; sk->e = e; @@ -314,12 +325,12 @@ generate_std (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e, /* Now we can test our keys. */ if (test_keys (sk, nbits - 64)) { - gcry_mpi_release (sk->n); sk->n = NULL; - gcry_mpi_release (sk->e); sk->e = NULL; - gcry_mpi_release (sk->p); sk->p = NULL; - gcry_mpi_release (sk->q); sk->q = NULL; - gcry_mpi_release (sk->d); sk->d = NULL; - gcry_mpi_release (sk->u); sk->u = NULL; + _gcry_mpi_release (sk->n); sk->n = NULL; + _gcry_mpi_release (sk->e); sk->e = NULL; + _gcry_mpi_release (sk->p); sk->p = NULL; + _gcry_mpi_release (sk->q); sk->q = NULL; + _gcry_mpi_release (sk->d); sk->d = NULL; + _gcry_mpi_release (sk->u); sk->u = NULL; fips_signal_error ("self-test after key generation failed"); return GPG_ERR_SELFTEST_FAILED; } @@ -329,14 +340,14 @@ generate_std (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e, /* Helper for generate_x931. */ -static gcry_mpi_t +static gcry_mpi_t gen_x931_parm_xp (unsigned int nbits) { gcry_mpi_t xp; - xp = gcry_mpi_snew (nbits); - gcry_mpi_randomize (xp, nbits, GCRY_VERY_STRONG_RANDOM); - + xp = mpi_snew (nbits); + _gcry_mpi_randomize (xp, nbits, GCRY_VERY_STRONG_RANDOM); + /* The requirement for Xp is: sqrt{2}*2^{nbits-1} <= xp <= 2^{nbits} - 1 @@ -347,24 +358,24 @@ gen_x931_parm_xp (unsigned int nbits) mpi_set_highbit (xp, nbits-1); mpi_set_bit (xp, nbits-2); gcry_assert ( mpi_get_nbits (xp) == nbits ); - + return xp; -} +} /* Helper for generate_x931. */ -static gcry_mpi_t +static gcry_mpi_t gen_x931_parm_xi (void) { gcry_mpi_t xi; - xi = gcry_mpi_snew (101); - gcry_mpi_randomize (xi, 101, GCRY_VERY_STRONG_RANDOM); + xi = mpi_snew (101); + _gcry_mpi_randomize (xi, 101, GCRY_VERY_STRONG_RANDOM); mpi_set_highbit (xi, 100); gcry_assert ( mpi_get_nbits (xi) == 101 ); - + return xi; -} +} @@ -389,19 +400,19 @@ generate_x931 (RSA_secret_key *sk, unsigned int nbits, unsigned long e_value, *swapped = 0; if (e_value == 1) /* Alias for a secure value. */ - e_value = 65537; + e_value = 65537; /* Point 1 of section 4.1: k = 1024 + 256s with S >= 0 */ if (nbits < 1024 || (nbits % 256)) return GPG_ERR_INV_VALUE; - + /* Point 2: 2 <= bitlength(e) < 2^{k-2} Note that we do not need to check the upper bound because we use an unsigned long for E and thus there is no way for E to reach that limit. */ if (e_value < 3) return GPG_ERR_INV_VALUE; - + /* Our implementaion requires E to be odd. */ if (!(e_value & 1)) return GPG_ERR_INV_VALUE; @@ -425,15 +436,15 @@ generate_x931 (RSA_secret_key *sk, unsigned int nbits, unsigned long e_value, /* Not given: Generate them. */ xp = gen_x931_parm_xp (nbits/2); /* Make sure that |xp - xq| > 2^{nbits - 100} holds. */ - tmpval = gcry_mpi_snew (nbits/2); + tmpval = mpi_snew (nbits/2); do { - gcry_mpi_release (xq); + _gcry_mpi_release (xq); xq = gen_x931_parm_xp (nbits/2); mpi_sub (tmpval, xp, xq); } while (mpi_get_nbits (tmpval) <= (nbits/2 - 100)); - gcry_mpi_release (tmpval); + _gcry_mpi_release (tmpval); xp1 = gen_x931_parm_xi (); xp2 = gen_x931_parm_xi (); @@ -444,26 +455,35 @@ generate_x931 (RSA_secret_key *sk, unsigned int nbits, unsigned long e_value, else { /* Parameters to derive the key are given. */ + /* Note that we explicitly need to setup the values of tbl + because some compilers (e.g. OpenWatcom, IRIX) don't allow + to initialize a structure with automatic variables. */ struct { const char *name; gcry_mpi_t *value; } tbl[] = { - { "Xp1", &xp1 }, - { "Xp2", &xp2 }, - { "Xp", &xp }, - { "Xq1", &xq1 }, - { "Xq2", &xq2 }, - { "Xq", &xq }, - { NULL, NULL } + { "Xp1" }, + { "Xp2" }, + { "Xp" }, + { "Xq1" }, + { "Xq2" }, + { "Xq" }, + { NULL } }; int idx; gcry_sexp_t oneparm; - + + tbl[0].value = &xp1; + tbl[1].value = &xp2; + tbl[2].value = &xp; + tbl[3].value = &xq1; + tbl[4].value = &xq2; + tbl[5].value = &xq; + for (idx=0; tbl[idx].name; idx++) { - oneparm = gcry_sexp_find_token (deriveparms, tbl[idx].name, 0); + oneparm = sexp_find_token (deriveparms, tbl[idx].name, 0); if (oneparm) { - *tbl[idx].value = gcry_sexp_nth_mpi (oneparm, 1, - GCRYMPI_FMT_USG); - gcry_sexp_release (oneparm); + *tbl[idx].value = sexp_nth_mpi (oneparm, 1, GCRYMPI_FMT_USG); + sexp_release (oneparm); } } for (idx=0; tbl[idx].name; idx++) @@ -473,27 +493,27 @@ generate_x931 (RSA_secret_key *sk, unsigned int nbits, unsigned long e_value, { /* At least one parameter is missing. */ for (idx=0; tbl[idx].name; idx++) - gcry_mpi_release (*tbl[idx].value); + _gcry_mpi_release (*tbl[idx].value); return GPG_ERR_MISSING_VALUE; } } - - e = mpi_alloc_set_ui (e_value); + + e = mpi_alloc_set_ui (e_value); /* Find two prime numbers. */ p = _gcry_derive_x931_prime (xp, xp1, xp2, e, NULL, NULL); q = _gcry_derive_x931_prime (xq, xq1, xq2, e, NULL, NULL); - gcry_mpi_release (xp); xp = NULL; - gcry_mpi_release (xp1); xp1 = NULL; - gcry_mpi_release (xp2); xp2 = NULL; - gcry_mpi_release (xq); xq = NULL; - gcry_mpi_release (xq1); xq1 = NULL; - gcry_mpi_release (xq2); xq2 = NULL; + _gcry_mpi_release (xp); xp = NULL; + _gcry_mpi_release (xp1); xp1 = NULL; + _gcry_mpi_release (xp2); xp2 = NULL; + _gcry_mpi_release (xq); xq = NULL; + _gcry_mpi_release (xq1); xq1 = NULL; + _gcry_mpi_release (xq2); xq2 = NULL; if (!p || !q) { - gcry_mpi_release (p); - gcry_mpi_release (q); - gcry_mpi_release (e); + _gcry_mpi_release (p); + _gcry_mpi_release (q); + _gcry_mpi_release (e); return GPG_ERR_NO_PRIME; } } @@ -506,26 +526,26 @@ generate_x931 (RSA_secret_key *sk, unsigned int nbits, unsigned long e_value, mpi_swap (p, q); *swapped = 1; } - n = gcry_mpi_new (nbits); + n = mpi_new (nbits); mpi_mul (n, p, q); /* Compute the Euler totient: phi = (p-1)(q-1) */ - pm1 = gcry_mpi_snew (nbits/2); - qm1 = gcry_mpi_snew (nbits/2); - phi = gcry_mpi_snew (nbits); + pm1 = mpi_snew (nbits/2); + qm1 = mpi_snew (nbits/2); + phi = mpi_snew (nbits); mpi_sub_ui (pm1, p, 1); mpi_sub_ui (qm1, q, 1); mpi_mul (phi, pm1, qm1); - g = gcry_mpi_snew (nbits); - gcry_assert (gcry_mpi_gcd (g, e, phi)); + g = mpi_snew (nbits); + gcry_assert (mpi_gcd (g, e, phi)); /* Compute: f = lcm(p-1,q-1) = phi / gcd(p-1,q-1) */ - gcry_mpi_gcd (g, pm1, qm1); + mpi_gcd (g, pm1, qm1); f = pm1; pm1 = NULL; - gcry_mpi_release (qm1); qm1 = NULL; + _gcry_mpi_release (qm1); qm1 = NULL; mpi_fdiv_q (f, phi, g); - gcry_mpi_release (phi); phi = NULL; + _gcry_mpi_release (phi); phi = NULL; d = g; g = NULL; /* Compute the secret key: d = e^{-1} mod lcm(p-1,q-1) */ mpi_invm (d, e, f); @@ -557,12 +577,12 @@ generate_x931 (RSA_secret_key *sk, unsigned int nbits, unsigned long e_value, /* Now we can test our keys. */ if (test_keys (sk, nbits - 64)) { - gcry_mpi_release (sk->n); sk->n = NULL; - gcry_mpi_release (sk->e); sk->e = NULL; - gcry_mpi_release (sk->p); sk->p = NULL; - gcry_mpi_release (sk->q); sk->q = NULL; - gcry_mpi_release (sk->d); sk->d = NULL; - gcry_mpi_release (sk->u); sk->u = NULL; + _gcry_mpi_release (sk->n); sk->n = NULL; + _gcry_mpi_release (sk->e); sk->e = NULL; + _gcry_mpi_release (sk->p); sk->p = NULL; + _gcry_mpi_release (sk->q); sk->q = NULL; + _gcry_mpi_release (sk->d); sk->d = NULL; + _gcry_mpi_release (sk->u); sk->u = NULL; fips_signal_error ("self-test after key generation failed"); return GPG_ERR_SELFTEST_FAILED; } @@ -572,7 +592,7 @@ generate_x931 (RSA_secret_key *sk, unsigned int nbits, unsigned long e_value, /**************** - * Test wether the secret key is valid. + * Test whether the secret key is valid. * Returns: true if this is a valid key. */ static int @@ -580,7 +600,7 @@ check_secret_key( RSA_secret_key *sk ) { int rc; gcry_mpi_t temp = mpi_alloc( mpi_get_nlimbs(sk->p)*2 ); - + mpi_mul(temp, sk->p, sk->q ); rc = mpi_cmp( temp, sk->n ); mpi_free(temp); @@ -652,7 +672,7 @@ stronger_key_check ( RSA_secret_key *skey ) { log_info ( "RSA Oops: d is wrong - fixed\n"); mpi_set (skey->d, t); - _gcry_log_mpidump (" fixed d", skey->d); + log_printmpi (" fixed d", skey->d); } /* check for correctness of u */ @@ -661,7 +681,7 @@ stronger_key_check ( RSA_secret_key *skey ) { log_info ( "RSA Oops: u is wrong - fixed\n"); mpi_set (skey->u, t); - _gcry_log_mpidump (" fixed u", skey->u); + log_printmpi (" fixed u", skey->u); } log_info ( "RSA secret key check finished\n"); @@ -682,16 +702,19 @@ stronger_key_check ( RSA_secret_key *skey ) * * Or faster: * - * m1 = c ^ (d mod (p-1)) mod p - * m2 = c ^ (d mod (q-1)) mod q - * h = u * (m2 - m1) mod q + * m1 = c ^ (d mod (p-1)) mod p + * m2 = c ^ (d mod (q-1)) mod q + * h = u * (m2 - m1) mod q * m = m1 + h * p * * Where m is OUTPUT, c is INPUT and d,n,p,q,u are elements of SKEY. */ static void -secret(gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey ) +secret (gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey ) { + /* Remove superfluous leading zeroes from INPUT. */ + mpi_normalize (input); + if (!skey->p || !skey->q || !skey->u) { mpi_powm (output, input, skey->d, skey->n); @@ -701,10 +724,10 @@ secret(gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey ) gcry_mpi_t m1 = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 ); gcry_mpi_t m2 = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 ); gcry_mpi_t h = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 ); - + /* m1 = c ^ (d mod (p-1)) mod p */ mpi_sub_ui( h, skey->p, 1 ); - mpi_fdiv_r( h, skey->d, h ); + mpi_fdiv_r( h, skey->d, h ); mpi_powm( m1, input, h, skey->p ); /* m2 = c ^ (d mod (q-1)) mod q */ mpi_sub_ui( h, skey->q, 1 ); @@ -712,13 +735,13 @@ secret(gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey ) mpi_powm( m2, input, h, skey->q ); /* h = u * ( m2 - m1 ) mod q */ mpi_sub( h, m2, m1 ); - if ( mpi_is_neg( h ) ) + if ( mpi_has_sign ( h ) ) mpi_add ( h, h, skey->q ); - mpi_mulm( h, skey->u, h, skey->q ); + mpi_mulm( h, skey->u, h, skey->q ); /* m = m2 + h * p */ mpi_mul ( h, h, skey->p ); mpi_add ( output, m1, h ); - + mpi_free ( h ); mpi_free ( m1 ); mpi_free ( m2 ); @@ -727,319 +750,540 @@ secret(gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey ) -/* Perform RSA blinding. */ -static gcry_mpi_t -rsa_blind (gcry_mpi_t x, gcry_mpi_t r, gcry_mpi_t e, gcry_mpi_t n) -{ - /* A helper. */ - gcry_mpi_t a; - - /* Result. */ - gcry_mpi_t y; - - a = gcry_mpi_snew (gcry_mpi_get_nbits (n)); - y = gcry_mpi_snew (gcry_mpi_get_nbits (n)); - - /* Now we calculate: y = (x * r^e) mod n, where r is the random - number, e is the public exponent, x is the non-blinded data and n - is the RSA modulus. */ - gcry_mpi_powm (a, r, e, n); - gcry_mpi_mulm (y, a, x, n); - - gcry_mpi_release (a); - - return y; -} - -/* Undo RSA blinding. */ -static gcry_mpi_t -rsa_unblind (gcry_mpi_t x, gcry_mpi_t ri, gcry_mpi_t n) -{ - gcry_mpi_t y; - - y = gcry_mpi_snew (gcry_mpi_get_nbits (n)); - - /* Here we calculate: y = (x * r^-1) mod n, where x is the blinded - decrypted data, ri is the modular multiplicative inverse of r and - n is the RSA modulus. */ - - gcry_mpi_mulm (y, ri, x, n); - - return y; -} - /********************************************* ************** interface ****************** *********************************************/ static gcry_err_code_t -rsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue, - const gcry_sexp_t genparms, - gcry_mpi_t *skey, gcry_mpi_t **retfactors, - gcry_sexp_t *r_extrainfo) +rsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey) { - RSA_secret_key sk; gpg_err_code_t ec; + unsigned int nbits; + unsigned long evalue; + RSA_secret_key sk; gcry_sexp_t deriveparms; - int transient_key = 0; - int use_x931 = 0; + int flags = 0; gcry_sexp_t l1; + gcry_sexp_t swap_info = NULL; + + memset (&sk, 0, sizeof sk); + + ec = _gcry_pk_util_get_nbits (genparms, &nbits); + if (ec) + return ec; + + ec = _gcry_pk_util_get_rsa_use_e (genparms, &evalue); + if (ec) + return ec; - (void)algo; - - *retfactors = NULL; /* We don't return them. */ + /* Parse the optional flags list. */ + l1 = sexp_find_token (genparms, "flags", 0); + if (l1) + { + ec = _gcry_pk_util_parse_flaglist (l1, &flags, NULL); + sexp_release (l1); + if (ec) + return ec; + } deriveparms = (genparms? - gcry_sexp_find_token (genparms, "derive-parms", 0) : NULL); + sexp_find_token (genparms, "derive-parms", 0) : NULL); if (!deriveparms) { /* Parse the optional "use-x931" flag. */ - l1 = gcry_sexp_find_token (genparms, "use-x931", 0); + l1 = sexp_find_token (genparms, "use-x931", 0); if (l1) { - use_x931 = 1; - gcry_sexp_release (l1); + flags |= PUBKEY_FLAG_USE_X931; + sexp_release (l1); } } - if (deriveparms || use_x931 || fips_mode ()) + if (deriveparms || (flags & PUBKEY_FLAG_USE_X931) || fips_mode ()) { int swapped; ec = generate_x931 (&sk, nbits, evalue, deriveparms, &swapped); - gcry_sexp_release (deriveparms); - if (!ec && r_extrainfo && swapped) - { - ec = gcry_sexp_new (r_extrainfo, - "(misc-key-info(p-q-swapped))", 0, 1); - if (ec) - { - gcry_mpi_release (sk.n); sk.n = NULL; - gcry_mpi_release (sk.e); sk.e = NULL; - gcry_mpi_release (sk.p); sk.p = NULL; - gcry_mpi_release (sk.q); sk.q = NULL; - gcry_mpi_release (sk.d); sk.d = NULL; - gcry_mpi_release (sk.u); sk.u = NULL; - } - } + sexp_release (deriveparms); + if (!ec && swapped) + ec = sexp_new (&swap_info, "(misc-key-info(p-q-swapped))", 0, 1); } else { /* Parse the optional "transient-key" flag. */ - l1 = gcry_sexp_find_token (genparms, "transient-key", 0); - if (l1) + if (!(flags & PUBKEY_FLAG_TRANSIENT_KEY)) { - transient_key = 1; - gcry_sexp_release (l1); + l1 = sexp_find_token (genparms, "transient-key", 0); + if (l1) + { + flags |= PUBKEY_FLAG_TRANSIENT_KEY; + sexp_release (l1); + } } /* Generate. */ - ec = generate_std (&sk, nbits, evalue, transient_key); + ec = generate_std (&sk, nbits, evalue, + !!(flags & PUBKEY_FLAG_TRANSIENT_KEY)); } if (!ec) { - skey[0] = sk.n; - skey[1] = sk.e; - skey[2] = sk.d; - skey[3] = sk.p; - skey[4] = sk.q; - skey[5] = sk.u; + ec = sexp_build (r_skey, NULL, + "(key-data" + " (public-key" + " (rsa(n%m)(e%m)))" + " (private-key" + " (rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))" + " %S)", + sk.n, sk.e, + sk.n, sk.e, sk.d, sk.p, sk.q, sk.u, + swap_info); } - - return ec; -} + mpi_free (sk.n); + mpi_free (sk.e); + mpi_free (sk.p); + mpi_free (sk.q); + mpi_free (sk.d); + mpi_free (sk.u); + sexp_release (swap_info); -static gcry_err_code_t -rsa_generate (int algo, unsigned int nbits, unsigned long evalue, - gcry_mpi_t *skey, gcry_mpi_t **retfactors) -{ - return rsa_generate_ext (algo, nbits, evalue, NULL, skey, retfactors, NULL); + return ec; } static gcry_err_code_t -rsa_check_secret_key (int algo, gcry_mpi_t *skey) +rsa_check_secret_key (gcry_sexp_t keyparms) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - RSA_secret_key sk; - - (void)algo; + gcry_err_code_t rc; + RSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL, NULL}; - sk.n = skey[0]; - sk.e = skey[1]; - sk.d = skey[2]; - sk.p = skey[3]; - sk.q = skey[4]; - sk.u = skey[5]; + /* To check the key we need the optional parameters. */ + rc = sexp_extract_param (keyparms, NULL, "nedpqu", + &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u, + NULL); + if (rc) + goto leave; - if (!sk.p || !sk.q || !sk.u) - err = GPG_ERR_NO_OBJ; /* To check the key we need the optional - parameters. */ - else if (!check_secret_key (&sk)) - err = GPG_ERR_PUBKEY_ALGO; + if (!check_secret_key (&sk)) + rc = GPG_ERR_BAD_SECKEY; - return err; + leave: + _gcry_mpi_release (sk.n); + _gcry_mpi_release (sk.e); + _gcry_mpi_release (sk.d); + _gcry_mpi_release (sk.p); + _gcry_mpi_release (sk.q); + _gcry_mpi_release (sk.u); + if (DBG_CIPHER) + log_debug ("rsa_testkey => %s\n", gpg_strerror (rc)); + return rc; } static gcry_err_code_t -rsa_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, - gcry_mpi_t *pkey, int flags) +rsa_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms) { - RSA_public_key pk; + gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_mpi_t data = NULL; + RSA_public_key pk = {NULL, NULL}; + gcry_mpi_t ciph = NULL; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT, + rsa_get_nbits (keyparms)); + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_mpidump ("rsa_encrypt data", data); + if (mpi_is_opaque (data)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + } + + /* Extract the key. */ + rc = sexp_extract_param (keyparms, NULL, "ne", &pk.n, &pk.e, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_mpidump ("rsa_encrypt n", pk.n); + log_mpidump ("rsa_encrypt e", pk.e); + } + + /* Do RSA computation and build result. */ + ciph = mpi_new (0); + public (ciph, data, &pk); + if (DBG_CIPHER) + log_mpidump ("rsa_encrypt res", ciph); + if ((ctx.flags & PUBKEY_FLAG_FIXEDLEN)) + { + /* We need to make sure to return the correct length to avoid + problems with missing leading zeroes. */ + unsigned char *em; + size_t emlen = (mpi_get_nbits (pk.n)+7)/8; - (void)algo; - (void)flags; - - pk.n = pkey[0]; - pk.e = pkey[1]; - resarr[0] = mpi_alloc (mpi_get_nlimbs (pk.n)); - public (resarr[0], data, &pk); - - return GPG_ERR_NO_ERROR; + rc = _gcry_mpi_to_octet_string (&em, NULL, ciph, emlen); + if (!rc) + { + rc = sexp_build (r_ciph, NULL, "(enc-val(rsa(a%b)))", (int)emlen, em); + xfree (em); + } + } + else + rc = sexp_build (r_ciph, NULL, "(enc-val(rsa(a%m)))", ciph); + + leave: + _gcry_mpi_release (ciph); + _gcry_mpi_release (pk.n); + _gcry_mpi_release (pk.e); + _gcry_mpi_release (data); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("rsa_encrypt => %s\n", gpg_strerror (rc)); + return rc; } static gcry_err_code_t -rsa_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data, - gcry_mpi_t *skey, int flags) +rsa_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) + { - RSA_secret_key sk; - gcry_mpi_t r = MPI_NULL; /* Random number needed for blinding. */ - gcry_mpi_t ri = MPI_NULL; /* Modular multiplicative inverse of - r. */ - gcry_mpi_t x = MPI_NULL; /* Data to decrypt. */ - gcry_mpi_t y; /* Result. */ + gpg_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_sexp_t l1 = NULL; + gcry_mpi_t data = NULL; + RSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL, NULL}; + gcry_mpi_t plain = NULL; + gcry_mpi_t r = NULL; /* Random number needed for blinding. */ + gcry_mpi_t ri = NULL; /* Modular multiplicative inverse of r. */ + gcry_mpi_t bldata = NULL;/* Blinded data to decrypt. */ + unsigned char *unpad = NULL; + size_t unpadlen = 0; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, + rsa_get_nbits (keyparms)); + + /* Extract the data. */ + rc = _gcry_pk_util_preparse_encval (s_data, rsa_names, &l1, &ctx); + if (rc) + goto leave; + rc = sexp_extract_param (l1, NULL, "a", &data, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + log_printmpi ("rsa_decrypt data", data); + if (mpi_is_opaque (data)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + } - (void)algo; + /* Extract the key. */ + rc = sexp_extract_param (keyparms, NULL, "nedp?q?u?", + &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u, + NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_printmpi ("rsa_decrypt n", sk.n); + log_printmpi ("rsa_decrypt e", sk.e); + if (!fips_mode ()) + { + log_printmpi ("rsa_decrypt d", sk.d); + log_printmpi ("rsa_decrypt p", sk.p); + log_printmpi ("rsa_decrypt q", sk.q); + log_printmpi ("rsa_decrypt u", sk.u); + } + } - /* Extract private key. */ - sk.n = skey[0]; - sk.e = skey[1]; - sk.d = skey[2]; - sk.p = skey[3]; /* Optional. */ - sk.q = skey[4]; /* Optional. */ - sk.u = skey[5]; /* Optional. */ + /* Better make sure that there are no superfluous leading zeroes in + the input and it has not been "padded" using multiples of N. + This mitigates side-channel attacks (CVE-2013-4576). */ + mpi_normalize (data); + mpi_fdiv_r (data, data, sk.n); - y = gcry_mpi_snew (gcry_mpi_get_nbits (sk.n)); + /* Allocate MPI for the plaintext. */ + plain = mpi_snew (ctx.nbits); /* We use blinding by default to mitigate timing attacks which can be practically mounted over the network as shown by Brumley and - Boney in 2003. */ - if (! (flags & PUBKEY_FLAG_NO_BLINDING)) + Boney in 2003. */ + if (!(ctx.flags & PUBKEY_FLAG_NO_BLINDING)) { - /* Initialize blinding. */ - /* First, we need a random number r between 0 and n - 1, which is relatively prime to n (i.e. it is neither p nor q). The random number needs to be only unpredictable, thus we employ the gcry_create_nonce function by using GCRY_WEAK_RANDOM with gcry_mpi_randomize. */ - r = gcry_mpi_snew (gcry_mpi_get_nbits (sk.n)); - ri = gcry_mpi_snew (gcry_mpi_get_nbits (sk.n)); - - gcry_mpi_randomize (r, gcry_mpi_get_nbits (sk.n), GCRY_WEAK_RANDOM); - gcry_mpi_mod (r, r, sk.n); - - /* Calculate inverse of r. It practically impossible that the - follwing test fails, thus we do not add code to release - allocated resources. */ - if (!gcry_mpi_invm (ri, r, sk.n)) - return GPG_ERR_INTERNAL; - } + r = mpi_snew (ctx.nbits); + ri = mpi_snew (ctx.nbits); + bldata = mpi_snew (ctx.nbits); - if (! (flags & PUBKEY_FLAG_NO_BLINDING)) - x = rsa_blind (data[0], r, sk.e, sk.n); - else - x = data[0]; + do + { + _gcry_mpi_randomize (r, ctx.nbits, GCRY_WEAK_RANDOM); + mpi_mod (r, r, sk.n); + } + while (!mpi_invm (ri, r, sk.n)); - /* Do the encryption. */ - secret (y, x, &sk); + /* Do blinding. We calculate: y = (x * r^e) mod n, where r is + the random number, e is the public exponent, x is the + non-blinded data and n is the RSA modulus. */ + mpi_powm (bldata, r, sk.e, sk.n); + mpi_mulm (bldata, bldata, data, sk.n); - if (! (flags & PUBKEY_FLAG_NO_BLINDING)) - { - /* Undo blinding. */ - gcry_mpi_t a = gcry_mpi_copy (y); - - gcry_mpi_release (y); - y = rsa_unblind (a, ri, sk.n); + /* Perform decryption. */ + secret (plain, bldata, &sk); + _gcry_mpi_release (bldata); bldata = NULL; - gcry_mpi_release (a); + /* Undo blinding. Here we calculate: y = (x * r^-1) mod n, + where x is the blinded decrypted data, ri is the modular + multiplicative inverse of r and n is the RSA modulus. */ + mpi_mulm (plain, plain, ri, sk.n); + + _gcry_mpi_release (r); r = NULL; + _gcry_mpi_release (ri); ri = NULL; } + else + secret (plain, data, &sk); - if (! (flags & PUBKEY_FLAG_NO_BLINDING)) + if (DBG_CIPHER) + log_printmpi ("rsa_decrypt res", plain); + + /* Reverse the encoding and build the s-expression. */ + switch (ctx.encoding) { - /* Deallocate resources needed for blinding. */ - gcry_mpi_release (x); - gcry_mpi_release (r); - gcry_mpi_release (ri); + case PUBKEY_ENC_PKCS1: + rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, ctx.nbits, plain); + mpi_free (plain); + plain = NULL; + if (!rc) + rc = sexp_build (r_plain, NULL, "(value %b)", (int)unpadlen, unpad); + break; + + case PUBKEY_ENC_OAEP: + rc = _gcry_rsa_oaep_decode (&unpad, &unpadlen, + ctx.nbits, ctx.hash_algo, + plain, ctx.label, ctx.labellen); + mpi_free (plain); + plain = NULL; + if (!rc) + rc = sexp_build (r_plain, NULL, "(value %b)", (int)unpadlen, unpad); + break; + + default: + /* Raw format. For backward compatibility we need to assume a + signed mpi by using the sexp format string "%m". */ + rc = sexp_build (r_plain, NULL, + (ctx.flags & PUBKEY_FLAG_LEGACYRESULT) + ? "%m":"(value %m)", plain); + break; } - /* Copy out result. */ - *result = y; - - return GPG_ERR_NO_ERROR; + leave: + xfree (unpad); + _gcry_mpi_release (plain); + _gcry_mpi_release (sk.n); + _gcry_mpi_release (sk.e); + _gcry_mpi_release (sk.d); + _gcry_mpi_release (sk.p); + _gcry_mpi_release (sk.q); + _gcry_mpi_release (sk.u); + _gcry_mpi_release (data); + _gcry_mpi_release (r); + _gcry_mpi_release (ri); + _gcry_mpi_release (bldata); + sexp_release (l1); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("rsa_decrypt => %s\n", gpg_strerror (rc)); + return rc; } static gcry_err_code_t -rsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey) +rsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) { - RSA_secret_key sk; + gpg_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_mpi_t data = NULL; + RSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL, NULL}; + gcry_mpi_t sig = NULL; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN, + rsa_get_nbits (keyparms)); + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_printmpi ("rsa_sign data", data); + if (mpi_is_opaque (data)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + } + + /* Extract the key. */ + rc = sexp_extract_param (keyparms, NULL, "nedp?q?u?", + &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u, + NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + { + log_printmpi ("rsa_sign n", sk.n); + log_printmpi ("rsa_sign e", sk.e); + if (!fips_mode ()) + { + log_printmpi ("rsa_sign d", sk.d); + log_printmpi ("rsa_sign p", sk.p); + log_printmpi ("rsa_sign q", sk.q); + log_printmpi ("rsa_sign u", sk.u); + } + } + + /* Do RSA computation and build the result. */ + sig = mpi_new (0); + secret (sig, data, &sk); + if (DBG_CIPHER) + log_printmpi ("rsa_sign res", sig); + if ((ctx.flags & PUBKEY_FLAG_FIXEDLEN)) + { + /* We need to make sure to return the correct length to avoid + problems with missing leading zeroes. */ + unsigned char *em; + size_t emlen = (mpi_get_nbits (sk.n)+7)/8; - (void)algo; - - sk.n = skey[0]; - sk.e = skey[1]; - sk.d = skey[2]; - sk.p = skey[3]; - sk.q = skey[4]; - sk.u = skey[5]; - resarr[0] = mpi_alloc( mpi_get_nlimbs (sk.n)); - secret (resarr[0], data, &sk); - - return GPG_ERR_NO_ERROR; + rc = _gcry_mpi_to_octet_string (&em, NULL, sig, emlen); + if (!rc) + { + rc = sexp_build (r_sig, NULL, "(sig-val(rsa(s%b)))", (int)emlen, em); + xfree (em); + } + } + else + rc = sexp_build (r_sig, NULL, "(sig-val(rsa(s%M)))", sig); + + + leave: + _gcry_mpi_release (sig); + _gcry_mpi_release (sk.n); + _gcry_mpi_release (sk.e); + _gcry_mpi_release (sk.d); + _gcry_mpi_release (sk.p); + _gcry_mpi_release (sk.q); + _gcry_mpi_release (sk.u); + _gcry_mpi_release (data); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("rsa_sign => %s\n", gpg_strerror (rc)); + return rc; } static gcry_err_code_t -rsa_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey, - int (*cmp) (void *opaque, gcry_mpi_t tmp), - void *opaquev) +rsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms) { - RSA_public_key pk; - gcry_mpi_t result; gcry_err_code_t rc; + struct pk_encoding_ctx ctx; + gcry_sexp_t l1 = NULL; + gcry_mpi_t sig = NULL; + gcry_mpi_t data = NULL; + RSA_public_key pk = { NULL, NULL }; + gcry_mpi_t result = NULL; + + _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY, + rsa_get_nbits (keyparms)); + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); + if (rc) + goto leave; + if (DBG_CIPHER) + log_printmpi ("rsa_verify data", data); + if (mpi_is_opaque (data)) + { + rc = GPG_ERR_INV_DATA; + goto leave; + } - (void)algo; - (void)cmp; - (void)opaquev; + /* Extract the signature value. */ + rc = _gcry_pk_util_preparse_sigval (s_sig, rsa_names, &l1, NULL); + if (rc) + goto leave; + rc = sexp_extract_param (l1, NULL, "s", &sig, NULL); + if (rc) + goto leave; + if (DBG_CIPHER) + log_printmpi ("rsa_verify sig", sig); - pk.n = pkey[0]; - pk.e = pkey[1]; - result = gcry_mpi_new ( 160 ); - public( result, data[0], &pk ); -#ifdef IS_DEVELOPMENT_VERSION + /* Extract the key. */ + rc = sexp_extract_param (keyparms, NULL, "ne", &pk.n, &pk.e, NULL); + if (rc) + goto leave; if (DBG_CIPHER) { - log_mpidump ("rsa verify result:", result ); - log_mpidump (" hash:", hash ); + log_printmpi ("rsa_verify n", pk.n); + log_printmpi ("rsa_verify e", pk.e); } -#endif /*IS_DEVELOPMENT_VERSION*/ - /*rc = (*cmp)( opaquev, result );*/ - rc = mpi_cmp (result, hash) ? GPG_ERR_BAD_SIGNATURE : GPG_ERR_NO_ERROR; - gcry_mpi_release (result); - + + /* Do RSA computation and compare. */ + result = mpi_new (0); + public (result, sig, &pk); + if (DBG_CIPHER) + log_printmpi ("rsa_verify cmp", result); + if (ctx.verify_cmp) + rc = ctx.verify_cmp (&ctx, result); + else + rc = mpi_cmp (result, data) ? GPG_ERR_BAD_SIGNATURE : 0; + + leave: + _gcry_mpi_release (result); + _gcry_mpi_release (pk.n); + _gcry_mpi_release (pk.e); + _gcry_mpi_release (data); + _gcry_mpi_release (sig); + sexp_release (l1); + _gcry_pk_util_free_encoding_ctx (&ctx); + if (DBG_CIPHER) + log_debug ("rsa_verify => %s\n", rc?gpg_strerror (rc):"Good"); return rc; } + +/* Return the number of bits for the key described by PARMS. On error + * 0 is returned. The format of PARMS starts with the algorithm name; + * for example: + * + * (rsa + * (n <mpi>) + * (e <mpi>)) + * + * More parameters may be given but we only need N here. + */ static unsigned int -rsa_get_nbits (int algo, gcry_mpi_t *pkey) +rsa_get_nbits (gcry_sexp_t parms) { - (void)algo; + gcry_sexp_t l1; + gcry_mpi_t n; + unsigned int nbits; + + l1 = sexp_find_token (parms, "n", 1); + if (!l1) + return 0; /* Parameter N not found. */ - return mpi_get_nbits (pkey[0]); + n = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + sexp_release (l1); + nbits = n? mpi_get_nbits (n) : 0; + _gcry_mpi_release (n); + return nbits; } @@ -1051,9 +1295,9 @@ rsa_get_nbits (int algo, gcry_mpi_t *pkey) (rsa (n #00B...#) (e #010001#)) - + PKCS-15 says that for RSA only the modulus should be hashed - - however, it is not clear wether this is meant to use the raw bytes + however, it is not clear whether this is meant to use the raw bytes (assuming this is an unsigned integer) or whether the DER required 0 should be prefixed. We hash the raw bytes. */ static gpg_err_code_t @@ -1063,19 +1307,19 @@ compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam) const char *data; size_t datalen; - l1 = gcry_sexp_find_token (keyparam, "n", 1); + l1 = sexp_find_token (keyparam, "n", 1); if (!l1) return GPG_ERR_NO_OBJ; - data = gcry_sexp_nth_data (l1, 1, &datalen); + data = sexp_nth_data (l1, 1, &datalen); if (!data) { - gcry_sexp_release (l1); + sexp_release (l1); return GPG_ERR_NO_OBJ; } - gcry_md_write (md, data, datalen); - gcry_sexp_release (l1); + _gcry_md_write (md, data, datalen); + sexp_release (l1); return 0; } @@ -1083,17 +1327,17 @@ compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam) -/* +/* Self-test section. */ static const char * selftest_sign_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) { - static const char sample_data[] = + static const char sample_data[] = "(data (flags pkcs1)" " (hash sha1 #11223344556677889900aabbccddeeff10203040#))"; - static const char sample_data_bad[] = + static const char sample_data_bad[] = "(data (flags pkcs1)" " (hash sha1 #11223344556677889900aabbccddeeff80203040#))"; @@ -1103,30 +1347,29 @@ selftest_sign_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) gcry_sexp_t data_bad = NULL; gcry_sexp_t sig = NULL; - err = gcry_sexp_sscan (&data, NULL, - sample_data, strlen (sample_data)); + err = sexp_sscan (&data, NULL, sample_data, strlen (sample_data)); if (!err) - err = gcry_sexp_sscan (&data_bad, NULL, - sample_data_bad, strlen (sample_data_bad)); + err = sexp_sscan (&data_bad, NULL, + sample_data_bad, strlen (sample_data_bad)); if (err) { errtxt = "converting data failed"; goto leave; } - err = gcry_pk_sign (&sig, data, skey); + err = _gcry_pk_sign (&sig, data, skey); if (err) { errtxt = "signing failed"; goto leave; } - err = gcry_pk_verify (sig, data, pkey); + err = _gcry_pk_verify (sig, data, pkey); if (err) { errtxt = "verify failed"; goto leave; } - err = gcry_pk_verify (sig, data_bad, pkey); + err = _gcry_pk_verify (sig, data_bad, pkey); if (gcry_err_code (err) != GPG_ERR_BAD_SIGNATURE) { errtxt = "bad signature not detected"; @@ -1135,9 +1378,9 @@ selftest_sign_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) leave: - gcry_sexp_release (sig); - gcry_sexp_release (data_bad); - gcry_sexp_release (data); + sexp_release (sig); + sexp_release (data_bad); + sexp_release (data); return errtxt; } @@ -1157,19 +1400,19 @@ extract_a_from_sexp (gcry_sexp_t encr_data) gcry_sexp_t l1, l2, l3; gcry_mpi_t a_value; - l1 = gcry_sexp_find_token (encr_data, "enc-val", 0); + l1 = sexp_find_token (encr_data, "enc-val", 0); if (!l1) return NULL; - l2 = gcry_sexp_find_token (l1, "rsa", 0); - gcry_sexp_release (l1); + l2 = sexp_find_token (l1, "rsa", 0); + sexp_release (l1); if (!l2) return NULL; - l3 = gcry_sexp_find_token (l2, "a", 0); - gcry_sexp_release (l2); + l3 = sexp_find_token (l2, "a", 0); + sexp_release (l2); if (!l3) return NULL; - a_value = gcry_sexp_nth_mpi (l3, 1, 0); - gcry_sexp_release (l3); + a_value = sexp_nth_mpi (l3, 1, 0); + sexp_release (l3); return a_value; } @@ -1190,12 +1433,11 @@ selftest_encr_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) gcry_sexp_t tmplist = NULL; /* Create plaintext. The plaintext is actually a big integer number. */ - plaintext = gcry_mpi_new (nbits); - gcry_mpi_randomize (plaintext, nbits, GCRY_WEAK_RANDOM); - + plaintext = mpi_new (nbits); + _gcry_mpi_randomize (plaintext, nbits, GCRY_WEAK_RANDOM); + /* Put the plaintext into an S-expression. */ - err = gcry_sexp_build (&plain, NULL, - "(data (flags raw) (value %m))", plaintext); + err = sexp_build (&plain, NULL, "(data (flags raw) (value %m))", plaintext); if (err) { errtxt = "converting data failed"; @@ -1203,7 +1445,7 @@ selftest_encr_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) } /* Encrypt. */ - err = gcry_pk_encrypt (&encr, plain, pkey); + err = _gcry_pk_encrypt (&encr, plain, pkey); if (err) { errtxt = "encrypt failed"; @@ -1211,7 +1453,7 @@ selftest_encr_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) } /* Extraxt the ciphertext from the returned S-expression. */ - /*gcry_sexp_dump (encr);*/ + /*sexp_dump (encr);*/ ciphertext = extract_a_from_sexp (encr); if (!ciphertext) { @@ -1220,16 +1462,16 @@ selftest_encr_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) } /* Check that the ciphertext does no match the plaintext. */ - /* _gcry_log_mpidump ("plaintext", plaintext); */ - /* _gcry_log_mpidump ("ciphertxt", ciphertext); */ - if (!gcry_mpi_cmp (plaintext, ciphertext)) + /* _gcry_log_printmpi ("plaintext", plaintext); */ + /* _gcry_log_printmpi ("ciphertxt", ciphertext); */ + if (!mpi_cmp (plaintext, ciphertext)) { errtxt = "ciphertext matches plaintext"; goto leave; } /* Decrypt. */ - err = gcry_pk_decrypt (&decr, encr, skey); + err = _gcry_pk_decrypt (&decr, encr, skey); if (err) { errtxt = "decrypt failed"; @@ -1242,32 +1484,32 @@ selftest_encr_1024 (gcry_sexp_t pkey, gcry_sexp_t skey) gcry_pk_encrypt directly to gcry_pk_decrypt, such a flag value won't be there as of today. To be prepared for future changes we take care of it anyway. */ - tmplist = gcry_sexp_find_token (decr, "value", 0); + tmplist = sexp_find_token (decr, "value", 0); if (tmplist) - decr_plaintext = gcry_sexp_nth_mpi (tmplist, 1, GCRYMPI_FMT_USG); + decr_plaintext = sexp_nth_mpi (tmplist, 1, GCRYMPI_FMT_USG); else - decr_plaintext = gcry_sexp_nth_mpi (decr, 0, GCRYMPI_FMT_USG); + decr_plaintext = sexp_nth_mpi (decr, 0, GCRYMPI_FMT_USG); if (!decr_plaintext) { errtxt = "decrypt returned no plaintext"; goto leave; } - + /* Check that the decrypted plaintext matches the original plaintext. */ - if (gcry_mpi_cmp (plaintext, decr_plaintext)) + if (mpi_cmp (plaintext, decr_plaintext)) { errtxt = "mismatch"; goto leave; } leave: - gcry_sexp_release (tmplist); - gcry_mpi_release (decr_plaintext); - gcry_sexp_release (decr); - gcry_mpi_release (ciphertext); - gcry_sexp_release (encr); - gcry_sexp_release (plain); - gcry_mpi_release (plaintext); + sexp_release (tmplist); + _gcry_mpi_release (decr_plaintext); + sexp_release (decr); + _gcry_mpi_release (ciphertext); + sexp_release (encr); + sexp_release (plain); + _gcry_mpi_release (plaintext); return errtxt; } @@ -1280,25 +1522,24 @@ selftests_rsa (selftest_report_func_t report) gcry_error_t err; gcry_sexp_t skey = NULL; gcry_sexp_t pkey = NULL; - + /* Convert the S-expressions into the internal representation. */ what = "convert"; - err = gcry_sexp_sscan (&skey, NULL, - sample_secret_key, strlen (sample_secret_key)); + err = sexp_sscan (&skey, NULL, sample_secret_key, strlen (sample_secret_key)); if (!err) - err = gcry_sexp_sscan (&pkey, NULL, - sample_public_key, strlen (sample_public_key)); + err = sexp_sscan (&pkey, NULL, + sample_public_key, strlen (sample_public_key)); if (err) { - errtxt = gcry_strerror (err); + errtxt = _gcry_strerror (err); goto failed; } what = "key consistency"; - err = gcry_pk_testkey (skey); + err = _gcry_pk_testkey (skey); if (err) { - errtxt = gcry_strerror (err); + errtxt = _gcry_strerror (err); goto failed; } @@ -1312,13 +1553,13 @@ selftests_rsa (selftest_report_func_t report) if (errtxt) goto failed; - gcry_sexp_release (pkey); - gcry_sexp_release (skey); + sexp_release (pkey); + sexp_release (skey); return 0; /* Succeeded. */ failed: - gcry_sexp_release (pkey); - gcry_sexp_release (skey); + sexp_release (pkey); + sexp_release (skey); if (report) report ("pubkey", GCRY_PK_RSA, what, errtxt); return GPG_ERR_SELFTEST_FAILED; @@ -1341,7 +1582,7 @@ run_selftests (int algo, int extended, selftest_report_func_t report) default: ec = GPG_ERR_PUBKEY_ALGO; break; - + } return ec; } @@ -1349,19 +1590,12 @@ run_selftests (int algo, int extended, selftest_report_func_t report) -static const char *rsa_names[] = - { - "rsa", - "openpgp-rsa", - "oid.1.2.840.113549.1.1.1", - NULL, - }; - gcry_pk_spec_t _gcry_pubkey_spec_rsa = { + GCRY_PK_RSA, { 0, 1 }, + (GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR), "RSA", rsa_names, "ne", "nedpqu", "a", "s", "n", - GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR, rsa_generate, rsa_check_secret_key, rsa_encrypt, @@ -1369,11 +1603,6 @@ gcry_pk_spec_t _gcry_pubkey_spec_rsa = rsa_sign, rsa_verify, rsa_get_nbits, - }; -pk_extra_spec_t _gcry_pubkey_extraspec_rsa = - { run_selftests, - rsa_generate_ext, compute_keygrip }; - diff --git a/plugins/MirOTR/Libgcrypt/cipher/salsa20.c b/plugins/MirOTR/Libgcrypt/cipher/salsa20.c new file mode 100644 index 0000000000..d75fe5151d --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/salsa20.c @@ -0,0 +1,577 @@ +/* salsa20.c - Bernstein's Salsa20 cipher + * Copyright (C) 2012 Simon Josefsson, Niels Möller + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * For a description of the algorithm, see: + * http://cr.yp.to/snuffle/spec.pdf + * http://cr.yp.to/snuffle/design.pdf + */ + +/* The code is based on the code in Nettle + (git commit id 9d2d8ddaee35b91a4e1a32ae77cba04bea3480e7) + which in turn is based on + salsa20-ref.c version 20051118 + D. J. Bernstein + Public domain. +*/ + + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "types.h" +#include "g10lib.h" +#include "cipher.h" +#include "bufhelp.h" + + +/* USE_AMD64 indicates whether to compile with AMD64 code. */ +#undef USE_AMD64 +#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) +# define USE_AMD64 1 +#endif + +/* USE_ARM_NEON_ASM indicates whether to enable ARM NEON assembly code. */ +#undef USE_ARM_NEON_ASM +#ifdef ENABLE_NEON_SUPPORT +# if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) \ + && defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) \ + && defined(HAVE_GCC_INLINE_ASM_NEON) +# define USE_ARM_NEON_ASM 1 +# endif +#endif /*ENABLE_NEON_SUPPORT*/ + + +#define SALSA20_MIN_KEY_SIZE 16 /* Bytes. */ +#define SALSA20_MAX_KEY_SIZE 32 /* Bytes. */ +#define SALSA20_BLOCK_SIZE 64 /* Bytes. */ +#define SALSA20_IV_SIZE 8 /* Bytes. */ +#define SALSA20_INPUT_LENGTH 16 /* Bytes. */ + +/* Number of rounds. The standard uses 20 rounds. In any case the + number of rounds must be even. */ +#define SALSA20_ROUNDS 20 +#define SALSA20R12_ROUNDS 12 + + +struct SALSA20_context_s; + +typedef unsigned int (*salsa20_core_t) (u32 *dst, struct SALSA20_context_s *ctx, + unsigned int rounds); +typedef void (* salsa20_keysetup_t)(struct SALSA20_context_s *ctx, + const byte *key, int keylen); +typedef void (* salsa20_ivsetup_t)(struct SALSA20_context_s *ctx, + const byte *iv); + +typedef struct SALSA20_context_s +{ + /* Indices 1-4 and 11-14 holds the key (two identical copies for the + shorter key size), indices 0, 5, 10, 15 are constant, indices 6, 7 + are the IV, and indices 8, 9 are the block counter: + + C K K K + K C I I + B B C K + K K K C + */ + u32 input[SALSA20_INPUT_LENGTH]; + u32 pad[SALSA20_INPUT_LENGTH]; + unsigned int unused; /* bytes in the pad. */ +#ifdef USE_ARM_NEON_ASM + int use_neon; +#endif + salsa20_keysetup_t keysetup; + salsa20_ivsetup_t ivsetup; + salsa20_core_t core; +} SALSA20_context_t; + + +/* The masking of the right shift is needed to allow n == 0 (using + just 32 - n and 64 - n results in undefined behaviour). Most uses + of these macros use a constant and non-zero rotation count. */ +#define ROTL32(n,x) (((x)<<(n)) | ((x)>>((-(n)&31)))) + + +#define LE_SWAP32(v) le_bswap32(v) + +#define LE_READ_UINT32(p) buf_get_le32(p) + + +static void salsa20_setiv (void *context, const byte *iv, size_t ivlen); +static const char *selftest (void); + + +#ifdef USE_AMD64 +/* AMD64 assembly implementations of Salsa20. */ +void _gcry_salsa20_amd64_keysetup(u32 *ctxinput, const void *key, int keybits); +void _gcry_salsa20_amd64_ivsetup(u32 *ctxinput, const void *iv); +unsigned int +_gcry_salsa20_amd64_encrypt_blocks(u32 *ctxinput, const void *src, void *dst, + size_t len, int rounds); + +static void +salsa20_keysetup(SALSA20_context_t *ctx, const byte *key, int keylen) +{ + _gcry_salsa20_amd64_keysetup(ctx->input, key, keylen * 8); +} + +static void +salsa20_ivsetup(SALSA20_context_t *ctx, const byte *iv) +{ + _gcry_salsa20_amd64_ivsetup(ctx->input, iv); +} + +static unsigned int +salsa20_core (u32 *dst, SALSA20_context_t *ctx, unsigned int rounds) +{ + memset(dst, 0, SALSA20_BLOCK_SIZE); + return _gcry_salsa20_amd64_encrypt_blocks(ctx->input, dst, dst, 1, rounds); +} + +#else /* USE_AMD64 */ + + + +#if 0 +# define SALSA20_CORE_DEBUG(i) do { \ + unsigned debug_j; \ + for (debug_j = 0; debug_j < 16; debug_j++) \ + { \ + if (debug_j == 0) \ + fprintf(stderr, "%2d:", (i)); \ + else if (debug_j % 4 == 0) \ + fprintf(stderr, "\n "); \ + fprintf(stderr, " %8x", pad[debug_j]); \ + } \ + fprintf(stderr, "\n"); \ + } while (0) +#else +# define SALSA20_CORE_DEBUG(i) +#endif + +#define QROUND(x0, x1, x2, x3) \ + do { \ + x1 ^= ROTL32 ( 7, x0 + x3); \ + x2 ^= ROTL32 ( 9, x1 + x0); \ + x3 ^= ROTL32 (13, x2 + x1); \ + x0 ^= ROTL32 (18, x3 + x2); \ + } while(0) + +static unsigned int +salsa20_core (u32 *dst, SALSA20_context_t *ctx, unsigned rounds) +{ + u32 pad[SALSA20_INPUT_LENGTH], *src = ctx->input; + unsigned int i; + + memcpy (pad, src, sizeof(pad)); + for (i = 0; i < rounds; i += 2) + { + SALSA20_CORE_DEBUG (i); + QROUND (pad[0], pad[4], pad[8], pad[12]); + QROUND (pad[5], pad[9], pad[13], pad[1] ); + QROUND (pad[10], pad[14], pad[2], pad[6] ); + QROUND (pad[15], pad[3], pad[7], pad[11]); + + SALSA20_CORE_DEBUG (i+1); + QROUND (pad[0], pad[1], pad[2], pad[3] ); + QROUND (pad[5], pad[6], pad[7], pad[4] ); + QROUND (pad[10], pad[11], pad[8], pad[9] ); + QROUND (pad[15], pad[12], pad[13], pad[14]); + } + SALSA20_CORE_DEBUG (i); + + for (i = 0; i < SALSA20_INPUT_LENGTH; i++) + { + u32 t = pad[i] + src[i]; + dst[i] = LE_SWAP32 (t); + } + + /* Update counter. */ + if (!++src[8]) + src[9]++; + + /* burn_stack */ + return ( 3*sizeof (void*) \ + + 2*sizeof (void*) \ + + 64 \ + + sizeof (unsigned int) \ + + sizeof (u32) ); +} +#undef QROUND +#undef SALSA20_CORE_DEBUG + +static void +salsa20_keysetup(SALSA20_context_t *ctx, const byte *key, int keylen) +{ + /* These constants are the little endian encoding of the string + "expand 32-byte k". For the 128 bit variant, the "32" in that + string will be fixed up to "16". */ + ctx->input[0] = 0x61707865; /* "apxe" */ + ctx->input[5] = 0x3320646e; /* "3 dn" */ + ctx->input[10] = 0x79622d32; /* "yb-2" */ + ctx->input[15] = 0x6b206574; /* "k et" */ + + ctx->input[1] = LE_READ_UINT32(key + 0); + ctx->input[2] = LE_READ_UINT32(key + 4); + ctx->input[3] = LE_READ_UINT32(key + 8); + ctx->input[4] = LE_READ_UINT32(key + 12); + if (keylen == SALSA20_MAX_KEY_SIZE) /* 256 bits */ + { + ctx->input[11] = LE_READ_UINT32(key + 16); + ctx->input[12] = LE_READ_UINT32(key + 20); + ctx->input[13] = LE_READ_UINT32(key + 24); + ctx->input[14] = LE_READ_UINT32(key + 28); + } + else /* 128 bits */ + { + ctx->input[11] = ctx->input[1]; + ctx->input[12] = ctx->input[2]; + ctx->input[13] = ctx->input[3]; + ctx->input[14] = ctx->input[4]; + + ctx->input[5] -= 0x02000000; /* Change to "1 dn". */ + ctx->input[10] += 0x00000004; /* Change to "yb-6". */ + } +} + +static void salsa20_ivsetup(SALSA20_context_t *ctx, const byte *iv) +{ + ctx->input[6] = LE_READ_UINT32(iv + 0); + ctx->input[7] = LE_READ_UINT32(iv + 4); + /* Reset the block counter. */ + ctx->input[8] = 0; + ctx->input[9] = 0; +} + +#endif /*!USE_AMD64*/ + +#ifdef USE_ARM_NEON_ASM + +/* ARM NEON implementation of Salsa20. */ +unsigned int +_gcry_arm_neon_salsa20_encrypt(void *c, const void *m, unsigned int nblks, + void *k, unsigned int rounds); + +static unsigned int +salsa20_core_neon (u32 *dst, SALSA20_context_t *ctx, unsigned int rounds) +{ + return _gcry_arm_neon_salsa20_encrypt(dst, NULL, 1, ctx->input, rounds); +} + +static void salsa20_ivsetup_neon(SALSA20_context_t *ctx, const byte *iv) +{ + memcpy(ctx->input + 8, iv, 8); + /* Reset the block counter. */ + memset(ctx->input + 10, 0, 8); +} + +static void +salsa20_keysetup_neon(SALSA20_context_t *ctx, const byte *key, int klen) +{ + static const unsigned char sigma32[16] = "expand 32-byte k"; + static const unsigned char sigma16[16] = "expand 16-byte k"; + + if (klen == 16) + { + memcpy (ctx->input, key, 16); + memcpy (ctx->input + 4, key, 16); /* Duplicate 128-bit key. */ + memcpy (ctx->input + 12, sigma16, 16); + } + else + { + /* 32-byte key */ + memcpy (ctx->input, key, 32); + memcpy (ctx->input + 12, sigma32, 16); + } +} + +#endif /*USE_ARM_NEON_ASM*/ + + +static gcry_err_code_t +salsa20_do_setkey (SALSA20_context_t *ctx, + const byte *key, unsigned int keylen) +{ + static int initialized; + static const char *selftest_failed; + + if (!initialized ) + { + initialized = 1; + selftest_failed = selftest (); + if (selftest_failed) + log_error ("SALSA20 selftest failed (%s)\n", selftest_failed ); + } + if (selftest_failed) + return GPG_ERR_SELFTEST_FAILED; + + if (keylen != SALSA20_MIN_KEY_SIZE + && keylen != SALSA20_MAX_KEY_SIZE) + return GPG_ERR_INV_KEYLEN; + + /* Default ops. */ + ctx->keysetup = salsa20_keysetup; + ctx->ivsetup = salsa20_ivsetup; + ctx->core = salsa20_core; + +#ifdef USE_ARM_NEON_ASM + ctx->use_neon = (_gcry_get_hw_features () & HWF_ARM_NEON) != 0; + if (ctx->use_neon) + { + /* Use ARM NEON ops instead. */ + ctx->keysetup = salsa20_keysetup_neon; + ctx->ivsetup = salsa20_ivsetup_neon; + ctx->core = salsa20_core_neon; + } +#endif + + ctx->keysetup (ctx, key, keylen); + + /* We default to a zero nonce. */ + salsa20_setiv (ctx, NULL, 0); + + return 0; +} + + +static gcry_err_code_t +salsa20_setkey (void *context, const byte *key, unsigned int keylen) +{ + SALSA20_context_t *ctx = (SALSA20_context_t *)context; + gcry_err_code_t rc = salsa20_do_setkey (ctx, key, keylen); + _gcry_burn_stack (4 + sizeof (void *) + 4 * sizeof (void *)); + return rc; +} + + +static void +salsa20_setiv (void *context, const byte *iv, size_t ivlen) +{ + SALSA20_context_t *ctx = (SALSA20_context_t *)context; + byte tmp[SALSA20_IV_SIZE]; + + if (iv && ivlen != SALSA20_IV_SIZE) + log_info ("WARNING: salsa20_setiv: bad ivlen=%u\n", (u32)ivlen); + + if (!iv || ivlen != SALSA20_IV_SIZE) + memset (tmp, 0, sizeof(tmp)); + else + memcpy (tmp, iv, SALSA20_IV_SIZE); + + ctx->ivsetup (ctx, tmp); + + /* Reset the unused pad bytes counter. */ + ctx->unused = 0; + + wipememory (tmp, sizeof(tmp)); +} + + + +/* Note: This function requires LENGTH > 0. */ +static void +salsa20_do_encrypt_stream (SALSA20_context_t *ctx, + byte *outbuf, const byte *inbuf, + size_t length, unsigned rounds) +{ + unsigned int nburn, burn = 0; + + if (ctx->unused) + { + unsigned char *p = (void*)ctx->pad; + size_t n; + + gcry_assert (ctx->unused < SALSA20_BLOCK_SIZE); + + n = ctx->unused; + if (n > length) + n = length; + buf_xor (outbuf, inbuf, p + SALSA20_BLOCK_SIZE - ctx->unused, n); + length -= n; + outbuf += n; + inbuf += n; + ctx->unused -= n; + if (!length) + return; + gcry_assert (!ctx->unused); + } + +#ifdef USE_AMD64 + if (length >= SALSA20_BLOCK_SIZE) + { + size_t nblocks = length / SALSA20_BLOCK_SIZE; + burn = _gcry_salsa20_amd64_encrypt_blocks(ctx->input, inbuf, outbuf, + nblocks, rounds); + length -= SALSA20_BLOCK_SIZE * nblocks; + outbuf += SALSA20_BLOCK_SIZE * nblocks; + inbuf += SALSA20_BLOCK_SIZE * nblocks; + } +#endif + +#ifdef USE_ARM_NEON_ASM + if (ctx->use_neon && length >= SALSA20_BLOCK_SIZE) + { + unsigned int nblocks = length / SALSA20_BLOCK_SIZE; + _gcry_arm_neon_salsa20_encrypt (outbuf, inbuf, nblocks, ctx->input, + rounds); + length -= SALSA20_BLOCK_SIZE * nblocks; + outbuf += SALSA20_BLOCK_SIZE * nblocks; + inbuf += SALSA20_BLOCK_SIZE * nblocks; + } +#endif + + while (length > 0) + { + /* Create the next pad and bump the block counter. Note that it + is the user's duty to change to another nonce not later than + after 2^70 processed bytes. */ + nburn = ctx->core (ctx->pad, ctx, rounds); + burn = nburn > burn ? nburn : burn; + + if (length <= SALSA20_BLOCK_SIZE) + { + buf_xor (outbuf, inbuf, ctx->pad, length); + ctx->unused = SALSA20_BLOCK_SIZE - length; + break; + } + buf_xor (outbuf, inbuf, ctx->pad, SALSA20_BLOCK_SIZE); + length -= SALSA20_BLOCK_SIZE; + outbuf += SALSA20_BLOCK_SIZE; + inbuf += SALSA20_BLOCK_SIZE; + } + + _gcry_burn_stack (burn); +} + + +static void +salsa20_encrypt_stream (void *context, + byte *outbuf, const byte *inbuf, size_t length) +{ + SALSA20_context_t *ctx = (SALSA20_context_t *)context; + + if (length) + salsa20_do_encrypt_stream (ctx, outbuf, inbuf, length, SALSA20_ROUNDS); +} + + +static void +salsa20r12_encrypt_stream (void *context, + byte *outbuf, const byte *inbuf, size_t length) +{ + SALSA20_context_t *ctx = (SALSA20_context_t *)context; + + if (length) + salsa20_do_encrypt_stream (ctx, outbuf, inbuf, length, SALSA20R12_ROUNDS); +} + + +static const char* +selftest (void) +{ + SALSA20_context_t ctx; + byte scratch[8+1]; + byte buf[256+64+4]; + int i; + + static byte key_1[] = + { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const byte nonce_1[] = + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const byte plaintext_1[] = + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const byte ciphertext_1[] = + { 0xE3, 0xBE, 0x8F, 0xDD, 0x8B, 0xEC, 0xA2, 0xE3}; + + salsa20_setkey (&ctx, key_1, sizeof key_1); + salsa20_setiv (&ctx, nonce_1, sizeof nonce_1); + scratch[8] = 0; + salsa20_encrypt_stream (&ctx, scratch, plaintext_1, sizeof plaintext_1); + if (memcmp (scratch, ciphertext_1, sizeof ciphertext_1)) + return "Salsa20 encryption test 1 failed."; + if (scratch[8]) + return "Salsa20 wrote too much."; + salsa20_setkey( &ctx, key_1, sizeof(key_1)); + salsa20_setiv (&ctx, nonce_1, sizeof nonce_1); + salsa20_encrypt_stream (&ctx, scratch, scratch, sizeof plaintext_1); + if (memcmp (scratch, plaintext_1, sizeof plaintext_1)) + return "Salsa20 decryption test 1 failed."; + + for (i = 0; i < sizeof buf; i++) + buf[i] = i; + salsa20_setkey (&ctx, key_1, sizeof key_1); + salsa20_setiv (&ctx, nonce_1, sizeof nonce_1); + /*encrypt*/ + salsa20_encrypt_stream (&ctx, buf, buf, sizeof buf); + /*decrypt*/ + salsa20_setkey (&ctx, key_1, sizeof key_1); + salsa20_setiv (&ctx, nonce_1, sizeof nonce_1); + salsa20_encrypt_stream (&ctx, buf, buf, 1); + salsa20_encrypt_stream (&ctx, buf+1, buf+1, (sizeof buf)-1-1); + salsa20_encrypt_stream (&ctx, buf+(sizeof buf)-1, buf+(sizeof buf)-1, 1); + for (i = 0; i < sizeof buf; i++) + if (buf[i] != (byte)i) + return "Salsa20 encryption test 2 failed."; + + return NULL; +} + + +gcry_cipher_spec_t _gcry_cipher_spec_salsa20 = + { + GCRY_CIPHER_SALSA20, + {0, 0}, /* flags */ + "SALSA20", /* name */ + NULL, /* aliases */ + NULL, /* oids */ + 1, /* blocksize in bytes. */ + SALSA20_MAX_KEY_SIZE*8, /* standard key length in bits. */ + sizeof (SALSA20_context_t), + salsa20_setkey, + NULL, + NULL, + salsa20_encrypt_stream, + salsa20_encrypt_stream, + NULL, + NULL, + salsa20_setiv + }; + +gcry_cipher_spec_t _gcry_cipher_spec_salsa20r12 = + { + GCRY_CIPHER_SALSA20R12, + {0, 0}, /* flags */ + "SALSA20R12", /* name */ + NULL, /* aliases */ + NULL, /* oids */ + 1, /* blocksize in bytes. */ + SALSA20_MAX_KEY_SIZE*8, /* standard key length in bits. */ + sizeof (SALSA20_context_t), + salsa20_setkey, + NULL, + NULL, + salsa20r12_encrypt_stream, + salsa20r12_encrypt_stream, + NULL, + NULL, + salsa20_setiv + }; diff --git a/plugins/MirOTR/Libgcrypt/cipher/scrypt.c b/plugins/MirOTR/Libgcrypt/cipher/scrypt.c new file mode 100644 index 0000000000..404943d854 --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/scrypt.c @@ -0,0 +1,324 @@ +/* scrypt.c - Scrypt password-based key derivation function. + * Copyright (C) 2012 Simon Josefsson + * Copyright (C) 2013 Christian Grothoff + * Copyright (C) 2013 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* Adapted from the nettle, low-level cryptographics library for + * libgcrypt by Christian Grothoff; original license: + * + * Copyright (C) 2012 Simon Josefsson + * + * The nettle library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The nettle library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the nettle library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02111-1301, USA. + */ + +#include <config.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "g10lib.h" +#include "kdf-internal.h" +#include "bufhelp.h" + +/* We really need a 64 bit type for this code. */ +#ifdef HAVE_U64_TYPEDEF + +#define SALSA20_INPUT_LENGTH 16 + +#define ROTL32(n,x) (((x)<<(n)) | ((x)>>(32-(n)))) + + +/* Reads a 64-bit integer, in network, big-endian, byte order */ +#define READ_UINT64(p) buf_get_be64(p) + + +/* And the other, little-endian, byteorder */ +#define LE_READ_UINT64(p) buf_get_le64(p) + +#define LE_SWAP32(v) le_bswap32(v) + + +#define QROUND(x0, x1, x2, x3) do { \ + x1 ^= ROTL32(7, x0 + x3); \ + x2 ^= ROTL32(9, x1 + x0); \ + x3 ^= ROTL32(13, x2 + x1); \ + x0 ^= ROTL32(18, x3 + x2); \ + } while(0) + + +static void +_salsa20_core(u32 *dst, const u32 *src, unsigned rounds) +{ + u32 x[SALSA20_INPUT_LENGTH]; + unsigned i; + + assert ( (rounds & 1) == 0); + + for (i = 0; i < SALSA20_INPUT_LENGTH; i++) + x[i] = LE_SWAP32(src[i]); + + for (i = 0; i < rounds;i += 2) + { + QROUND(x[0], x[4], x[8], x[12]); + QROUND(x[5], x[9], x[13], x[1]); + QROUND(x[10], x[14], x[2], x[6]); + QROUND(x[15], x[3], x[7], x[11]); + + QROUND(x[0], x[1], x[2], x[3]); + QROUND(x[5], x[6], x[7], x[4]); + QROUND(x[10], x[11], x[8], x[9]); + QROUND(x[15], x[12], x[13], x[14]); + } + + for (i = 0; i < SALSA20_INPUT_LENGTH; i++) + { + u32 t = x[i] + LE_SWAP32(src[i]); + dst[i] = LE_SWAP32(t); + } +} + + +static void +_scryptBlockMix (u32 r, unsigned char *B, unsigned char *tmp2) +{ + u64 i; + unsigned char *X = tmp2; + unsigned char *Y = tmp2 + 64; + +#if 0 + if (r == 1) + { + for (i = 0; i < 2 * r; i++) + { + size_t j; + printf ("B[%d] = ", (int)i); + for (j = 0; j < 64; j++) + { + if (j && !(j % 16)) + printf ("\n "); + printf (" %02x", B[i * 64 + j]); + } + putchar ('\n'); + } + } +#endif + + /* X = B[2 * r - 1] */ + memcpy (X, &B[(2 * r - 1) * 64], 64); + + /* for i = 0 to 2 * r - 1 do */ + for (i = 0; i <= 2 * r - 1; i++) + { + /* T = X xor B[i] */ + buf_xor(X, X, &B[i * 64], 64); + + /* X = Salsa (T) */ + _salsa20_core ((u32*)X, (u32*)X, 8); + + /* Y[i] = X */ + memcpy (&Y[i * 64], X, 64); + } + + for (i = 0; i < r; i++) + { + memcpy (&B[i * 64], &Y[2 * i * 64], 64); + memcpy (&B[(r + i) * 64], &Y[(2 * i + 1) * 64], 64); + } + +#if 0 + if (r==1) + { + for (i = 0; i < 2 * r; i++) + { + size_t j; + printf ("B'[%d] =", (int)i); + for (j = 0; j < 64; j++) + { + if (j && !(j % 16)) + printf ("\n "); + printf (" %02x", B[i * 64 + j]); + } + putchar ('\n'); + } + } +#endif +} + +static void +_scryptROMix (u32 r, unsigned char *B, u64 N, + unsigned char *tmp1, unsigned char *tmp2) +{ + unsigned char *X = B, *T = B; + u64 i; + +#if 0 + if (r == 1) + { + printf ("B = "); + for (i = 0; i < 128 * r; i++) + { + if (i && !(i % 16)) + printf ("\n "); + printf (" %02x", B[i]); + } + putchar ('\n'); + } +#endif + + /* for i = 0 to N - 1 do */ + for (i = 0; i <= N - 1; i++) + { + /* V[i] = X */ + memcpy (&tmp1[i * 128 * r], X, 128 * r); + + /* X = ScryptBlockMix (X) */ + _scryptBlockMix (r, X, tmp2); + } + + /* for i = 0 to N - 1 do */ + for (i = 0; i <= N - 1; i++) + { + u64 j; + + /* j = Integerify (X) mod N */ + j = LE_READ_UINT64 (&X[128 * r - 64]) % N; + + /* T = X xor V[j] */ + buf_xor (T, T, &tmp1[j * 128 * r], 128 * r); + + /* X = scryptBlockMix (T) */ + _scryptBlockMix (r, T, tmp2); + } + +#if 0 + if (r == 1) + { + printf ("B' ="); + for (i = 0; i < 128 * r; i++) + { + if (i && !(i % 16)) + printf ("\n "); + printf (" %02x", B[i]); + } + putchar ('\n'); + } +#endif +} + +/** + */ +gcry_err_code_t +_gcry_kdf_scrypt (const unsigned char *passwd, size_t passwdlen, + int algo, int subalgo, + const unsigned char *salt, size_t saltlen, + unsigned long iterations, + size_t dkLen, unsigned char *DK) +{ + u64 N = subalgo; /* CPU/memory cost paramter. */ + u32 r; /* Block size. */ + u32 p = iterations; /* Parallelization parameter. */ + + gpg_err_code_t ec; + u32 i; + unsigned char *B = NULL; + unsigned char *tmp1 = NULL; + unsigned char *tmp2 = NULL; + size_t r128; + size_t nbytes; + + if (subalgo < 1 || !iterations) + return GPG_ERR_INV_VALUE; + + if (algo == GCRY_KDF_SCRYPT) + r = 8; + else if (algo == 41) /* Hack to allow the use of all test vectors. */ + r = 1; + else + return GPG_ERR_UNKNOWN_ALGORITHM; + + r128 = r * 128; + if (r128 / 128 != r) + return GPG_ERR_ENOMEM; + + nbytes = p * r128; + if (r128 && nbytes / r128 != p) + return GPG_ERR_ENOMEM; + + nbytes = N * r128; + if (r128 && nbytes / r128 != N) + return GPG_ERR_ENOMEM; + + nbytes = 64 + r128; + if (nbytes < r128) + return GPG_ERR_ENOMEM; + + B = xtrymalloc (p * r128); + if (!B) + { + ec = gpg_err_code_from_syserror (); + goto leave; + } + + tmp1 = xtrymalloc (N * r128); + if (!tmp1) + { + ec = gpg_err_code_from_syserror (); + goto leave; + } + + tmp2 = xtrymalloc (64 + r128); + if (!tmp2) + { + ec = gpg_err_code_from_syserror (); + goto leave; + } + + ec = _gcry_kdf_pkdf2 (passwd, passwdlen, GCRY_MD_SHA256, salt, saltlen, + 1 /* iterations */, p * r128, B); + + for (i = 0; !ec && i < p; i++) + _scryptROMix (r, &B[i * r128], N, tmp1, tmp2); + + for (i = 0; !ec && i < p; i++) + ec = _gcry_kdf_pkdf2 (passwd, passwdlen, GCRY_MD_SHA256, B, p * r128, + 1 /* iterations */, dkLen, DK); + + leave: + xfree (tmp2); + xfree (tmp1); + xfree (B); + + return ec; +} + + +#endif /* HAVE_U64_TYPEDEF */ diff --git a/plugins/MirOTR/Libgcrypt/cipher/seed.c b/plugins/MirOTR/Libgcrypt/cipher/seed.c index b0980d61ec..9f87c05589 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/seed.c +++ b/plugins/MirOTR/Libgcrypt/cipher/seed.c @@ -29,15 +29,12 @@ #include "types.h" /* for byte and u32 typedefs */ #include "g10lib.h" #include "cipher.h" +#include "bufhelp.h" #define NUMKC 16 -#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \ - ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) -#define PUTU32(ct, st) { (ct)[0] = (byte)((st) >> 24); \ - (ct)[1] = (byte)((st) >> 16); \ - (ct)[2] = (byte)((st) >> 8); \ - (ct)[3] = (byte)(st); } +#define GETU32(pt) buf_get_be32(pt) +#define PUTU32(ct, st) buf_put_be32(ct, st) union wordbuf { @@ -59,7 +56,7 @@ union wordbuf static const char *selftest(void); -typedef struct +typedef struct { u32 keyschedule[32]; } SEED_context; @@ -258,7 +255,7 @@ static const u32 KC[NUMKC] = { /* Perform the key setup. - */ + */ static gcry_err_code_t do_setkey (SEED_context *ctx, const byte *key, const unsigned keylen) { @@ -371,13 +368,13 @@ do_encrypt (const SEED_context *ctx, byte *outbuf, const byte *inbuf) PUTU32 (outbuf+12, x2); } -static void +static unsigned int seed_encrypt (void *context, byte *outbuf, const byte *inbuf) { SEED_context *ctx = context; do_encrypt (ctx, outbuf, inbuf); - _gcry_burn_stack (4*6); + return /*burn_stack*/ (4*6); } @@ -417,13 +414,13 @@ do_decrypt (SEED_context *ctx, byte *outbuf, const byte *inbuf) PUTU32 (outbuf+12, x2); } -static void +static unsigned int seed_decrypt (void *context, byte *outbuf, const byte *inbuf) { SEED_context *ctx = context; do_decrypt (ctx, outbuf, inbuf); - _gcry_burn_stack (4*6); + return /*burn_stack*/ (4*6); } @@ -432,7 +429,7 @@ static const char* selftest (void) { SEED_context ctx; - byte scratch[16]; + byte scratch[16]; /* The test vector is taken from the appendix section B.3 of RFC4269. */ @@ -473,6 +470,7 @@ static gcry_cipher_oid_spec_t seed_oids[] = gcry_cipher_spec_t _gcry_cipher_spec_seed = { + GCRY_CIPHER_SEED, {0, 0}, "SEED", NULL, seed_oids, 16, 128, sizeof (SEED_context), seed_setkey, seed_encrypt, seed_decrypt, }; diff --git a/plugins/MirOTR/Libgcrypt/cipher/serpent.c b/plugins/MirOTR/Libgcrypt/cipher/serpent.c index 6b7e655a98..0be49da477 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/serpent.c +++ b/plugins/MirOTR/Libgcrypt/cipher/serpent.c @@ -28,6 +28,33 @@ #include "g10lib.h" #include "cipher.h" #include "bithelp.h" +#include "bufhelp.h" +#include "cipher-selftest.h" + + +/* USE_SSE2 indicates whether to compile with AMD64 SSE2 code. */ +#undef USE_SSE2 +#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) +# define USE_SSE2 1 +#endif + +/* USE_AVX2 indicates whether to compile with AMD64 AVX2 code. */ +#undef USE_AVX2 +#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) +# if defined(ENABLE_AVX2_SUPPORT) +# define USE_AVX2 1 +# endif +#endif + +/* USE_NEON indicates whether to enable ARM NEON assembly code. */ +#undef USE_NEON +#ifdef ENABLE_NEON_SUPPORT +# if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) \ + && defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) \ + && defined(HAVE_GCC_INLINE_ASM_NEON) +# define USE_NEON 1 +# endif +#endif /*ENABLE_NEON_SUPPORT*/ /* Number of rounds per Serpent encrypt/decrypt operation. */ #define ROUNDS 32 @@ -49,415 +76,378 @@ typedef u32 serpent_subkeys_t[ROUNDS + 1][4]; typedef struct serpent_context { serpent_subkeys_t keys; /* Generated subkeys. */ + +#ifdef USE_AVX2 + int use_avx2; +#endif +#ifdef USE_NEON + int use_neon; +#endif } serpent_context_t; -/* A prototype. */ -static const char *serpent_test (void); - +#ifdef USE_SSE2 +/* Assembler implementations of Serpent using SSE2. Process 8 block in + parallel. + */ +extern void _gcry_serpent_sse2_ctr_enc(serpent_context_t *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *ctr); + +extern void _gcry_serpent_sse2_cbc_dec(serpent_context_t *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *iv); + +extern void _gcry_serpent_sse2_cfb_dec(serpent_context_t *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *iv); +#endif -#define byte_swap_32(x) \ - (0 \ - | (((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) \ - | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) +#ifdef USE_AVX2 +/* Assembler implementations of Serpent using SSE2. Process 16 block in + parallel. + */ +extern void _gcry_serpent_avx2_ctr_enc(serpent_context_t *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *ctr); + +extern void _gcry_serpent_avx2_cbc_dec(serpent_context_t *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *iv); + +extern void _gcry_serpent_avx2_cfb_dec(serpent_context_t *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *iv); +#endif -/* These are the S-Boxes of Serpent. They are copied from Serpents - reference implementation (the optimized one, contained in - `floppy2') and are therefore: +#ifdef USE_NEON +/* Assembler implementations of Serpent using ARM NEON. Process 8 block in + parallel. + */ +extern void _gcry_serpent_neon_ctr_enc(serpent_context_t *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *ctr); + +extern void _gcry_serpent_neon_cbc_dec(serpent_context_t *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *iv); + +extern void _gcry_serpent_neon_cfb_dec(serpent_context_t *ctx, + unsigned char *out, + const unsigned char *in, + unsigned char *iv); +#endif - Copyright (C) 1998 Ross Anderson, Eli Biham, Lars Knudsen. - To quote the Serpent homepage - (http://www.cl.cam.ac.uk/~rja14/serpent.html): +/* A prototype. */ +static const char *serpent_test (void); - "Serpent is now completely in the public domain, and we impose no - restrictions on its use. This was announced on the 21st August at - the First AES Candidate Conference. The optimised implementations - in the submission package are now under the GNU PUBLIC LICENSE - (GPL), although some comments in the code still say otherwise. You - are welcome to use Serpent for any application." */ -#define SBOX0(a, b, c, d, w, x, y, z) \ +/* + * These are the S-Boxes of Serpent from following research paper. + * + * D. A. Osvik, “Speeding up Serpent,” in Third AES Candidate Conference, + * (New York, New York, USA), p. 317–329, National Institute of Standards and + * Technology, 2000. + * + * Paper is also available at: http://www.ii.uib.no/~osvik/pub/aes3.pdf + * + */ + +#define SBOX0(r0, r1, r2, r3, w, x, y, z) \ { \ - u32 t02, t03, t05, t06, t07, t08, t09; \ - u32 t11, t12, t13, t14, t15, t17, t01; \ - t01 = b ^ c ; \ - t02 = a | d ; \ - t03 = a ^ b ; \ - z = t02 ^ t01; \ - t05 = c | z ; \ - t06 = a ^ d ; \ - t07 = b | c ; \ - t08 = d & t05; \ - t09 = t03 & t07; \ - y = t09 ^ t08; \ - t11 = t09 & y ; \ - t12 = c ^ d ; \ - t13 = t07 ^ t11; \ - t14 = b & t06; \ - t15 = t06 ^ t13; \ - w = ~ t15; \ - t17 = w ^ t14; \ - x = t12 ^ t17; \ + u32 r4; \ + \ + r3 ^= r0; r4 = r1; \ + r1 &= r3; r4 ^= r2; \ + r1 ^= r0; r0 |= r3; \ + r0 ^= r4; r4 ^= r3; \ + r3 ^= r2; r2 |= r1; \ + r2 ^= r4; r4 = ~r4; \ + r4 |= r1; r1 ^= r3; \ + r1 ^= r4; r3 |= r0; \ + r1 ^= r3; r4 ^= r3; \ + \ + w = r1; x = r4; y = r2; z = r0; \ } -#define SBOX0_INVERSE(a, b, c, d, w, x, y, z) \ +#define SBOX0_INVERSE(r0, r1, r2, r3, w, x, y, z) \ { \ - u32 t02, t03, t04, t05, t06, t08, t09, t10; \ - u32 t12, t13, t14, t15, t17, t18, t01; \ - t01 = c ^ d ; \ - t02 = a | b ; \ - t03 = b | c ; \ - t04 = c & t01; \ - t05 = t02 ^ t01; \ - t06 = a | t04; \ - y = ~ t05; \ - t08 = b ^ d ; \ - t09 = t03 & t08; \ - t10 = d | y ; \ - x = t09 ^ t06; \ - t12 = a | t05; \ - t13 = x ^ t12; \ - t14 = t03 ^ t10; \ - t15 = a ^ c ; \ - z = t14 ^ t13; \ - t17 = t05 & t13; \ - t18 = t14 | t17; \ - w = t15 ^ t18; \ + u32 r4; \ + \ + r2 = ~r2; r4 = r1; \ + r1 |= r0; r4 = ~r4; \ + r1 ^= r2; r2 |= r4; \ + r1 ^= r3; r0 ^= r4; \ + r2 ^= r0; r0 &= r3; \ + r4 ^= r0; r0 |= r1; \ + r0 ^= r2; r3 ^= r4; \ + r2 ^= r1; r3 ^= r0; \ + r3 ^= r1; \ + r2 &= r3; \ + r4 ^= r2; \ + \ + w = r0; x = r4; y = r1; z = r3; \ } -#define SBOX1(a, b, c, d, w, x, y, z) \ +#define SBOX1(r0, r1, r2, r3, w, x, y, z) \ { \ - u32 t02, t03, t04, t05, t06, t07, t08; \ - u32 t10, t11, t12, t13, t16, t17, t01; \ - t01 = a | d ; \ - t02 = c ^ d ; \ - t03 = ~ b ; \ - t04 = a ^ c ; \ - t05 = a | t03; \ - t06 = d & t04; \ - t07 = t01 & t02; \ - t08 = b | t06; \ - y = t02 ^ t05; \ - t10 = t07 ^ t08; \ - t11 = t01 ^ t10; \ - t12 = y ^ t11; \ - t13 = b & d ; \ - z = ~ t10; \ - x = t13 ^ t12; \ - t16 = t10 | x ; \ - t17 = t05 & t16; \ - w = c ^ t17; \ + u32 r4; \ + \ + r0 = ~r0; r2 = ~r2; \ + r4 = r0; r0 &= r1; \ + r2 ^= r0; r0 |= r3; \ + r3 ^= r2; r1 ^= r0; \ + r0 ^= r4; r4 |= r1; \ + r1 ^= r3; r2 |= r0; \ + r2 &= r4; r0 ^= r1; \ + r1 &= r2; \ + r1 ^= r0; r0 &= r2; \ + r0 ^= r4; \ + \ + w = r2; x = r0; y = r3; z = r1; \ } -#define SBOX1_INVERSE(a, b, c, d, w, x, y, z) \ +#define SBOX1_INVERSE(r0, r1, r2, r3, w, x, y, z) \ { \ - u32 t02, t03, t04, t05, t06, t07, t08; \ - u32 t09, t10, t11, t14, t15, t17, t01; \ - t01 = a ^ b ; \ - t02 = b | d ; \ - t03 = a & c ; \ - t04 = c ^ t02; \ - t05 = a | t04; \ - t06 = t01 & t05; \ - t07 = d | t03; \ - t08 = b ^ t06; \ - t09 = t07 ^ t06; \ - t10 = t04 | t03; \ - t11 = d & t08; \ - y = ~ t09; \ - x = t10 ^ t11; \ - t14 = a | y ; \ - t15 = t06 ^ x ; \ - z = t01 ^ t04; \ - t17 = c ^ t15; \ - w = t14 ^ t17; \ + u32 r4; \ + \ + r4 = r1; r1 ^= r3; \ + r3 &= r1; r4 ^= r2; \ + r3 ^= r0; r0 |= r1; \ + r2 ^= r3; r0 ^= r4; \ + r0 |= r2; r1 ^= r3; \ + r0 ^= r1; r1 |= r3; \ + r1 ^= r0; r4 = ~r4; \ + r4 ^= r1; r1 |= r0; \ + r1 ^= r0; \ + r1 |= r4; \ + r3 ^= r1; \ + \ + w = r4; x = r0; y = r3; z = r2; \ } -#define SBOX2(a, b, c, d, w, x, y, z) \ +#define SBOX2(r0, r1, r2, r3, w, x, y, z) \ { \ - u32 t02, t03, t05, t06, t07, t08; \ - u32 t09, t10, t12, t13, t14, t01; \ - t01 = a | c ; \ - t02 = a ^ b ; \ - t03 = d ^ t01; \ - w = t02 ^ t03; \ - t05 = c ^ w ; \ - t06 = b ^ t05; \ - t07 = b | t05; \ - t08 = t01 & t06; \ - t09 = t03 ^ t07; \ - t10 = t02 | t09; \ - x = t10 ^ t08; \ - t12 = a | d ; \ - t13 = t09 ^ x ; \ - t14 = b ^ t13; \ - z = ~ t09; \ - y = t12 ^ t14; \ + u32 r4; \ + \ + r4 = r0; r0 &= r2; \ + r0 ^= r3; r2 ^= r1; \ + r2 ^= r0; r3 |= r4; \ + r3 ^= r1; r4 ^= r2; \ + r1 = r3; r3 |= r4; \ + r3 ^= r0; r0 &= r1; \ + r4 ^= r0; r1 ^= r3; \ + r1 ^= r4; r4 = ~r4; \ + \ + w = r2; x = r3; y = r1; z = r4; \ } -#define SBOX2_INVERSE(a, b, c, d, w, x, y, z) \ +#define SBOX2_INVERSE(r0, r1, r2, r3, w, x, y, z) \ { \ - u32 t02, t03, t04, t06, t07, t08, t09; \ - u32 t10, t11, t12, t15, t16, t17, t01; \ - t01 = a ^ d ; \ - t02 = c ^ d ; \ - t03 = a & c ; \ - t04 = b | t02; \ - w = t01 ^ t04; \ - t06 = a | c ; \ - t07 = d | w ; \ - t08 = ~ d ; \ - t09 = b & t06; \ - t10 = t08 | t03; \ - t11 = b & t07; \ - t12 = t06 & t02; \ - z = t09 ^ t10; \ - x = t12 ^ t11; \ - t15 = c & z ; \ - t16 = w ^ x ; \ - t17 = t10 ^ t15; \ - y = t16 ^ t17; \ + u32 r4; \ + \ + r2 ^= r3; r3 ^= r0; \ + r4 = r3; r3 &= r2; \ + r3 ^= r1; r1 |= r2; \ + r1 ^= r4; r4 &= r3; \ + r2 ^= r3; r4 &= r0; \ + r4 ^= r2; r2 &= r1; \ + r2 |= r0; r3 = ~r3; \ + r2 ^= r3; r0 ^= r3; \ + r0 &= r1; r3 ^= r4; \ + r3 ^= r0; \ + \ + w = r1; x = r4; y = r2; z = r3; \ } -#define SBOX3(a, b, c, d, w, x, y, z) \ +#define SBOX3(r0, r1, r2, r3, w, x, y, z) \ { \ - u32 t02, t03, t04, t05, t06, t07, t08; \ - u32 t09, t10, t11, t13, t14, t15, t01; \ - t01 = a ^ c ; \ - t02 = a | d ; \ - t03 = a & d ; \ - t04 = t01 & t02; \ - t05 = b | t03; \ - t06 = a & b ; \ - t07 = d ^ t04; \ - t08 = c | t06; \ - t09 = b ^ t07; \ - t10 = d & t05; \ - t11 = t02 ^ t10; \ - z = t08 ^ t09; \ - t13 = d | z ; \ - t14 = a | t07; \ - t15 = b & t13; \ - y = t08 ^ t11; \ - w = t14 ^ t15; \ - x = t05 ^ t04; \ + u32 r4; \ + \ + r4 = r0; r0 |= r3; \ + r3 ^= r1; r1 &= r4; \ + r4 ^= r2; r2 ^= r3; \ + r3 &= r0; r4 |= r1; \ + r3 ^= r4; r0 ^= r1; \ + r4 &= r0; r1 ^= r3; \ + r4 ^= r2; r1 |= r0; \ + r1 ^= r2; r0 ^= r3; \ + r2 = r1; r1 |= r3; \ + r1 ^= r0; \ + \ + w = r1; x = r2; y = r3; z = r4; \ } -#define SBOX3_INVERSE(a, b, c, d, w, x, y, z) \ +#define SBOX3_INVERSE(r0, r1, r2, r3, w, x, y, z) \ { \ - u32 t02, t03, t04, t05, t06, t07, t09; \ - u32 t11, t12, t13, t14, t16, t01; \ - t01 = c | d ; \ - t02 = a | d ; \ - t03 = c ^ t02; \ - t04 = b ^ t02; \ - t05 = a ^ d ; \ - t06 = t04 & t03; \ - t07 = b & t01; \ - y = t05 ^ t06; \ - t09 = a ^ t03; \ - w = t07 ^ t03; \ - t11 = w | t05; \ - t12 = t09 & t11; \ - t13 = a & y ; \ - t14 = t01 ^ t05; \ - x = b ^ t12; \ - t16 = b | t13; \ - z = t14 ^ t16; \ + u32 r4; \ + \ + r4 = r2; r2 ^= r1; \ + r0 ^= r2; r4 &= r2; \ + r4 ^= r0; r0 &= r1; \ + r1 ^= r3; r3 |= r4; \ + r2 ^= r3; r0 ^= r3; \ + r1 ^= r4; r3 &= r2; \ + r3 ^= r1; r1 ^= r0; \ + r1 |= r2; r0 ^= r3; \ + r1 ^= r4; \ + r0 ^= r1; \ + \ + w = r2; x = r1; y = r3; z = r0; \ } -#define SBOX4(a, b, c, d, w, x, y, z) \ +#define SBOX4(r0, r1, r2, r3, w, x, y, z) \ { \ - u32 t02, t03, t04, t05, t06, t08, t09; \ - u32 t10, t11, t12, t13, t14, t15, t16, t01; \ - t01 = a | b ; \ - t02 = b | c ; \ - t03 = a ^ t02; \ - t04 = b ^ d ; \ - t05 = d | t03; \ - t06 = d & t01; \ - z = t03 ^ t06; \ - t08 = z & t04; \ - t09 = t04 & t05; \ - t10 = c ^ t06; \ - t11 = b & c ; \ - t12 = t04 ^ t08; \ - t13 = t11 | t03; \ - t14 = t10 ^ t09; \ - t15 = a & t05; \ - t16 = t11 | t12; \ - y = t13 ^ t08; \ - x = t15 ^ t16; \ - w = ~ t14; \ + u32 r4; \ + \ + r1 ^= r3; r3 = ~r3; \ + r2 ^= r3; r3 ^= r0; \ + r4 = r1; r1 &= r3; \ + r1 ^= r2; r4 ^= r3; \ + r0 ^= r4; r2 &= r4; \ + r2 ^= r0; r0 &= r1; \ + r3 ^= r0; r4 |= r1; \ + r4 ^= r0; r0 |= r3; \ + r0 ^= r2; r2 &= r3; \ + r0 = ~r0; r4 ^= r2; \ + \ + w = r1; x = r4; y = r0; z = r3; \ } -#define SBOX4_INVERSE(a, b, c, d, w, x, y, z) \ +#define SBOX4_INVERSE(r0, r1, r2, r3, w, x, y, z) \ { \ - u32 t02, t03, t04, t05, t06, t07, t09; \ - u32 t10, t11, t12, t13, t15, t01; \ - t01 = b | d ; \ - t02 = c | d ; \ - t03 = a & t01; \ - t04 = b ^ t02; \ - t05 = c ^ d ; \ - t06 = ~ t03; \ - t07 = a & t04; \ - x = t05 ^ t07; \ - t09 = x | t06; \ - t10 = a ^ t07; \ - t11 = t01 ^ t09; \ - t12 = d ^ t04; \ - t13 = c | t10; \ - z = t03 ^ t12; \ - t15 = a ^ t04; \ - y = t11 ^ t13; \ - w = t15 ^ t09; \ + u32 r4; \ + \ + r4 = r2; r2 &= r3; \ + r2 ^= r1; r1 |= r3; \ + r1 &= r0; r4 ^= r2; \ + r4 ^= r1; r1 &= r2; \ + r0 = ~r0; r3 ^= r4; \ + r1 ^= r3; r3 &= r0; \ + r3 ^= r2; r0 ^= r1; \ + r2 &= r0; r3 ^= r0; \ + r2 ^= r4; \ + r2 |= r3; r3 ^= r0; \ + r2 ^= r1; \ + \ + w = r0; x = r3; y = r2; z = r4; \ } -#define SBOX5(a, b, c, d, w, x, y, z) \ +#define SBOX5(r0, r1, r2, r3, w, x, y, z) \ { \ - u32 t02, t03, t04, t05, t07, t08, t09; \ - u32 t10, t11, t12, t13, t14, t01; \ - t01 = b ^ d ; \ - t02 = b | d ; \ - t03 = a & t01; \ - t04 = c ^ t02; \ - t05 = t03 ^ t04; \ - w = ~ t05; \ - t07 = a ^ t01; \ - t08 = d | w ; \ - t09 = b | t05; \ - t10 = d ^ t08; \ - t11 = b | t07; \ - t12 = t03 | w ; \ - t13 = t07 | t10; \ - t14 = t01 ^ t11; \ - y = t09 ^ t13; \ - x = t07 ^ t08; \ - z = t12 ^ t14; \ + u32 r4; \ + \ + r0 ^= r1; r1 ^= r3; \ + r3 = ~r3; r4 = r1; \ + r1 &= r0; r2 ^= r3; \ + r1 ^= r2; r2 |= r4; \ + r4 ^= r3; r3 &= r1; \ + r3 ^= r0; r4 ^= r1; \ + r4 ^= r2; r2 ^= r0; \ + r0 &= r3; r2 = ~r2; \ + r0 ^= r4; r4 |= r3; \ + r2 ^= r4; \ + \ + w = r1; x = r3; y = r0; z = r2; \ } -#define SBOX5_INVERSE(a, b, c, d, w, x, y, z) \ +#define SBOX5_INVERSE(r0, r1, r2, r3, w, x, y, z) \ { \ - u32 t02, t03, t04, t05, t07, t08, t09; \ - u32 t10, t12, t13, t15, t16, t01; \ - t01 = a & d ; \ - t02 = c ^ t01; \ - t03 = a ^ d ; \ - t04 = b & t02; \ - t05 = a & c ; \ - w = t03 ^ t04; \ - t07 = a & w ; \ - t08 = t01 ^ w ; \ - t09 = b | t05; \ - t10 = ~ b ; \ - x = t08 ^ t09; \ - t12 = t10 | t07; \ - t13 = w | x ; \ - z = t02 ^ t12; \ - t15 = t02 ^ t13; \ - t16 = b ^ d ; \ - y = t16 ^ t15; \ + u32 r4; \ + \ + r1 = ~r1; r4 = r3; \ + r2 ^= r1; r3 |= r0; \ + r3 ^= r2; r2 |= r1; \ + r2 &= r0; r4 ^= r3; \ + r2 ^= r4; r4 |= r0; \ + r4 ^= r1; r1 &= r2; \ + r1 ^= r3; r4 ^= r2; \ + r3 &= r4; r4 ^= r1; \ + r3 ^= r4; r4 = ~r4; \ + r3 ^= r0; \ + \ + w = r1; x = r4; y = r3; z = r2; \ } -#define SBOX6(a, b, c, d, w, x, y, z) \ +#define SBOX6(r0, r1, r2, r3, w, x, y, z) \ { \ - u32 t02, t03, t04, t05, t07, t08, t09, t10; \ - u32 t11, t12, t13, t15, t17, t18, t01; \ - t01 = a & d ; \ - t02 = b ^ c ; \ - t03 = a ^ d ; \ - t04 = t01 ^ t02; \ - t05 = b | c ; \ - x = ~ t04; \ - t07 = t03 & t05; \ - t08 = b & x ; \ - t09 = a | c ; \ - t10 = t07 ^ t08; \ - t11 = b | d ; \ - t12 = c ^ t11; \ - t13 = t09 ^ t10; \ - y = ~ t13; \ - t15 = x & t03; \ - z = t12 ^ t07; \ - t17 = a ^ b ; \ - t18 = y ^ t15; \ - w = t17 ^ t18; \ + u32 r4; \ + \ + r2 = ~r2; r4 = r3; \ + r3 &= r0; r0 ^= r4; \ + r3 ^= r2; r2 |= r4; \ + r1 ^= r3; r2 ^= r0; \ + r0 |= r1; r2 ^= r1; \ + r4 ^= r0; r0 |= r3; \ + r0 ^= r2; r4 ^= r3; \ + r4 ^= r0; r3 = ~r3; \ + r2 &= r4; \ + r2 ^= r3; \ + \ + w = r0; x = r1; y = r4; z = r2; \ } -#define SBOX6_INVERSE(a, b, c, d, w, x, y, z) \ +#define SBOX6_INVERSE(r0, r1, r2, r3, w, x, y, z) \ { \ - u32 t02, t03, t04, t05, t06, t07, t08, t09; \ - u32 t12, t13, t14, t15, t16, t17, t01; \ - t01 = a ^ c ; \ - t02 = ~ c ; \ - t03 = b & t01; \ - t04 = b | t02; \ - t05 = d | t03; \ - t06 = b ^ d ; \ - t07 = a & t04; \ - t08 = a | t02; \ - t09 = t07 ^ t05; \ - x = t06 ^ t08; \ - w = ~ t09; \ - t12 = b & w ; \ - t13 = t01 & t05; \ - t14 = t01 ^ t12; \ - t15 = t07 ^ t13; \ - t16 = d | t02; \ - t17 = a ^ x ; \ - z = t17 ^ t15; \ - y = t16 ^ t14; \ + u32 r4; \ + \ + r0 ^= r2; r4 = r2; \ + r2 &= r0; r4 ^= r3; \ + r2 = ~r2; r3 ^= r1; \ + r2 ^= r3; r4 |= r0; \ + r0 ^= r2; r3 ^= r4; \ + r4 ^= r1; r1 &= r3; \ + r1 ^= r0; r0 ^= r3; \ + r0 |= r2; r3 ^= r1; \ + r4 ^= r0; \ + \ + w = r1; x = r2; y = r4; z = r3; \ } -#define SBOX7(a, b, c, d, w, x, y, z) \ +#define SBOX7(r0, r1, r2, r3, w, x, y, z) \ { \ - u32 t02, t03, t04, t05, t06, t08, t09, t10; \ - u32 t11, t13, t14, t15, t16, t17, t01; \ - t01 = a & c ; \ - t02 = ~ d ; \ - t03 = a & t02; \ - t04 = b | t01; \ - t05 = a & b ; \ - t06 = c ^ t04; \ - z = t03 ^ t06; \ - t08 = c | z ; \ - t09 = d | t05; \ - t10 = a ^ t08; \ - t11 = t04 & z ; \ - x = t09 ^ t10; \ - t13 = b ^ x ; \ - t14 = t01 ^ x ; \ - t15 = c ^ t05; \ - t16 = t11 | t13; \ - t17 = t02 | t14; \ - w = t15 ^ t17; \ - y = a ^ t16; \ + u32 r4; \ + \ + r4 = r1; r1 |= r2; \ + r1 ^= r3; r4 ^= r2; \ + r2 ^= r1; r3 |= r4; \ + r3 &= r0; r4 ^= r2; \ + r3 ^= r1; r1 |= r4; \ + r1 ^= r0; r0 |= r4; \ + r0 ^= r2; r1 ^= r4; \ + r2 ^= r1; r1 &= r0; \ + r1 ^= r4; r2 = ~r2; \ + r2 |= r0; \ + r4 ^= r2; \ + \ + w = r4; x = r3; y = r1; z = r0; \ } -#define SBOX7_INVERSE(a, b, c, d, w, x, y, z) \ +#define SBOX7_INVERSE(r0, r1, r2, r3, w, x, y, z) \ { \ - u32 t02, t03, t04, t06, t07, t08, t09; \ - u32 t10, t11, t13, t14, t15, t16, t01; \ - t01 = a & b ; \ - t02 = a | b ; \ - t03 = c | t01; \ - t04 = d & t02; \ - z = t03 ^ t04; \ - t06 = b ^ t04; \ - t07 = d ^ z ; \ - t08 = ~ t07; \ - t09 = t06 | t08; \ - t10 = b ^ d ; \ - t11 = a | d ; \ - x = a ^ t09; \ - t13 = c ^ t06; \ - t14 = c & t11; \ - t15 = d | x ; \ - t16 = t01 | t10; \ - w = t13 ^ t15; \ - y = t14 ^ t16; \ + u32 r4; \ + \ + r4 = r2; r2 ^= r0; \ + r0 &= r3; r4 |= r3; \ + r2 = ~r2; r3 ^= r1; \ + r1 |= r0; r0 ^= r2; \ + r2 &= r4; r3 &= r4; \ + r1 ^= r2; r2 ^= r0; \ + r0 |= r2; r4 ^= r1; \ + r0 ^= r3; r3 ^= r4; \ + r4 |= r0; r3 ^= r2; \ + r4 ^= r2; \ + \ + w = r3; x = r0; y = r1; z = r4; \ } /* XOR BLOCK1 into BLOCK0. */ @@ -478,23 +468,17 @@ static const char *serpent_test (void); block_dst[3] = block_src[3]; \ } -/* Apply SBOX number WHICH to to the block found in ARRAY0 at index - INDEX, writing the output to the block found in ARRAY1 at index - INDEX. */ -#define SBOX(which, array0, array1, index) \ - SBOX##which (array0[index + 0], array0[index + 1], \ - array0[index + 2], array0[index + 3], \ - array1[index + 0], array1[index + 1], \ - array1[index + 2], array1[index + 3]); - -/* Apply inverse SBOX number WHICH to to the block found in ARRAY0 at - index INDEX, writing the output to the block found in ARRAY1 at - index INDEX. */ -#define SBOX_INVERSE(which, array0, array1, index) \ - SBOX##which##_INVERSE (array0[index + 0], array0[index + 1], \ - array0[index + 2], array0[index + 3], \ - array1[index + 0], array1[index + 1], \ - array1[index + 2], array1[index + 3]); +/* Apply SBOX number WHICH to to the block found in ARRAY0, writing + the output to the block found in ARRAY1. */ +#define SBOX(which, array0, array1) \ + SBOX##which (array0[0], array0[1], array0[2], array0[3], \ + array1[0], array1[1], array1[2], array1[3]); + +/* Apply inverse SBOX number WHICH to to the block found in ARRAY0, writing + the output to the block found in ARRAY1. */ +#define SBOX_INVERSE(which, array0, array1) \ + SBOX##which##_INVERSE (array0[0], array0[1], array0[2], array0[3], \ + array1[0], array1[1], array1[2], array1[3]); /* Apply the linear transformation to BLOCK. */ #define LINEAR_TRANSFORMATION(block) \ @@ -533,7 +517,7 @@ static const char *serpent_test (void); { \ BLOCK_XOR (block, subkeys[round]); \ round++; \ - SBOX (which, block, block_tmp, 0); \ + SBOX (which, block, block_tmp); \ LINEAR_TRANSFORMATION (block_tmp); \ BLOCK_COPY (block, block_tmp); \ } @@ -546,7 +530,7 @@ static const char *serpent_test (void); { \ BLOCK_XOR (block, subkeys[round]); \ round++; \ - SBOX (which, block, block_tmp, 0); \ + SBOX (which, block, block_tmp); \ BLOCK_XOR (block_tmp, subkeys[round]); \ round++; \ } @@ -557,7 +541,7 @@ static const char *serpent_test (void); #define ROUND_INVERSE(which, subkey, block, block_tmp) \ { \ LINEAR_TRANSFORMATION_INVERSE (block); \ - SBOX_INVERSE (which, block, block_tmp, 0); \ + SBOX_INVERSE (which, block, block_tmp); \ BLOCK_XOR (block_tmp, subkey[round]); \ round--; \ BLOCK_COPY (block, block_tmp); \ @@ -571,7 +555,7 @@ static const char *serpent_test (void); { \ BLOCK_XOR (block, subkeys[round]); \ round--; \ - SBOX_INVERSE (which, block, block_tmp, 0); \ + SBOX_INVERSE (which, block, block_tmp); \ BLOCK_XOR (block_tmp, subkeys[round]); \ round--; \ } @@ -585,14 +569,9 @@ serpent_key_prepare (const byte *key, unsigned int key_length, int i; /* Copy key. */ - for (i = 0; i < key_length / 4; i++) - { -#ifdef WORDS_BIGENDIAN - key_prepared[i] = byte_swap_32 (((u32 *) key)[i]); -#else - key_prepared[i] = ((u32 *) key)[i]; -#endif - } + key_length /= 4; + for (i = 0; i < key_length; i++) + key_prepared[i] = buf_get_le32 (key + i * 4); if (i < 8) { @@ -609,58 +588,57 @@ serpent_key_prepare (const byte *key, unsigned int key_length, static void serpent_subkeys_generate (serpent_key_t key, serpent_subkeys_t subkeys) { - u32 w_real[140]; /* The `prekey'. */ - u32 k[132]; - u32 *w = &w_real[8]; - int i, j; + u32 w[8]; /* The `prekey'. */ + u32 ws[4]; + u32 wt[4]; /* Initialize with key values. */ - for (i = 0; i < 8; i++) - w[i - 8] = key[i]; + w[0] = key[0]; + w[1] = key[1]; + w[2] = key[2]; + w[3] = key[3]; + w[4] = key[4]; + w[5] = key[5]; + w[6] = key[6]; + w[7] = key[7]; /* Expand to intermediate key using the affine recurrence. */ - for (i = 0; i < 132; i++) - w[i] = rol (w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ i, 11); +#define EXPAND_KEY4(wo, r) \ + wo[0] = w[(r+0)%8] = \ + rol (w[(r+0)%8] ^ w[(r+3)%8] ^ w[(r+5)%8] ^ w[(r+7)%8] ^ PHI ^ (r+0), 11); \ + wo[1] = w[(r+1)%8] = \ + rol (w[(r+1)%8] ^ w[(r+4)%8] ^ w[(r+6)%8] ^ w[(r+0)%8] ^ PHI ^ (r+1), 11); \ + wo[2] = w[(r+2)%8] = \ + rol (w[(r+2)%8] ^ w[(r+5)%8] ^ w[(r+7)%8] ^ w[(r+1)%8] ^ PHI ^ (r+2), 11); \ + wo[3] = w[(r+3)%8] = \ + rol (w[(r+3)%8] ^ w[(r+6)%8] ^ w[(r+0)%8] ^ w[(r+2)%8] ^ PHI ^ (r+3), 11); + +#define EXPAND_KEY(r) \ + EXPAND_KEY4(ws, (r)); \ + EXPAND_KEY4(wt, (r + 4)); /* Calculate subkeys via S-Boxes, in bitslice mode. */ - SBOX (3, w, k, 0); - SBOX (2, w, k, 4); - SBOX (1, w, k, 8); - SBOX (0, w, k, 12); - SBOX (7, w, k, 16); - SBOX (6, w, k, 20); - SBOX (5, w, k, 24); - SBOX (4, w, k, 28); - SBOX (3, w, k, 32); - SBOX (2, w, k, 36); - SBOX (1, w, k, 40); - SBOX (0, w, k, 44); - SBOX (7, w, k, 48); - SBOX (6, w, k, 52); - SBOX (5, w, k, 56); - SBOX (4, w, k, 60); - SBOX (3, w, k, 64); - SBOX (2, w, k, 68); - SBOX (1, w, k, 72); - SBOX (0, w, k, 76); - SBOX (7, w, k, 80); - SBOX (6, w, k, 84); - SBOX (5, w, k, 88); - SBOX (4, w, k, 92); - SBOX (3, w, k, 96); - SBOX (2, w, k, 100); - SBOX (1, w, k, 104); - SBOX (0, w, k, 108); - SBOX (7, w, k, 112); - SBOX (6, w, k, 116); - SBOX (5, w, k, 120); - SBOX (4, w, k, 124); - SBOX (3, w, k, 128); - - /* Renumber subkeys. */ - for (i = 0; i < ROUNDS + 1; i++) - for (j = 0; j < 4; j++) - subkeys[i][j] = k[4 * i + j]; + EXPAND_KEY (0); SBOX (3, ws, subkeys[0]); SBOX (2, wt, subkeys[1]); + EXPAND_KEY (8); SBOX (1, ws, subkeys[2]); SBOX (0, wt, subkeys[3]); + EXPAND_KEY (16); SBOX (7, ws, subkeys[4]); SBOX (6, wt, subkeys[5]); + EXPAND_KEY (24); SBOX (5, ws, subkeys[6]); SBOX (4, wt, subkeys[7]); + EXPAND_KEY (32); SBOX (3, ws, subkeys[8]); SBOX (2, wt, subkeys[9]); + EXPAND_KEY (40); SBOX (1, ws, subkeys[10]); SBOX (0, wt, subkeys[11]); + EXPAND_KEY (48); SBOX (7, ws, subkeys[12]); SBOX (6, wt, subkeys[13]); + EXPAND_KEY (56); SBOX (5, ws, subkeys[14]); SBOX (4, wt, subkeys[15]); + EXPAND_KEY (64); SBOX (3, ws, subkeys[16]); SBOX (2, wt, subkeys[17]); + EXPAND_KEY (72); SBOX (1, ws, subkeys[18]); SBOX (0, wt, subkeys[19]); + EXPAND_KEY (80); SBOX (7, ws, subkeys[20]); SBOX (6, wt, subkeys[21]); + EXPAND_KEY (88); SBOX (5, ws, subkeys[22]); SBOX (4, wt, subkeys[23]); + EXPAND_KEY (96); SBOX (3, ws, subkeys[24]); SBOX (2, wt, subkeys[25]); + EXPAND_KEY (104); SBOX (1, ws, subkeys[26]); SBOX (0, wt, subkeys[27]); + EXPAND_KEY (112); SBOX (7, ws, subkeys[28]); SBOX (6, wt, subkeys[29]); + EXPAND_KEY (120); SBOX (5, ws, subkeys[30]); SBOX (4, wt, subkeys[31]); + EXPAND_KEY4 (ws, 128); SBOX (3, ws, subkeys[32]); + + wipememory (ws, sizeof (ws)); + wipememory (wt, sizeof (wt)); + wipememory (w, sizeof (w)); } /* Initialize CONTEXT with the key KEY of KEY_LENGTH bits. */ @@ -672,7 +650,24 @@ serpent_setkey_internal (serpent_context_t *context, serpent_key_prepare (key, key_length, key_prepared); serpent_subkeys_generate (key_prepared, context->keys); - _gcry_burn_stack (272 * sizeof (u32)); + +#ifdef USE_AVX2 + context->use_avx2 = 0; + if ((_gcry_get_hw_features () & HWF_INTEL_AVX2)) + { + context->use_avx2 = 1; + } +#endif + +#ifdef USE_NEON + context->use_neon = 0; + if ((_gcry_get_hw_features () & HWF_ARM_NEON)) + { + context->use_neon = 1; + } +#endif + + wipememory (key_prepared, sizeof(key_prepared)); } /* Initialize CTX with the key KEY of KEY_LENGTH bytes. */ @@ -684,45 +679,35 @@ serpent_setkey (void *ctx, static const char *serpent_test_ret; static int serpent_init_done; gcry_err_code_t ret = GPG_ERR_NO_ERROR; - + if (! serpent_init_done) { /* Execute a self-test the first time, Serpent is used. */ + serpent_init_done = 1; serpent_test_ret = serpent_test (); if (serpent_test_ret) log_error ("Serpent test failure: %s\n", serpent_test_ret); - serpent_init_done = 1; } if (serpent_test_ret) ret = GPG_ERR_SELFTEST_FAILED; else - { - serpent_setkey_internal (context, key, key_length); - _gcry_burn_stack (sizeof (serpent_key_t)); - } + serpent_setkey_internal (context, key, key_length); return ret; } static void serpent_encrypt_internal (serpent_context_t *context, - const serpent_block_t input, serpent_block_t output) + const byte *input, byte *output) { serpent_block_t b, b_next; int round = 0; -#ifdef WORDS_BIGENDIAN - b[0] = byte_swap_32 (input[0]); - b[1] = byte_swap_32 (input[1]); - b[2] = byte_swap_32 (input[2]); - b[3] = byte_swap_32 (input[3]); -#else - b[0] = input[0]; - b[1] = input[1]; - b[2] = input[2]; - b[3] = input[3]; -#endif + b[0] = buf_get_le32 (input + 0); + b[1] = buf_get_le32 (input + 4); + b[2] = buf_get_le32 (input + 8); + b[3] = buf_get_le32 (input + 12); ROUND (0, context->keys, b, b_next); ROUND (1, context->keys, b, b_next); @@ -758,37 +743,23 @@ serpent_encrypt_internal (serpent_context_t *context, ROUND_LAST (7, context->keys, b, b_next); -#ifdef WORDS_BIGENDIAN - output[0] = byte_swap_32 (b_next[0]); - output[1] = byte_swap_32 (b_next[1]); - output[2] = byte_swap_32 (b_next[2]); - output[3] = byte_swap_32 (b_next[3]); -#else - output[0] = b_next[0]; - output[1] = b_next[1]; - output[2] = b_next[2]; - output[3] = b_next[3]; -#endif + buf_put_le32 (output + 0, b_next[0]); + buf_put_le32 (output + 4, b_next[1]); + buf_put_le32 (output + 8, b_next[2]); + buf_put_le32 (output + 12, b_next[3]); } static void serpent_decrypt_internal (serpent_context_t *context, - const serpent_block_t input, serpent_block_t output) + const byte *input, byte *output) { serpent_block_t b, b_next; int round = ROUNDS; -#ifdef WORDS_BIGENDIAN - b_next[0] = byte_swap_32 (input[0]); - b_next[1] = byte_swap_32 (input[1]); - b_next[2] = byte_swap_32 (input[2]); - b_next[3] = byte_swap_32 (input[3]); -#else - b_next[0] = input[0]; - b_next[1] = input[1]; - b_next[2] = input[2]; - b_next[3] = input[3]; -#endif + b_next[0] = buf_get_le32 (input + 0); + b_next[1] = buf_get_le32 (input + 4); + b_next[2] = buf_get_le32 (input + 8); + b_next[3] = buf_get_le32 (input + 12); ROUND_FIRST_INVERSE (7, context->keys, b_next, b); @@ -824,43 +795,409 @@ serpent_decrypt_internal (serpent_context_t *context, ROUND_INVERSE (1, context->keys, b, b_next); ROUND_INVERSE (0, context->keys, b, b_next); - -#ifdef WORDS_BIGENDIAN - output[0] = byte_swap_32 (b_next[0]); - output[1] = byte_swap_32 (b_next[1]); - output[2] = byte_swap_32 (b_next[2]); - output[3] = byte_swap_32 (b_next[3]); -#else - output[0] = b_next[0]; - output[1] = b_next[1]; - output[2] = b_next[2]; - output[3] = b_next[3]; -#endif + buf_put_le32 (output + 0, b_next[0]); + buf_put_le32 (output + 4, b_next[1]); + buf_put_le32 (output + 8, b_next[2]); + buf_put_le32 (output + 12, b_next[3]); } -static void +static unsigned int serpent_encrypt (void *ctx, byte *buffer_out, const byte *buffer_in) { serpent_context_t *context = ctx; - serpent_encrypt_internal (context, - (const u32 *) buffer_in, (u32 *) buffer_out); - _gcry_burn_stack (2 * sizeof (serpent_block_t)); + serpent_encrypt_internal (context, buffer_in, buffer_out); + return /*burn_stack*/ (2 * sizeof (serpent_block_t)); } -static void +static unsigned int serpent_decrypt (void *ctx, byte *buffer_out, const byte *buffer_in) { serpent_context_t *context = ctx; - serpent_decrypt_internal (context, - (const u32 *) buffer_in, - (u32 *) buffer_out); - _gcry_burn_stack (2 * sizeof (serpent_block_t)); + serpent_decrypt_internal (context, buffer_in, buffer_out); + return /*burn_stack*/ (2 * sizeof (serpent_block_t)); } +/* Bulk encryption of complete blocks in CTR mode. This function is only + intended for the bulk encryption feature of cipher.c. CTR is expected to be + of size sizeof(serpent_block_t). */ +void +_gcry_serpent_ctr_enc(void *context, unsigned char *ctr, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks) +{ + serpent_context_t *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char tmpbuf[sizeof(serpent_block_t)]; + int burn_stack_depth = 2 * sizeof (serpent_block_t); + int i; + +#ifdef USE_AVX2 + if (ctx->use_avx2) + { + int did_use_avx2 = 0; + + /* Process data in 16 block chunks. */ + while (nblocks >= 16) + { + _gcry_serpent_avx2_ctr_enc(ctx, outbuf, inbuf, ctr); + + nblocks -= 16; + outbuf += 16 * sizeof(serpent_block_t); + inbuf += 16 * sizeof(serpent_block_t); + did_use_avx2 = 1; + } + + if (did_use_avx2) + { + /* serpent-avx2 assembly code does not use stack */ + if (nblocks == 0) + burn_stack_depth = 0; + } + + /* Use generic/sse2 code to handle smaller chunks... */ + /* TODO: use caching instead? */ + } +#endif + +#ifdef USE_SSE2 + { + int did_use_sse2 = 0; + + /* Process data in 8 block chunks. */ + while (nblocks >= 8) + { + _gcry_serpent_sse2_ctr_enc(ctx, outbuf, inbuf, ctr); + + nblocks -= 8; + outbuf += 8 * sizeof(serpent_block_t); + inbuf += 8 * sizeof(serpent_block_t); + did_use_sse2 = 1; + } + + if (did_use_sse2) + { + /* serpent-sse2 assembly code does not use stack */ + if (nblocks == 0) + burn_stack_depth = 0; + } + + /* Use generic code to handle smaller chunks... */ + /* TODO: use caching instead? */ + } +#endif + +#ifdef USE_NEON + if (ctx->use_neon) + { + int did_use_neon = 0; + + /* Process data in 8 block chunks. */ + while (nblocks >= 8) + { + _gcry_serpent_neon_ctr_enc(ctx, outbuf, inbuf, ctr); + + nblocks -= 8; + outbuf += 8 * sizeof(serpent_block_t); + inbuf += 8 * sizeof(serpent_block_t); + did_use_neon = 1; + } + + if (did_use_neon) + { + /* serpent-neon assembly code does not use stack */ + if (nblocks == 0) + burn_stack_depth = 0; + } + + /* Use generic code to handle smaller chunks... */ + /* TODO: use caching instead? */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* Encrypt the counter. */ + serpent_encrypt_internal(ctx, ctr, tmpbuf); + /* XOR the input with the encrypted counter and store in output. */ + buf_xor(outbuf, tmpbuf, inbuf, sizeof(serpent_block_t)); + outbuf += sizeof(serpent_block_t); + inbuf += sizeof(serpent_block_t); + /* Increment the counter. */ + for (i = sizeof(serpent_block_t); i > 0; i--) + { + ctr[i-1]++; + if (ctr[i-1]) + break; + } + } + + wipememory(tmpbuf, sizeof(tmpbuf)); + _gcry_burn_stack(burn_stack_depth); +} + +/* Bulk decryption of complete blocks in CBC mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +void +_gcry_serpent_cbc_dec(void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks) +{ + serpent_context_t *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char savebuf[sizeof(serpent_block_t)]; + int burn_stack_depth = 2 * sizeof (serpent_block_t); + +#ifdef USE_AVX2 + if (ctx->use_avx2) + { + int did_use_avx2 = 0; + + /* Process data in 16 block chunks. */ + while (nblocks >= 16) + { + _gcry_serpent_avx2_cbc_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 16; + outbuf += 16 * sizeof(serpent_block_t); + inbuf += 16 * sizeof(serpent_block_t); + did_use_avx2 = 1; + } + + if (did_use_avx2) + { + /* serpent-avx2 assembly code does not use stack */ + if (nblocks == 0) + burn_stack_depth = 0; + } + + /* Use generic/sse2 code to handle smaller chunks... */ + } +#endif + +#ifdef USE_SSE2 + { + int did_use_sse2 = 0; + + /* Process data in 8 block chunks. */ + while (nblocks >= 8) + { + _gcry_serpent_sse2_cbc_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 8; + outbuf += 8 * sizeof(serpent_block_t); + inbuf += 8 * sizeof(serpent_block_t); + did_use_sse2 = 1; + } + + if (did_use_sse2) + { + /* serpent-sse2 assembly code does not use stack */ + if (nblocks == 0) + burn_stack_depth = 0; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#ifdef USE_NEON + if (ctx->use_neon) + { + int did_use_neon = 0; + + /* Process data in 8 block chunks. */ + while (nblocks >= 8) + { + _gcry_serpent_neon_cbc_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 8; + outbuf += 8 * sizeof(serpent_block_t); + inbuf += 8 * sizeof(serpent_block_t); + did_use_neon = 1; + } + + if (did_use_neon) + { + /* serpent-neon assembly code does not use stack */ + if (nblocks == 0) + burn_stack_depth = 0; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* INBUF is needed later and it may be identical to OUTBUF, so store + the intermediate result to SAVEBUF. */ + serpent_decrypt_internal (ctx, inbuf, savebuf); + + buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, sizeof(serpent_block_t)); + inbuf += sizeof(serpent_block_t); + outbuf += sizeof(serpent_block_t); + } + + wipememory(savebuf, sizeof(savebuf)); + _gcry_burn_stack(burn_stack_depth); +} + +/* Bulk decryption of complete blocks in CFB mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +void +_gcry_serpent_cfb_dec(void *context, unsigned char *iv, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks) +{ + serpent_context_t *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + int burn_stack_depth = 2 * sizeof (serpent_block_t); + +#ifdef USE_AVX2 + if (ctx->use_avx2) + { + int did_use_avx2 = 0; + + /* Process data in 16 block chunks. */ + while (nblocks >= 16) + { + _gcry_serpent_avx2_cfb_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 16; + outbuf += 16 * sizeof(serpent_block_t); + inbuf += 16 * sizeof(serpent_block_t); + did_use_avx2 = 1; + } + + if (did_use_avx2) + { + /* serpent-avx2 assembly code does not use stack */ + if (nblocks == 0) + burn_stack_depth = 0; + } + + /* Use generic/sse2 code to handle smaller chunks... */ + } +#endif + +#ifdef USE_SSE2 + { + int did_use_sse2 = 0; + + /* Process data in 8 block chunks. */ + while (nblocks >= 8) + { + _gcry_serpent_sse2_cfb_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 8; + outbuf += 8 * sizeof(serpent_block_t); + inbuf += 8 * sizeof(serpent_block_t); + did_use_sse2 = 1; + } + + if (did_use_sse2) + { + /* serpent-sse2 assembly code does not use stack */ + if (nblocks == 0) + burn_stack_depth = 0; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + +#ifdef USE_NEON + if (ctx->use_neon) + { + int did_use_neon = 0; + + /* Process data in 8 block chunks. */ + while (nblocks >= 8) + { + _gcry_serpent_neon_cfb_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 8; + outbuf += 8 * sizeof(serpent_block_t); + inbuf += 8 * sizeof(serpent_block_t); + did_use_neon = 1; + } + + if (did_use_neon) + { + /* serpent-neon assembly code does not use stack */ + if (nblocks == 0) + burn_stack_depth = 0; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + serpent_encrypt_internal(ctx, iv, iv); + buf_xor_n_copy(outbuf, iv, inbuf, sizeof(serpent_block_t)); + outbuf += sizeof(serpent_block_t); + inbuf += sizeof(serpent_block_t); + } + + _gcry_burn_stack(burn_stack_depth); +} + + + +/* Run the self-tests for SERPENT-CTR-128, tests IV increment of bulk CTR + encryption. Returns NULL on success. */ +static const char* +selftest_ctr_128 (void) +{ + const int nblocks = 16+8+1; + const int blocksize = sizeof(serpent_block_t); + const int context_size = sizeof(serpent_context_t); + + return _gcry_selftest_helper_ctr("SERPENT", &serpent_setkey, + &serpent_encrypt, &_gcry_serpent_ctr_enc, nblocks, blocksize, + context_size); +} + + +/* Run the self-tests for SERPENT-CBC-128, tests bulk CBC decryption. + Returns NULL on success. */ +static const char* +selftest_cbc_128 (void) +{ + const int nblocks = 16+8+2; + const int blocksize = sizeof(serpent_block_t); + const int context_size = sizeof(serpent_context_t); + + return _gcry_selftest_helper_cbc("SERPENT", &serpent_setkey, + &serpent_encrypt, &_gcry_serpent_cbc_dec, nblocks, blocksize, + context_size); +} + + +/* Run the self-tests for SERPENT-CBC-128, tests bulk CBC decryption. + Returns NULL on success. */ +static const char* +selftest_cfb_128 (void) +{ + const int nblocks = 16+8+2; + const int blocksize = sizeof(serpent_block_t); + const int context_size = sizeof(serpent_context_t); + + return _gcry_selftest_helper_cfb("SERPENT", &serpent_setkey, + &serpent_encrypt, &_gcry_serpent_cfb_dec, nblocks, blocksize, + context_size); +} + + /* Serpent test. */ static const char * @@ -869,6 +1206,7 @@ serpent_test (void) serpent_context_t context; unsigned char scratch[16]; unsigned int i; + const char *r; static struct test { @@ -914,9 +1252,7 @@ serpent_test (void) { serpent_setkey_internal (&context, test_data[i].key, test_data[i].key_length); - serpent_encrypt_internal (&context, - (const u32 *) test_data[i].text_plain, - (u32 *) scratch); + serpent_encrypt_internal (&context, test_data[i].text_plain, scratch); if (memcmp (scratch, test_data[i].text_cipher, sizeof (serpent_block_t))) switch (test_data[i].key_length) @@ -929,9 +1265,7 @@ serpent_test (void) return "Serpent-256 test encryption failed."; } - serpent_decrypt_internal (&context, - (const u32 *) test_data[i].text_cipher, - (u32 *) scratch); + serpent_decrypt_internal (&context, test_data[i].text_cipher, scratch); if (memcmp (scratch, test_data[i].text_plain, sizeof (serpent_block_t))) switch (test_data[i].key_length) { @@ -944,6 +1278,15 @@ serpent_test (void) } } + if ( (r = selftest_ctr_128 ()) ) + return r; + + if ( (r = selftest_cbc_128 ()) ) + return r; + + if ( (r = selftest_cfb_128 ()) ) + return r; + return NULL; } @@ -958,6 +1301,7 @@ static const char *cipher_spec_serpent128_aliases[] = gcry_cipher_spec_t _gcry_cipher_spec_serpent128 = { + GCRY_CIPHER_SERPENT128, {0, 0}, "SERPENT128", cipher_spec_serpent128_aliases, NULL, 16, 128, sizeof (serpent_context_t), serpent_setkey, serpent_encrypt, serpent_decrypt @@ -965,6 +1309,7 @@ gcry_cipher_spec_t _gcry_cipher_spec_serpent128 = gcry_cipher_spec_t _gcry_cipher_spec_serpent192 = { + GCRY_CIPHER_SERPENT192, {0, 0}, "SERPENT192", NULL, NULL, 16, 192, sizeof (serpent_context_t), serpent_setkey, serpent_encrypt, serpent_decrypt @@ -972,6 +1317,7 @@ gcry_cipher_spec_t _gcry_cipher_spec_serpent192 = gcry_cipher_spec_t _gcry_cipher_spec_serpent256 = { + GCRY_CIPHER_SERPENT256, {0, 0}, "SERPENT256", NULL, NULL, 16, 256, sizeof (serpent_context_t), serpent_setkey, serpent_encrypt, serpent_decrypt diff --git a/plugins/MirOTR/Libgcrypt/cipher/sha1.c b/plugins/MirOTR/Libgcrypt/cipher/sha1.c index 67cbaff3b3..2e0b030c31 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/sha1.c +++ b/plugins/MirOTR/Libgcrypt/cipher/sha1.c @@ -32,17 +32,25 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#ifdef HAVE_STDINT_H +#ifdef HAVE_STDINT_H # include <stdint.h> #endif #include "g10lib.h" -#include "memory.h" #include "bithelp.h" +#include "bufhelp.h" #include "cipher.h" #include "hash-common.h" +/* USE_SSSE3 indicates whether to compile with Intel SSSE3 code. */ +#undef USE_SSSE3 +#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) && \ + defined(HAVE_GCC_INLINE_ASM_SSSE3) +# define USE_SSSE3 1 +#endif + + /* A macro to test whether P is properly aligned for an u32 type. Note that config.h provides a suitable replacement for uintptr_t if it does not exist in stdint.h. */ @@ -52,31 +60,41 @@ /* # define U32_ALIGNED_P(p) (!(((uintptr_t)p) % sizeof (u32))) */ /* #endif */ -#define TRANSFORM(x,d,n) transform ((x), (d), (n)) - - -typedef struct +typedef struct { + gcry_md_block_ctx_t bctx; u32 h0,h1,h2,h3,h4; - u32 nblocks; - unsigned char buf[64]; - int count; +#ifdef USE_SSSE3 + unsigned int use_ssse3:1; +#endif } SHA1_CONTEXT; +static unsigned int +transform (void *c, const unsigned char *data); static void -mir_sha1_init (void *context) +sha1_init (void *context, unsigned int flags) { SHA1_CONTEXT *hd = context; + (void)flags; + hd->h0 = 0x67452301; hd->h1 = 0xefcdab89; hd->h2 = 0x98badcfe; hd->h3 = 0x10325476; hd->h4 = 0xc3d2e1f0; - hd->nblocks = 0; - hd->count = 0; + + hd->bctx.nblocks = 0; + hd->bctx.nblocks_high = 0; + hd->bctx.count = 0; + hd->bctx.blocksize = 64; + hd->bctx.bwrite = transform; + +#ifdef USE_SSSE3 + hd->use_ssse3 = (_gcry_get_hw_features () & HWF_INTEL_SSSE3) != 0; +#endif } @@ -105,33 +123,17 @@ mir_sha1_init (void *context) /* * Transform NBLOCKS of each 64 bytes (16 32-bit words) at DATA. */ -static void -transform (SHA1_CONTEXT *hd, const unsigned char *data, size_t nblocks) +static unsigned int +_transform (void *ctx, const unsigned char *data) { + SHA1_CONTEXT *hd = ctx; + const u32 *idata = (const void *)data; register u32 a, b, c, d, e; /* Local copies of the chaining variables. */ register u32 tm; /* Helper. */ u32 x[16]; /* The array we work on. */ - - /* Loop over all blocks. */ - for ( ;nblocks; nblocks--) - { -#ifdef WORDS_BIGENDIAN - memcpy (x, data, 64); - data += 64; -#else - { - int i; - unsigned char *p; - - for(i=0, p=(unsigned char*)x; i < 16; i++, p += 4 ) - { - p[3] = *data++; - p[2] = *data++; - p[1] = *data++; - p[0] = *data++; - } - } -#endif + +#define I(i) (x[i] = buf_get_be32(idata + i)) + /* Get the values of the chaining variables. */ a = hd->h0; b = hd->h1; @@ -140,22 +142,22 @@ transform (SHA1_CONTEXT *hd, const unsigned char *data, size_t nblocks) e = hd->h4; /* Transform. */ - R( a, b, c, d, e, F1, K1, x[ 0] ); - R( e, a, b, c, d, F1, K1, x[ 1] ); - R( d, e, a, b, c, F1, K1, x[ 2] ); - R( c, d, e, a, b, F1, K1, x[ 3] ); - R( b, c, d, e, a, F1, K1, x[ 4] ); - R( a, b, c, d, e, F1, K1, x[ 5] ); - R( e, a, b, c, d, F1, K1, x[ 6] ); - R( d, e, a, b, c, F1, K1, x[ 7] ); - R( c, d, e, a, b, F1, K1, x[ 8] ); - R( b, c, d, e, a, F1, K1, x[ 9] ); - R( a, b, c, d, e, F1, K1, x[10] ); - R( e, a, b, c, d, F1, K1, x[11] ); - R( d, e, a, b, c, F1, K1, x[12] ); - R( c, d, e, a, b, F1, K1, x[13] ); - R( b, c, d, e, a, F1, K1, x[14] ); - R( a, b, c, d, e, F1, K1, x[15] ); + R( a, b, c, d, e, F1, K1, I( 0) ); + R( e, a, b, c, d, F1, K1, I( 1) ); + R( d, e, a, b, c, F1, K1, I( 2) ); + R( c, d, e, a, b, F1, K1, I( 3) ); + R( b, c, d, e, a, F1, K1, I( 4) ); + R( a, b, c, d, e, F1, K1, I( 5) ); + R( e, a, b, c, d, F1, K1, I( 6) ); + R( d, e, a, b, c, F1, K1, I( 7) ); + R( c, d, e, a, b, F1, K1, I( 8) ); + R( b, c, d, e, a, F1, K1, I( 9) ); + R( a, b, c, d, e, F1, K1, I(10) ); + R( e, a, b, c, d, F1, K1, I(11) ); + R( d, e, a, b, c, F1, K1, I(12) ); + R( c, d, e, a, b, F1, K1, I(13) ); + R( b, c, d, e, a, F1, K1, I(14) ); + R( a, b, c, d, e, F1, K1, I(15) ); R( e, a, b, c, d, F1, K1, M(16) ); R( d, e, a, b, c, F1, K1, M(17) ); R( c, d, e, a, b, F1, K1, M(18) ); @@ -227,53 +229,29 @@ transform (SHA1_CONTEXT *hd, const unsigned char *data, size_t nblocks) hd->h2 += c; hd->h3 += d; hd->h4 += e; - } + + return /* burn_stack */ 88+4*sizeof(void*); } -/* Update the message digest with the contents - * of INBUF with length INLEN. - */ -static void -sha1_write( void *context, const void *inbuf_arg, size_t inlen) -{ - const unsigned char *inbuf = inbuf_arg; - SHA1_CONTEXT *hd = context; - size_t nblocks; +#ifdef USE_SSSE3 +unsigned int +_gcry_sha1_transform_amd64_ssse3 (void *state, const unsigned char *data); +#endif - if (hd->count == 64) /* Flush the buffer. */ - { - TRANSFORM( hd, hd->buf, 1 ); - _gcry_burn_stack (88+4*sizeof(void*)); - hd->count = 0; - hd->nblocks++; - } - if (!inbuf) - return; - if (hd->count) - { - for (; inlen && hd->count < 64; inlen--) - hd->buf[hd->count++] = *inbuf++; - sha1_write (hd, NULL, 0); - if (!inlen) - return; - } +static unsigned int +transform (void *ctx, const unsigned char *data) +{ + SHA1_CONTEXT *hd = ctx; - nblocks = inlen / 64; - if (nblocks) - { - TRANSFORM (hd, inbuf, nblocks); - hd->count = 0; - hd->nblocks += nblocks; - inlen -= nblocks * 64; - inbuf += nblocks * 64; - } - _gcry_burn_stack (88+4*sizeof(void*)); +#ifdef USE_SSSE3 + if (hd->use_ssse3) + return _gcry_sha1_transform_amd64_ssse3 (&hd->h0, data) + + 4 * sizeof(void*); +#endif - /* Save remaining bytes. */ - for (; inlen && hd->count < 64; inlen--) - hd->buf[hd->count++] = *inbuf++; + return _transform (hd, data); } @@ -288,19 +266,24 @@ static void sha1_final(void *context) { SHA1_CONTEXT *hd = context; - - u32 t, msb, lsb; + u32 t, th, msb, lsb; unsigned char *p; + unsigned int burn; - sha1_write(hd, NULL, 0); /* flush */; + _gcry_md_block_write (hd, NULL, 0); /* flush */; + + t = hd->bctx.nblocks; + if (sizeof t == sizeof hd->bctx.nblocks) + th = hd->bctx.nblocks_high; + else + th = hd->bctx.nblocks >> 32; - t = hd->nblocks; /* multiply by 64 to make a byte count */ lsb = t << 6; - msb = t >> 26; + msb = (th << 6) | (t >> 26); /* add the count */ t = lsb; - if( (lsb += hd->count) < t ) + if( (lsb += hd->bctx.count) < t ) msb++; /* multiply by 8 to make a bit count */ t = lsb; @@ -308,39 +291,28 @@ sha1_final(void *context) msb <<= 3; msb |= t >> 29; - if( hd->count < 56 ) /* enough room */ + if( hd->bctx.count < 56 ) /* enough room */ { - hd->buf[hd->count++] = 0x80; /* pad */ - while( hd->count < 56 ) - hd->buf[hd->count++] = 0; /* pad */ + hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad */ + while( hd->bctx.count < 56 ) + hd->bctx.buf[hd->bctx.count++] = 0; /* pad */ } else /* need one extra block */ { - hd->buf[hd->count++] = 0x80; /* pad character */ - while( hd->count < 64 ) - hd->buf[hd->count++] = 0; - sha1_write(hd, NULL, 0); /* flush */; - memset(hd->buf, 0, 56 ); /* fill next block with zeroes */ + hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad character */ + while( hd->bctx.count < 64 ) + hd->bctx.buf[hd->bctx.count++] = 0; + _gcry_md_block_write(hd, NULL, 0); /* flush */; + memset(hd->bctx.buf, 0, 56 ); /* fill next block with zeroes */ } /* append the 64 bit count */ - hd->buf[56] = msb >> 24; - hd->buf[57] = msb >> 16; - hd->buf[58] = msb >> 8; - hd->buf[59] = msb ; - hd->buf[60] = lsb >> 24; - hd->buf[61] = lsb >> 16; - hd->buf[62] = lsb >> 8; - hd->buf[63] = lsb ; - TRANSFORM( hd, hd->buf, 1 ); - _gcry_burn_stack (88+4*sizeof(void*)); - - p = hd->buf; -#ifdef WORDS_BIGENDIAN -#define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0) -#else /* little endian */ -#define X(a) do { *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16; \ - *p++ = hd->h##a >> 8; *p++ = hd->h##a; } while(0) -#endif + buf_put_be32(hd->bctx.buf + 56, msb); + buf_put_be32(hd->bctx.buf + 60, lsb); + burn = transform( hd, hd->bctx.buf ); + _gcry_burn_stack (burn); + + p = hd->bctx.buf; +#define X(a) do { *(u32*)p = be_bswap32(hd->h##a) ; p += 4; } while(0) X(0); X(1); X(2); @@ -355,7 +327,7 @@ sha1_read( void *context ) { SHA1_CONTEXT *hd = context; - return hd->buf; + return hd->bctx.buf; } /**************** @@ -367,15 +339,30 @@ _gcry_sha1_hash_buffer (void *outbuf, const void *buffer, size_t length) { SHA1_CONTEXT hd; - mir_sha1_init (&hd); - sha1_write (&hd, buffer, length); + sha1_init (&hd, 0); + _gcry_md_block_write (&hd, buffer, length); + sha1_final (&hd); + memcpy (outbuf, hd.bctx.buf, 20); +} + + +/* Variant of the above shortcut function using a multiple buffers. */ +void +_gcry_sha1_hash_buffers (void *outbuf, const gcry_buffer_t *iov, int iovcnt) +{ + SHA1_CONTEXT hd; + + sha1_init (&hd, 0); + for (;iovcnt > 0; iov++, iovcnt--) + _gcry_md_block_write (&hd, + (const char*)iov[0].data + iov[0].off, iov[0].len); sha1_final (&hd); - memcpy (outbuf, hd.buf, 20); + memcpy (outbuf, hd.bctx.buf, 20); } -/* +/* Self-test section. */ @@ -385,10 +372,10 @@ selftests_sha1 (int extended, selftest_report_func_t report) { const char *what; const char *errtxt; - + what = "short string"; errtxt = _gcry_hash_selftest_check_one - (GCRY_MD_SHA1, 0, + (GCRY_MD_SHA1, 0, "abc", 3, "\xA9\x99\x3E\x36\x47\x06\x81\x6A\xBA\x3E" "\x25\x71\x78\x50\xC2\x6C\x9C\xD0\xD8\x9D", 20); @@ -399,13 +386,13 @@ selftests_sha1 (int extended, selftest_report_func_t report) { what = "long string"; errtxt = _gcry_hash_selftest_check_one - (GCRY_MD_SHA1, 0, + (GCRY_MD_SHA1, 0, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56, "\x84\x98\x3E\x44\x1C\x3B\xD2\x6E\xBA\xAE" "\x4A\xA1\xF9\x51\x29\xE5\xE5\x46\x70\xF1", 20); if (errtxt) goto failed; - + what = "one million \"a\""; errtxt = _gcry_hash_selftest_check_one (GCRY_MD_SHA1, 1, @@ -439,7 +426,7 @@ run_selftests (int algo, int extended, selftest_report_func_t report) default: ec = GPG_ERR_DIGEST_ALGO; break; - + } return ec; } @@ -468,12 +455,9 @@ static gcry_md_oid_spec_t oid_spec_sha1[] = gcry_md_spec_t _gcry_digest_spec_sha1 = { + GCRY_MD_SHA1, {0, 1}, "SHA1", asn, DIM (asn), oid_spec_sha1, 20, - mir_sha1_init, sha1_write, sha1_final, sha1_read, - sizeof (SHA1_CONTEXT) - }; -md_extra_spec_t _gcry_digest_extraspec_sha1 = - { + sha1_init, _gcry_md_block_write, sha1_final, sha1_read, + sizeof (SHA1_CONTEXT), run_selftests }; - diff --git a/plugins/MirOTR/Libgcrypt/cipher/sha256.c b/plugins/MirOTR/Libgcrypt/cipher/sha256.c index 8063592f75..d92303cdc7 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/sha256.c +++ b/plugins/MirOTR/Libgcrypt/cipher/sha256.c @@ -19,7 +19,7 @@ /* Test vectors: - + "abc" SHA224: 23097d22 3405d822 8642a477 bda255b3 2aadbce4 bda0b3f7 e36c9da7 SHA256: ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad @@ -27,7 +27,7 @@ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" SHA224: 75388b16 512776cc 5dba5da1 fd890150 b0c6455c b4f58b19 52522525 SHA256: 248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1 - + "a" one million times SHA224: 20794655 980c91d8 bbb4c1ea 97618a4b f03f4258 1948b2ee 4ee7ad67 SHA256: cdc76e5c 9914fb92 81a1c7e2 84d73e67 f1809a48 a497200e 046d39cc c7112cd0 @@ -42,22 +42,40 @@ #include "g10lib.h" #include "bithelp.h" +#include "bufhelp.h" #include "cipher.h" #include "hash-common.h" + +/* USE_SSSE3 indicates whether to compile with Intel SSSE3 code. */ +#undef USE_SSSE3 +#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) && \ + defined(HAVE_GCC_INLINE_ASM_SSSE3) && \ + defined(HAVE_INTEL_SYNTAX_PLATFORM_AS) +# define USE_SSSE3 1 +#endif + + typedef struct { + gcry_md_block_ctx_t bctx; u32 h0,h1,h2,h3,h4,h5,h6,h7; - u32 nblocks; - byte buf[64]; - int count; +#ifdef USE_SSSE3 + unsigned int use_ssse3:1; +#endif } SHA256_CONTEXT; +static unsigned int +transform (void *c, const unsigned char *data); + + static void -sha256_init (void *context) +sha256_init (void *context, unsigned int flags) { SHA256_CONTEXT *hd = context; + (void)flags; + hd->h0 = 0x6a09e667; hd->h1 = 0xbb67ae85; hd->h2 = 0x3c6ef372; @@ -67,16 +85,25 @@ sha256_init (void *context) hd->h6 = 0x1f83d9ab; hd->h7 = 0x5be0cd19; - hd->nblocks = 0; - hd->count = 0; + hd->bctx.nblocks = 0; + hd->bctx.nblocks_high = 0; + hd->bctx.count = 0; + hd->bctx.blocksize = 64; + hd->bctx.bwrite = transform; + +#ifdef USE_SSSE3 + hd->use_ssse3 = (_gcry_get_hw_features () & HWF_INTEL_SSSE3) != 0; +#endif } static void -sha224_init (void *context) +sha224_init (void *context, unsigned int flags) { SHA256_CONTEXT *hd = context; + (void)flags; + hd->h0 = 0xc1059ed8; hd->h1 = 0x367cd507; hd->h2 = 0x3070dd17; @@ -86,8 +113,15 @@ sha224_init (void *context) hd->h6 = 0x64f98fa7; hd->h7 = 0xbefa4fa4; - hd->nblocks = 0; - hd->count = 0; + hd->bctx.nblocks = 0; + hd->bctx.nblocks_high = 0; + hd->bctx.count = 0; + hd->bctx.blocksize = 64; + hd->bctx.bwrite = transform; + +#ifdef USE_SSSE3 + hd->use_ssse3 = (_gcry_get_hw_features () & HWF_INTEL_SSSE3) != 0; +#endif } @@ -123,7 +157,7 @@ Maj (u32 x, u32 y, u32 z) { return ((x & y) | (z & (x|y))); } - + /* (4.4) */ static inline u32 Sum0 (u32 x) @@ -138,15 +172,16 @@ Sum1 (u32 x) return (ror (x, 6) ^ ror (x, 11) ^ ror (x, 25)); } - -static void -transform (SHA256_CONTEXT *hd, const unsigned char *data) + +static unsigned int +_transform (void *ctx, const unsigned char *data) { + SHA256_CONTEXT *hd = ctx; static const u32 K[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, @@ -162,10 +197,9 @@ transform (SHA256_CONTEXT *hd, const unsigned char *data) }; u32 a,b,c,d,e,f,g,h,t1,t2; - u32 x[16]; u32 w[64]; int i; - + a = hd->h0; b = hd->h1; c = hd->h2; @@ -174,25 +208,9 @@ transform (SHA256_CONTEXT *hd, const unsigned char *data) f = hd->h5; g = hd->h6; h = hd->h7; - -#ifdef WORDS_BIGENDIAN - memcpy (x, data, 64); -#else - { - byte *p2; - - for (i=0, p2=(byte*)x; i < 16; i++, p2 += 4 ) - { - p2[3] = *data++; - p2[2] = *data++; - p2[1] = *data++; - p2[0] = *data++; - } - } -#endif for (i=0; i < 16; i++) - w[i] = x[i]; + w[i] = buf_get_be32(data + i * 4); for (; i < 64; i++) w[i] = S1(w[i-2]) + w[i-7] + S0(w[i-15]) + w[i-16]; @@ -202,7 +220,7 @@ transform (SHA256_CONTEXT *hd, const unsigned char *data) R(a,b,c,d,e,f,g,h,K[i],w[i]); i++; #else - t1 = h + Sum1 (e) + Cho (e, f, g) + K[i] + w[i]; + t1 = h + Sum1 (e) + Cho (e, f, g) + K[i] + w[i]; t2 = Sum0 (a) + Maj (a, b, c); d += t1; h = t1 + t2; @@ -254,49 +272,32 @@ transform (SHA256_CONTEXT *hd, const unsigned char *data) hd->h5 += f; hd->h6 += g; hd->h7 += h; + + return /*burn_stack*/ 74*4+32; } #undef S0 #undef S1 #undef R -/* Update the message digest with the contents of INBUF with length - INLEN. */ -static void -sha256_write (void *context, const void *inbuf_arg, size_t inlen) +#ifdef USE_SSSE3 +unsigned int _gcry_sha256_transform_amd64_ssse3(const void *input_data, + u32 state[8], size_t num_blks); +#endif + + +static unsigned int +transform (void *ctx, const unsigned char *data) { - const unsigned char *inbuf = inbuf_arg; - SHA256_CONTEXT *hd = context; + SHA256_CONTEXT *hd = ctx; - if (hd->count == 64) - { /* flush the buffer */ - transform (hd, hd->buf); - _gcry_burn_stack (74*4+32); - hd->count = 0; - hd->nblocks++; - } - if (!inbuf) - return; - if (hd->count) - { - for (; inlen && hd->count < 64; inlen--) - hd->buf[hd->count++] = *inbuf++; - sha256_write (hd, NULL, 0); - if (!inlen) - return; - } +#ifdef USE_SSSE3 + if (hd->use_ssse3) + return _gcry_sha256_transform_amd64_ssse3 (data, &hd->h0, 1) + + 4 * sizeof(void*); +#endif - while (inlen >= 64) - { - transform (hd, inbuf); - hd->count = 0; - hd->nblocks++; - inlen -= 64; - inbuf += 64; - } - _gcry_burn_stack (74*4+32); - for (; inlen && hd->count < 64; inlen--) - hd->buf[hd->count++] = *inbuf++; + return _transform (hd, data); } @@ -309,18 +310,24 @@ static void sha256_final(void *context) { SHA256_CONTEXT *hd = context; - u32 t, msb, lsb; + u32 t, th, msb, lsb; byte *p; - - sha256_write (hd, NULL, 0); /* flush */; + unsigned int burn; + + _gcry_md_block_write (hd, NULL, 0); /* flush */; + + t = hd->bctx.nblocks; + if (sizeof t == sizeof hd->bctx.nblocks) + th = hd->bctx.nblocks_high; + else + th = hd->bctx.nblocks >> 32; - t = hd->nblocks; /* multiply by 64 to make a byte count */ lsb = t << 6; - msb = t >> 26; + msb = (th << 6) | (t >> 26); /* add the count */ t = lsb; - if ((lsb += hd->count) < t) + if ((lsb += hd->bctx.count) < t) msb++; /* multiply by 8 to make a bit count */ t = lsb; @@ -328,39 +335,28 @@ sha256_final(void *context) msb <<= 3; msb |= t >> 29; - if (hd->count < 56) + if (hd->bctx.count < 56) { /* enough room */ - hd->buf[hd->count++] = 0x80; /* pad */ - while (hd->count < 56) - hd->buf[hd->count++] = 0; /* pad */ + hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad */ + while (hd->bctx.count < 56) + hd->bctx.buf[hd->bctx.count++] = 0; /* pad */ } else { /* need one extra block */ - hd->buf[hd->count++] = 0x80; /* pad character */ - while (hd->count < 64) - hd->buf[hd->count++] = 0; - sha256_write (hd, NULL, 0); /* flush */; - memset (hd->buf, 0, 56 ); /* fill next block with zeroes */ + hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad character */ + while (hd->bctx.count < 64) + hd->bctx.buf[hd->bctx.count++] = 0; + _gcry_md_block_write (hd, NULL, 0); /* flush */; + memset (hd->bctx.buf, 0, 56 ); /* fill next block with zeroes */ } /* append the 64 bit count */ - hd->buf[56] = msb >> 24; - hd->buf[57] = msb >> 16; - hd->buf[58] = msb >> 8; - hd->buf[59] = msb; - hd->buf[60] = lsb >> 24; - hd->buf[61] = lsb >> 16; - hd->buf[62] = lsb >> 8; - hd->buf[63] = lsb; - transform (hd, hd->buf); - _gcry_burn_stack (74*4+32); - - p = hd->buf; -#ifdef WORDS_BIGENDIAN -#define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0) -#else /* little endian */ -#define X(a) do { *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16; \ - *p++ = hd->h##a >> 8; *p++ = hd->h##a; } while(0) -#endif + buf_put_be32(hd->bctx.buf + 56, msb); + buf_put_be32(hd->bctx.buf + 60, lsb); + burn = transform (hd, hd->bctx.buf); + _gcry_burn_stack (burn); + + p = hd->bctx.buf; +#define X(a) do { *(u32*)p = be_bswap32(hd->h##a); p += 4; } while(0) X(0); X(1); X(2); @@ -377,12 +373,12 @@ sha256_read (void *context) { SHA256_CONTEXT *hd = context; - return hd->buf; + return hd->bctx.buf; } -/* +/* Self-test section. */ @@ -392,10 +388,10 @@ selftests_sha224 (int extended, selftest_report_func_t report) { const char *what; const char *errtxt; - + what = "short string"; errtxt = _gcry_hash_selftest_check_one - (GCRY_MD_SHA224, 0, + (GCRY_MD_SHA224, 0, "abc", 3, "\x23\x09\x7d\x22\x34\x05\xd8\x22\x86\x42\xa4\x77\xbd\xa2\x55\xb3" "\x2a\xad\xbc\xe4\xbd\xa0\xb3\xf7\xe3\x6c\x9d\xa7", 28); @@ -406,13 +402,13 @@ selftests_sha224 (int extended, selftest_report_func_t report) { what = "long string"; errtxt = _gcry_hash_selftest_check_one - (GCRY_MD_SHA224, 0, + (GCRY_MD_SHA224, 0, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56, "\x75\x38\x8b\x16\x51\x27\x76\xcc\x5d\xba\x5d\xa1\xfd\x89\x01\x50" "\xb0\xc6\x45\x5c\xb4\xf5\x8b\x19\x52\x52\x25\x25", 28); if (errtxt) goto failed; - + what = "one million \"a\""; errtxt = _gcry_hash_selftest_check_one (GCRY_MD_SHA224, 1, @@ -436,10 +432,10 @@ selftests_sha256 (int extended, selftest_report_func_t report) { const char *what; const char *errtxt; - + what = "short string"; errtxt = _gcry_hash_selftest_check_one - (GCRY_MD_SHA256, 0, + (GCRY_MD_SHA256, 0, "abc", 3, "\xba\x78\x16\xbf\x8f\x01\xcf\xea\x41\x41\x40\xde\x5d\xae\x22\x23" "\xb0\x03\x61\xa3\x96\x17\x7a\x9c\xb4\x10\xff\x61\xf2\x00\x15\xad", 32); @@ -450,14 +446,14 @@ selftests_sha256 (int extended, selftest_report_func_t report) { what = "long string"; errtxt = _gcry_hash_selftest_check_one - (GCRY_MD_SHA256, 0, + (GCRY_MD_SHA256, 0, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56, "\x24\x8d\x6a\x61\xd2\x06\x38\xb8\xe5\xc0\x26\x93\x0c\x3e\x60\x39" "\xa3\x3c\xe4\x59\x64\xff\x21\x67\xf6\xec\xed\xd4\x19\xdb\x06\xc1", 32); if (errtxt) goto failed; - + what = "one million \"a\""; errtxt = _gcry_hash_selftest_check_one (GCRY_MD_SHA256, 1, @@ -495,7 +491,7 @@ run_selftests (int algo, int extended, selftest_report_func_t report) default: ec = GPG_ERR_DIGEST_ALGO; break; - + } return ec; } @@ -512,7 +508,7 @@ static byte asn224[19] = /* Object ID is 2.16.840.1.101.3.4.2.4 */ static gcry_md_oid_spec_t oid_spec_sha224[] = { /* From RFC3874, Section 4 */ - { "2.16.840.1.101.3.4.2.4" }, + { "2.16.840.1.101.3.4.2.4" }, { NULL }, }; @@ -524,7 +520,7 @@ static byte asn256[19] = /* Object ID is 2.16.840.1.101.3.4.2.1 */ static gcry_md_oid_spec_t oid_spec_sha256[] = { /* According to the OpenPGP draft rfc2440-bis06 */ - { "2.16.840.1.101.3.4.2.1" }, + { "2.16.840.1.101.3.4.2.1" }, /* PKCS#1 sha256WithRSAEncryption */ { "1.2.840.113549.1.1.11" }, @@ -533,22 +529,18 @@ static gcry_md_oid_spec_t oid_spec_sha256[] = gcry_md_spec_t _gcry_digest_spec_sha224 = { + GCRY_MD_SHA224, {0, 1}, "SHA224", asn224, DIM (asn224), oid_spec_sha224, 28, - sha224_init, sha256_write, sha256_final, sha256_read, - sizeof (SHA256_CONTEXT) - }; -md_extra_spec_t _gcry_digest_extraspec_sha224 = - { + sha224_init, _gcry_md_block_write, sha256_final, sha256_read, + sizeof (SHA256_CONTEXT), run_selftests }; gcry_md_spec_t _gcry_digest_spec_sha256 = { + GCRY_MD_SHA256, {0, 1}, "SHA256", asn256, DIM (asn256), oid_spec_sha256, 32, - sha256_init, sha256_write, sha256_final, sha256_read, - sizeof (SHA256_CONTEXT) - }; -md_extra_spec_t _gcry_digest_extraspec_sha256 = - { + sha256_init, _gcry_md_block_write, sha256_final, sha256_read, + sizeof (SHA256_CONTEXT), run_selftests }; diff --git a/plugins/MirOTR/Libgcrypt/cipher/sha512.c b/plugins/MirOTR/Libgcrypt/cipher/sha512.c index 59c3e6586e..6f729cc02e 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/sha512.c +++ b/plugins/MirOTR/Libgcrypt/cipher/sha512.c @@ -50,21 +50,83 @@ #include <string.h> #include "g10lib.h" #include "bithelp.h" +#include "bufhelp.h" #include "cipher.h" #include "hash-common.h" + +/* USE_ARM_NEON_ASM indicates whether to enable ARM NEON assembly code. */ +#undef USE_ARM_NEON_ASM +#ifdef ENABLE_NEON_SUPPORT +# if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) \ + && defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) \ + && defined(HAVE_GCC_INLINE_ASM_NEON) +# define USE_ARM_NEON_ASM 1 +# endif +#endif /*ENABLE_NEON_SUPPORT*/ + + +/* USE_SSSE3 indicates whether to compile with Intel SSSE3 code. */ +#undef USE_SSSE3 +#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) && \ + defined(HAVE_GCC_INLINE_ASM_SSSE3) && \ + defined(HAVE_INTEL_SYNTAX_PLATFORM_AS) +# define USE_SSSE3 1 +#endif + + +/* USE_AVX indicates whether to compile with Intel AVX code. */ +#undef USE_AVX +#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) && \ + defined(HAVE_GCC_INLINE_ASM_AVX) && \ + defined(HAVE_INTEL_SYNTAX_PLATFORM_AS) +# define USE_AVX 1 +#endif + + +/* USE_AVX2 indicates whether to compile with Intel AVX2/rorx code. */ +#undef USE_AVX2 +#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) && \ + defined(HAVE_GCC_INLINE_ASM_AVX2) && defined(HAVE_GCC_INLINE_ASM_BMI2) && \ + defined(HAVE_INTEL_SYNTAX_PLATFORM_AS) +# define USE_AVX2 1 +#endif + + typedef struct { u64 h0, h1, h2, h3, h4, h5, h6, h7; - u64 nblocks; - byte buf[128]; - int count; +} SHA512_STATE; + +typedef struct +{ + gcry_md_block_ctx_t bctx; + SHA512_STATE state; +#ifdef USE_ARM_NEON_ASM + unsigned int use_neon:1; +#endif +#ifdef USE_SSSE3 + unsigned int use_ssse3:1; +#endif +#ifdef USE_AVX + unsigned int use_avx:1; +#endif +#ifdef USE_AVX2 + unsigned int use_avx2:1; +#endif } SHA512_CONTEXT; +static unsigned int +transform (void *context, const unsigned char *data); + static void -sha512_init (void *context) +sha512_init (void *context, unsigned int flags) { - SHA512_CONTEXT *hd = context; + SHA512_CONTEXT *ctx = context; + SHA512_STATE *hd = &ctx->state; + unsigned int features = _gcry_get_hw_features (); + + (void)flags; hd->h0 = U64_C(0x6a09e667f3bcc908); hd->h1 = U64_C(0xbb67ae8584caa73b); @@ -75,14 +137,36 @@ sha512_init (void *context) hd->h6 = U64_C(0x1f83d9abfb41bd6b); hd->h7 = U64_C(0x5be0cd19137e2179); - hd->nblocks = 0; - hd->count = 0; + ctx->bctx.nblocks = 0; + ctx->bctx.nblocks_high = 0; + ctx->bctx.count = 0; + ctx->bctx.blocksize = 128; + ctx->bctx.bwrite = transform; + +#ifdef USE_ARM_NEON_ASM + ctx->use_neon = (features & HWF_ARM_NEON) != 0; +#endif +#ifdef USE_SSSE3 + ctx->use_ssse3 = (features & HWF_INTEL_SSSE3) != 0; +#endif +#ifdef USE_AVX + ctx->use_avx = (features & HWF_INTEL_AVX) && (features & HWF_INTEL_CPU); +#endif +#ifdef USE_AVX2 + ctx->use_avx2 = (features & HWF_INTEL_AVX2) && (features & HWF_INTEL_BMI2); +#endif + + (void)features; } static void -sha384_init (void *context) +sha384_init (void *context, unsigned int flags) { - SHA512_CONTEXT *hd = context; + SHA512_CONTEXT *ctx = context; + SHA512_STATE *hd = &ctx->state; + unsigned int features = _gcry_get_hw_features (); + + (void)flags; hd->h0 = U64_C(0xcbbb9d5dc1059ed8); hd->h1 = U64_C(0x629a292a367cd507); @@ -93,8 +177,26 @@ sha384_init (void *context) hd->h6 = U64_C(0xdb0c2e0d64f98fa7); hd->h7 = U64_C(0x47b5481dbefa4fa4); - hd->nblocks = 0; - hd->count = 0; + ctx->bctx.nblocks = 0; + ctx->bctx.nblocks_high = 0; + ctx->bctx.count = 0; + ctx->bctx.blocksize = 128; + ctx->bctx.bwrite = transform; + +#ifdef USE_ARM_NEON_ASM + ctx->use_neon = (features & HWF_ARM_NEON) != 0; +#endif +#ifdef USE_SSSE3 + ctx->use_ssse3 = (features & HWF_INTEL_SSSE3) != 0; +#endif +#ifdef USE_AVX + ctx->use_avx = (features & HWF_INTEL_AVX) && (features & HWF_INTEL_CPU); +#endif +#ifdef USE_AVX2 + ctx->use_avx2 = (features & HWF_INTEL_AVX2) && (features & HWF_INTEL_BMI2); +#endif + + (void)features; } @@ -128,58 +230,59 @@ Sum1 (u64 x) return (ROTR (x, 14) ^ ROTR (x, 18) ^ ROTR (x, 41)); } +static const u64 k[] = + { + U64_C(0x428a2f98d728ae22), U64_C(0x7137449123ef65cd), + U64_C(0xb5c0fbcfec4d3b2f), U64_C(0xe9b5dba58189dbbc), + U64_C(0x3956c25bf348b538), U64_C(0x59f111f1b605d019), + U64_C(0x923f82a4af194f9b), U64_C(0xab1c5ed5da6d8118), + U64_C(0xd807aa98a3030242), U64_C(0x12835b0145706fbe), + U64_C(0x243185be4ee4b28c), U64_C(0x550c7dc3d5ffb4e2), + U64_C(0x72be5d74f27b896f), U64_C(0x80deb1fe3b1696b1), + U64_C(0x9bdc06a725c71235), U64_C(0xc19bf174cf692694), + U64_C(0xe49b69c19ef14ad2), U64_C(0xefbe4786384f25e3), + U64_C(0x0fc19dc68b8cd5b5), U64_C(0x240ca1cc77ac9c65), + U64_C(0x2de92c6f592b0275), U64_C(0x4a7484aa6ea6e483), + U64_C(0x5cb0a9dcbd41fbd4), U64_C(0x76f988da831153b5), + U64_C(0x983e5152ee66dfab), U64_C(0xa831c66d2db43210), + U64_C(0xb00327c898fb213f), U64_C(0xbf597fc7beef0ee4), + U64_C(0xc6e00bf33da88fc2), U64_C(0xd5a79147930aa725), + U64_C(0x06ca6351e003826f), U64_C(0x142929670a0e6e70), + U64_C(0x27b70a8546d22ffc), U64_C(0x2e1b21385c26c926), + U64_C(0x4d2c6dfc5ac42aed), U64_C(0x53380d139d95b3df), + U64_C(0x650a73548baf63de), U64_C(0x766a0abb3c77b2a8), + U64_C(0x81c2c92e47edaee6), U64_C(0x92722c851482353b), + U64_C(0xa2bfe8a14cf10364), U64_C(0xa81a664bbc423001), + U64_C(0xc24b8b70d0f89791), U64_C(0xc76c51a30654be30), + U64_C(0xd192e819d6ef5218), U64_C(0xd69906245565a910), + U64_C(0xf40e35855771202a), U64_C(0x106aa07032bbd1b8), + U64_C(0x19a4c116b8d2d0c8), U64_C(0x1e376c085141ab53), + U64_C(0x2748774cdf8eeb99), U64_C(0x34b0bcb5e19b48a8), + U64_C(0x391c0cb3c5c95a63), U64_C(0x4ed8aa4ae3418acb), + U64_C(0x5b9cca4f7763e373), U64_C(0x682e6ff3d6b2b8a3), + U64_C(0x748f82ee5defb2fc), U64_C(0x78a5636f43172f60), + U64_C(0x84c87814a1f0ab72), U64_C(0x8cc702081a6439ec), + U64_C(0x90befffa23631e28), U64_C(0xa4506cebde82bde9), + U64_C(0xbef9a3f7b2c67915), U64_C(0xc67178f2e372532b), + U64_C(0xca273eceea26619c), U64_C(0xd186b8c721c0c207), + U64_C(0xeada7dd6cde0eb1e), U64_C(0xf57d4f7fee6ed178), + U64_C(0x06f067aa72176fba), U64_C(0x0a637dc5a2c898a6), + U64_C(0x113f9804bef90dae), U64_C(0x1b710b35131c471b), + U64_C(0x28db77f523047d84), U64_C(0x32caab7b40c72493), + U64_C(0x3c9ebe0a15c9bebc), U64_C(0x431d67c49c100d4c), + U64_C(0x4cc5d4becb3e42b6), U64_C(0x597f299cfc657e2a), + U64_C(0x5fcb6fab3ad6faec), U64_C(0x6c44198c4a475817) + }; + /**************** * Transform the message W which consists of 16 64-bit-words */ -static void -transform (SHA512_CONTEXT *hd, const unsigned char *data) +static unsigned int +__transform (SHA512_STATE *hd, const unsigned char *data) { u64 a, b, c, d, e, f, g, h; - u64 w[80]; + u64 w[16]; int t; - static const u64 k[] = - { - U64_C(0x428a2f98d728ae22), U64_C(0x7137449123ef65cd), - U64_C(0xb5c0fbcfec4d3b2f), U64_C(0xe9b5dba58189dbbc), - U64_C(0x3956c25bf348b538), U64_C(0x59f111f1b605d019), - U64_C(0x923f82a4af194f9b), U64_C(0xab1c5ed5da6d8118), - U64_C(0xd807aa98a3030242), U64_C(0x12835b0145706fbe), - U64_C(0x243185be4ee4b28c), U64_C(0x550c7dc3d5ffb4e2), - U64_C(0x72be5d74f27b896f), U64_C(0x80deb1fe3b1696b1), - U64_C(0x9bdc06a725c71235), U64_C(0xc19bf174cf692694), - U64_C(0xe49b69c19ef14ad2), U64_C(0xefbe4786384f25e3), - U64_C(0x0fc19dc68b8cd5b5), U64_C(0x240ca1cc77ac9c65), - U64_C(0x2de92c6f592b0275), U64_C(0x4a7484aa6ea6e483), - U64_C(0x5cb0a9dcbd41fbd4), U64_C(0x76f988da831153b5), - U64_C(0x983e5152ee66dfab), U64_C(0xa831c66d2db43210), - U64_C(0xb00327c898fb213f), U64_C(0xbf597fc7beef0ee4), - U64_C(0xc6e00bf33da88fc2), U64_C(0xd5a79147930aa725), - U64_C(0x06ca6351e003826f), U64_C(0x142929670a0e6e70), - U64_C(0x27b70a8546d22ffc), U64_C(0x2e1b21385c26c926), - U64_C(0x4d2c6dfc5ac42aed), U64_C(0x53380d139d95b3df), - U64_C(0x650a73548baf63de), U64_C(0x766a0abb3c77b2a8), - U64_C(0x81c2c92e47edaee6), U64_C(0x92722c851482353b), - U64_C(0xa2bfe8a14cf10364), U64_C(0xa81a664bbc423001), - U64_C(0xc24b8b70d0f89791), U64_C(0xc76c51a30654be30), - U64_C(0xd192e819d6ef5218), U64_C(0xd69906245565a910), - U64_C(0xf40e35855771202a), U64_C(0x106aa07032bbd1b8), - U64_C(0x19a4c116b8d2d0c8), U64_C(0x1e376c085141ab53), - U64_C(0x2748774cdf8eeb99), U64_C(0x34b0bcb5e19b48a8), - U64_C(0x391c0cb3c5c95a63), U64_C(0x4ed8aa4ae3418acb), - U64_C(0x5b9cca4f7763e373), U64_C(0x682e6ff3d6b2b8a3), - U64_C(0x748f82ee5defb2fc), U64_C(0x78a5636f43172f60), - U64_C(0x84c87814a1f0ab72), U64_C(0x8cc702081a6439ec), - U64_C(0x90befffa23631e28), U64_C(0xa4506cebde82bde9), - U64_C(0xbef9a3f7b2c67915), U64_C(0xc67178f2e372532b), - U64_C(0xca273eceea26619c), U64_C(0xd186b8c721c0c207), - U64_C(0xeada7dd6cde0eb1e), U64_C(0xf57d4f7fee6ed178), - U64_C(0x06f067aa72176fba), U64_C(0x0a637dc5a2c898a6), - U64_C(0x113f9804bef90dae), U64_C(0x1b710b35131c471b), - U64_C(0x28db77f523047d84), U64_C(0x32caab7b40c72493), - U64_C(0x3c9ebe0a15c9bebc), U64_C(0x431d67c49c100d4c), - U64_C(0x4cc5d4becb3e42b6), U64_C(0x597f299cfc657e2a), - U64_C(0x5fcb6fab3ad6faec), U64_C(0x6c44198c4a475817) - }; /* get values from the chaining vars */ a = hd->h0; @@ -191,35 +294,14 @@ transform (SHA512_CONTEXT *hd, const unsigned char *data) g = hd->h6; h = hd->h7; -#ifdef WORDS_BIGENDIAN - memcpy (w, data, 128); -#else - { - int i; - byte *p2; - - for (i = 0, p2 = (byte *) w; i < 16; i++, p2 += 8) - { - p2[7] = *data++; - p2[6] = *data++; - p2[5] = *data++; - p2[4] = *data++; - p2[3] = *data++; - p2[2] = *data++; - p2[1] = *data++; - p2[0] = *data++; - } - } -#endif + for ( t = 0; t < 16; t++ ) + w[t] = buf_get_be64(data + t * 8); #define S0(x) (ROTR((x),1) ^ ROTR((x),8) ^ ((x)>>7)) #define S1(x) (ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6)) - for (t = 16; t < 80; t++) - w[t] = S1 (w[t - 2]) + w[t - 7] + S0 (w[t - 15]) + w[t - 16]; - - for (t = 0; t < 80; ) + for (t = 0; t < 80 - 16; ) { u64 t1, t2; @@ -232,7 +314,8 @@ transform (SHA512_CONTEXT *hd, const unsigned char *data) Unrolled with inline: 330ms */ #if 0 /* Not unrolled. */ - t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[t]; + t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[t%16]; + w[t%16] += S1 (w[(t - 2)%16]) + w[(t - 7)%16] + S0 (w[(t - 15)%16]); t2 = Sum0 (a) + Maj (a, b, c); h = g; g = f; @@ -244,47 +327,204 @@ transform (SHA512_CONTEXT *hd, const unsigned char *data) a = t1 + t2; t++; #else /* Unrolled to interweave the chain variables. */ - t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[t]; + t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[0]; + w[0] += S1 (w[14]) + w[9] + S0 (w[1]); + t2 = Sum0 (a) + Maj (a, b, c); + d += t1; + h = t1 + t2; + + t1 = g + Sum1 (d) + Ch (d, e, f) + k[t+1] + w[1]; + w[1] += S1 (w[15]) + w[10] + S0 (w[2]); + t2 = Sum0 (h) + Maj (h, a, b); + c += t1; + g = t1 + t2; + + t1 = f + Sum1 (c) + Ch (c, d, e) + k[t+2] + w[2]; + w[2] += S1 (w[0]) + w[11] + S0 (w[3]); + t2 = Sum0 (g) + Maj (g, h, a); + b += t1; + f = t1 + t2; + + t1 = e + Sum1 (b) + Ch (b, c, d) + k[t+3] + w[3]; + w[3] += S1 (w[1]) + w[12] + S0 (w[4]); + t2 = Sum0 (f) + Maj (f, g, h); + a += t1; + e = t1 + t2; + + t1 = d + Sum1 (a) + Ch (a, b, c) + k[t+4] + w[4]; + w[4] += S1 (w[2]) + w[13] + S0 (w[5]); + t2 = Sum0 (e) + Maj (e, f, g); + h += t1; + d = t1 + t2; + + t1 = c + Sum1 (h) + Ch (h, a, b) + k[t+5] + w[5]; + w[5] += S1 (w[3]) + w[14] + S0 (w[6]); + t2 = Sum0 (d) + Maj (d, e, f); + g += t1; + c = t1 + t2; + + t1 = b + Sum1 (g) + Ch (g, h, a) + k[t+6] + w[6]; + w[6] += S1 (w[4]) + w[15] + S0 (w[7]); + t2 = Sum0 (c) + Maj (c, d, e); + f += t1; + b = t1 + t2; + + t1 = a + Sum1 (f) + Ch (f, g, h) + k[t+7] + w[7]; + w[7] += S1 (w[5]) + w[0] + S0 (w[8]); + t2 = Sum0 (b) + Maj (b, c, d); + e += t1; + a = t1 + t2; + + t1 = h + Sum1 (e) + Ch (e, f, g) + k[t+8] + w[8]; + w[8] += S1 (w[6]) + w[1] + S0 (w[9]); t2 = Sum0 (a) + Maj (a, b, c); d += t1; h = t1 + t2; - t1 = g + Sum1 (d) + Ch (d, e, f) + k[t+1] + w[t+1]; + t1 = g + Sum1 (d) + Ch (d, e, f) + k[t+9] + w[9]; + w[9] += S1 (w[7]) + w[2] + S0 (w[10]); t2 = Sum0 (h) + Maj (h, a, b); c += t1; g = t1 + t2; - t1 = f + Sum1 (c) + Ch (c, d, e) + k[t+2] + w[t+2]; + t1 = f + Sum1 (c) + Ch (c, d, e) + k[t+10] + w[10]; + w[10] += S1 (w[8]) + w[3] + S0 (w[11]); t2 = Sum0 (g) + Maj (g, h, a); b += t1; f = t1 + t2; - t1 = e + Sum1 (b) + Ch (b, c, d) + k[t+3] + w[t+3]; + t1 = e + Sum1 (b) + Ch (b, c, d) + k[t+11] + w[11]; + w[11] += S1 (w[9]) + w[4] + S0 (w[12]); t2 = Sum0 (f) + Maj (f, g, h); a += t1; e = t1 + t2; - t1 = d + Sum1 (a) + Ch (a, b, c) + k[t+4] + w[t+4]; + t1 = d + Sum1 (a) + Ch (a, b, c) + k[t+12] + w[12]; + w[12] += S1 (w[10]) + w[5] + S0 (w[13]); t2 = Sum0 (e) + Maj (e, f, g); h += t1; d = t1 + t2; - t1 = c + Sum1 (h) + Ch (h, a, b) + k[t+5] + w[t+5]; + t1 = c + Sum1 (h) + Ch (h, a, b) + k[t+13] + w[13]; + w[13] += S1 (w[11]) + w[6] + S0 (w[14]); t2 = Sum0 (d) + Maj (d, e, f); g += t1; c = t1 + t2; - t1 = b + Sum1 (g) + Ch (g, h, a) + k[t+6] + w[t+6]; + t1 = b + Sum1 (g) + Ch (g, h, a) + k[t+14] + w[14]; + w[14] += S1 (w[12]) + w[7] + S0 (w[15]); t2 = Sum0 (c) + Maj (c, d, e); f += t1; b = t1 + t2; - t1 = a + Sum1 (f) + Ch (f, g, h) + k[t+7] + w[t+7]; + t1 = a + Sum1 (f) + Ch (f, g, h) + k[t+15] + w[15]; + w[15] += S1 (w[13]) + w[8] + S0 (w[0]); t2 = Sum0 (b) + Maj (b, c, d); e += t1; a = t1 + t2; - - t += 8; + + t += 16; +#endif + } + + for (; t < 80; ) + { + u64 t1, t2; + +#if 0 /* Not unrolled. */ + t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[t%16]; + t2 = Sum0 (a) + Maj (a, b, c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; +#else /* Unrolled to interweave the chain variables. */ + t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[0]; + t2 = Sum0 (a) + Maj (a, b, c); + d += t1; + h = t1 + t2; + + t1 = g + Sum1 (d) + Ch (d, e, f) + k[t+1] + w[1]; + t2 = Sum0 (h) + Maj (h, a, b); + c += t1; + g = t1 + t2; + + t1 = f + Sum1 (c) + Ch (c, d, e) + k[t+2] + w[2]; + t2 = Sum0 (g) + Maj (g, h, a); + b += t1; + f = t1 + t2; + + t1 = e + Sum1 (b) + Ch (b, c, d) + k[t+3] + w[3]; + t2 = Sum0 (f) + Maj (f, g, h); + a += t1; + e = t1 + t2; + + t1 = d + Sum1 (a) + Ch (a, b, c) + k[t+4] + w[4]; + t2 = Sum0 (e) + Maj (e, f, g); + h += t1; + d = t1 + t2; + + t1 = c + Sum1 (h) + Ch (h, a, b) + k[t+5] + w[5]; + t2 = Sum0 (d) + Maj (d, e, f); + g += t1; + c = t1 + t2; + + t1 = b + Sum1 (g) + Ch (g, h, a) + k[t+6] + w[6]; + t2 = Sum0 (c) + Maj (c, d, e); + f += t1; + b = t1 + t2; + + t1 = a + Sum1 (f) + Ch (f, g, h) + k[t+7] + w[7]; + t2 = Sum0 (b) + Maj (b, c, d); + e += t1; + a = t1 + t2; + + t1 = h + Sum1 (e) + Ch (e, f, g) + k[t+8] + w[8]; + t2 = Sum0 (a) + Maj (a, b, c); + d += t1; + h = t1 + t2; + + t1 = g + Sum1 (d) + Ch (d, e, f) + k[t+9] + w[9]; + t2 = Sum0 (h) + Maj (h, a, b); + c += t1; + g = t1 + t2; + + t1 = f + Sum1 (c) + Ch (c, d, e) + k[t+10] + w[10]; + t2 = Sum0 (g) + Maj (g, h, a); + b += t1; + f = t1 + t2; + + t1 = e + Sum1 (b) + Ch (b, c, d) + k[t+11] + w[11]; + t2 = Sum0 (f) + Maj (f, g, h); + a += t1; + e = t1 + t2; + + t1 = d + Sum1 (a) + Ch (a, b, c) + k[t+12] + w[12]; + t2 = Sum0 (e) + Maj (e, f, g); + h += t1; + d = t1 + t2; + + t1 = c + Sum1 (h) + Ch (h, a, b) + k[t+13] + w[13]; + t2 = Sum0 (d) + Maj (d, e, f); + g += t1; + c = t1 + t2; + + t1 = b + Sum1 (g) + Ch (g, h, a) + k[t+14] + w[14]; + t2 = Sum0 (c) + Maj (c, d, e); + f += t1; + b = t1 + t2; + + t1 = a + Sum1 (f) + Ch (f, g, h) + k[t+15] + w[15]; + t2 = Sum0 (b) + Maj (b, c, d); + e += t1; + a = t1 + t2; + + t += 16; #endif } @@ -297,47 +537,69 @@ transform (SHA512_CONTEXT *hd, const unsigned char *data) hd->h5 += f; hd->h6 += g; hd->h7 += h; + + return /* burn_stack */ (8 + 16) * sizeof(u64) + sizeof(u32) + + 3 * sizeof(void*); } -/* Update the message digest with the contents - * of INBUF with length INLEN. - */ -static void -sha512_write (void *context, const void *inbuf_arg, size_t inlen) +#ifdef USE_ARM_NEON_ASM +void _gcry_sha512_transform_armv7_neon (SHA512_STATE *hd, + const unsigned char *data, + const u64 k[]); +#endif + +#ifdef USE_SSSE3 +unsigned int _gcry_sha512_transform_amd64_ssse3(const void *input_data, + void *state, size_t num_blks); +#endif + +#ifdef USE_AVX +unsigned int _gcry_sha512_transform_amd64_avx(const void *input_data, + void *state, size_t num_blks); +#endif + +#ifdef USE_AVX2 +unsigned int _gcry_sha512_transform_amd64_avx2(const void *input_data, + void *state, size_t num_blks); +#endif + + +static unsigned int +transform (void *context, const unsigned char *data) { - const unsigned char *inbuf = inbuf_arg; - SHA512_CONTEXT *hd = context; + SHA512_CONTEXT *ctx = context; - if (hd->count == 128) - { /* flush the buffer */ - transform (hd, hd->buf); - _gcry_burn_stack (768); - hd->count = 0; - hd->nblocks++; - } - if (!inbuf) - return; - if (hd->count) - { - for (; inlen && hd->count < 128; inlen--) - hd->buf[hd->count++] = *inbuf++; - sha512_write (context, NULL, 0); - if (!inlen) - return; - } +#ifdef USE_AVX2 + if (ctx->use_avx2) + return _gcry_sha512_transform_amd64_avx2 (data, &ctx->state, 1) + + 4 * sizeof(void*); +#endif - while (inlen >= 128) +#ifdef USE_AVX + if (ctx->use_avx) + return _gcry_sha512_transform_amd64_avx (data, &ctx->state, 1) + + 4 * sizeof(void*); +#endif + +#ifdef USE_SSSE3 + if (ctx->use_ssse3) + return _gcry_sha512_transform_amd64_ssse3 (data, &ctx->state, 1) + + 4 * sizeof(void*); +#endif + +#ifdef USE_ARM_NEON_ASM + if (ctx->use_neon) { - transform (hd, inbuf); - hd->count = 0; - hd->nblocks++; - inlen -= 128; - inbuf += 128; + _gcry_sha512_transform_armv7_neon (&ctx->state, data, k); + + /* _gcry_sha512_transform_armv7_neon does not store sensitive data + * to stack. */ + return /* no burn_stack */ 0; } - _gcry_burn_stack (768); - for (; inlen && hd->count < 128; inlen--) - hd->buf[hd->count++] = *inbuf++; +#endif + + return __transform (&ctx->state, data) + 3 * sizeof(void*); } @@ -353,18 +615,24 @@ static void sha512_final (void *context) { SHA512_CONTEXT *hd = context; - u64 t, msb, lsb; + unsigned int stack_burn_depth; + u64 t, th, msb, lsb; byte *p; - sha512_write (context, NULL, 0); /* flush */ ; + _gcry_md_block_write (context, NULL, 0); /* flush */ ; + + t = hd->bctx.nblocks; + /* if (sizeof t == sizeof hd->bctx.nblocks) */ + th = hd->bctx.nblocks_high; + /* else */ + /* th = hd->bctx.nblocks >> 64; In case we ever use u128 */ - t = hd->nblocks; /* multiply by 128 to make a byte count */ lsb = t << 7; - msb = t >> 57; + msb = (th << 7) | (t >> 57); /* add the count */ t = lsb; - if ((lsb += hd->count) < t) + if ((lsb += hd->bctx.count) < t) msb++; /* multiply by 8 to make a bit count */ t = lsb; @@ -372,50 +640,28 @@ sha512_final (void *context) msb <<= 3; msb |= t >> 61; - if (hd->count < 112) + if (hd->bctx.count < 112) { /* enough room */ - hd->buf[hd->count++] = 0x80; /* pad */ - while (hd->count < 112) - hd->buf[hd->count++] = 0; /* pad */ + hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad */ + while (hd->bctx.count < 112) + hd->bctx.buf[hd->bctx.count++] = 0; /* pad */ } else { /* need one extra block */ - hd->buf[hd->count++] = 0x80; /* pad character */ - while (hd->count < 128) - hd->buf[hd->count++] = 0; - sha512_write (context, NULL, 0); /* flush */ ; - memset (hd->buf, 0, 112); /* fill next block with zeroes */ + hd->bctx.buf[hd->bctx.count++] = 0x80; /* pad character */ + while (hd->bctx.count < 128) + hd->bctx.buf[hd->bctx.count++] = 0; + _gcry_md_block_write (context, NULL, 0); /* flush */ ; + memset (hd->bctx.buf, 0, 112); /* fill next block with zeroes */ } /* append the 128 bit count */ - hd->buf[112] = msb >> 56; - hd->buf[113] = msb >> 48; - hd->buf[114] = msb >> 40; - hd->buf[115] = msb >> 32; - hd->buf[116] = msb >> 24; - hd->buf[117] = msb >> 16; - hd->buf[118] = msb >> 8; - hd->buf[119] = msb; - - hd->buf[120] = lsb >> 56; - hd->buf[121] = lsb >> 48; - hd->buf[122] = lsb >> 40; - hd->buf[123] = lsb >> 32; - hd->buf[124] = lsb >> 24; - hd->buf[125] = lsb >> 16; - hd->buf[126] = lsb >> 8; - hd->buf[127] = lsb; - transform (hd, hd->buf); - _gcry_burn_stack (768); - - p = hd->buf; -#ifdef WORDS_BIGENDIAN -#define X(a) do { *(u64*)p = hd->h##a ; p += 8; } while (0) -#else /* little endian */ -#define X(a) do { *p++ = hd->h##a >> 56; *p++ = hd->h##a >> 48; \ - *p++ = hd->h##a >> 40; *p++ = hd->h##a >> 32; \ - *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16; \ - *p++ = hd->h##a >> 8; *p++ = hd->h##a; } while (0) -#endif + buf_put_be64(hd->bctx.buf + 112, msb); + buf_put_be64(hd->bctx.buf + 120, lsb); + stack_burn_depth = transform (hd, hd->bctx.buf); + _gcry_burn_stack (stack_burn_depth); + + p = hd->bctx.buf; +#define X(a) do { *(u64*)p = be_bswap64(hd->state.h##a) ; p += 8; } while (0) X (0); X (1); X (2); @@ -433,12 +679,12 @@ static byte * sha512_read (void *context) { SHA512_CONTEXT *hd = (SHA512_CONTEXT *) context; - return hd->buf; + return hd->bctx.buf; } -/* +/* Self-test section. */ @@ -448,10 +694,10 @@ selftests_sha384 (int extended, selftest_report_func_t report) { const char *what; const char *errtxt; - + what = "short string"; errtxt = _gcry_hash_selftest_check_one - (GCRY_MD_SHA384, 0, + (GCRY_MD_SHA384, 0, "abc", 3, "\xcb\x00\x75\x3f\x45\xa3\x5e\x8b\xb5\xa0\x3d\x69\x9a\xc6\x50\x07" "\x27\x2c\x32\xab\x0e\xde\xd1\x63\x1a\x8b\x60\x5a\x43\xff\x5b\xed" @@ -463,9 +709,9 @@ selftests_sha384 (int extended, selftest_report_func_t report) { what = "long string"; errtxt = _gcry_hash_selftest_check_one - (GCRY_MD_SHA384, 0, + (GCRY_MD_SHA384, 0, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" - "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, "\x09\x33\x0C\x33\xF7\x11\x47\xE8\x3D\x19\x2F\xC7\x82\xCD\x1B\x47" "\x53\x11\x1B\x17\x3B\x3B\x05\xD2\x2F\xA0\x80\x86\xE3\xB0\xF7\x12" "\xFC\xC7\xC7\x1A\x55\x7E\x2D\xB9\x66\xC3\xE9\xFA\x91\x74\x60\x39", @@ -498,10 +744,10 @@ selftests_sha512 (int extended, selftest_report_func_t report) { const char *what; const char *errtxt; - + what = "short string"; errtxt = _gcry_hash_selftest_check_one - (GCRY_MD_SHA512, 0, + (GCRY_MD_SHA512, 0, "abc", 3, "\xDD\xAF\x35\xA1\x93\x61\x7A\xBA\xCC\x41\x73\x49\xAE\x20\x41\x31" "\x12\xE6\xFA\x4E\x89\xA9\x7E\xA2\x0A\x9E\xEE\xE6\x4B\x55\xD3\x9A" @@ -514,9 +760,9 @@ selftests_sha512 (int extended, selftest_report_func_t report) { what = "long string"; errtxt = _gcry_hash_selftest_check_one - (GCRY_MD_SHA512, 0, + (GCRY_MD_SHA512, 0, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" - "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, "\x8E\x95\x9B\x75\xDA\xE3\x13\xDA\x8C\xF4\xF7\x28\x14\xFC\x14\x3F" "\x8F\x77\x79\xC6\xEB\x9F\x7F\xA1\x72\x99\xAE\xAD\xB6\x88\x90\x18" "\x50\x1D\x28\x9E\x49\x00\xF7\xE4\x33\x1B\x99\xDE\xC4\xB5\x43\x3A" @@ -524,7 +770,7 @@ selftests_sha512 (int extended, selftest_report_func_t report) 64); if (errtxt) goto failed; - + what = "one million \"a\""; errtxt = _gcry_hash_selftest_check_one (GCRY_MD_SHA512, 1, @@ -564,7 +810,7 @@ run_selftests (int algo, int extended, selftest_report_func_t report) default: ec = GPG_ERR_DIGEST_ALGO; break; - + } return ec; } @@ -589,14 +835,12 @@ static gcry_md_oid_spec_t oid_spec_sha512[] = { NULL } }; -gcry_md_spec_t _gcry_digest_spec_sha512 = +gcry_md_spec_t _gcry_digest_spec_sha512 = { + GCRY_MD_SHA512, {0, 1}, "SHA512", sha512_asn, DIM (sha512_asn), oid_spec_sha512, 64, - sha512_init, sha512_write, sha512_final, sha512_read, + sha512_init, _gcry_md_block_write, sha512_final, sha512_read, sizeof (SHA512_CONTEXT), - }; -md_extra_spec_t _gcry_digest_extraspec_sha512 = - { run_selftests }; @@ -609,7 +853,7 @@ static byte sha384_asn[] = /* Object ID is 2.16.840.1.101.3.4.2.2 */ static gcry_md_oid_spec_t oid_spec_sha384[] = { - { "2.16.840.1.101.3.4.2.2" }, + { "2.16.840.1.101.3.4.2.2" }, /* PKCS#1 sha384WithRSAEncryption */ { "1.2.840.113549.1.1.12" }, @@ -617,13 +861,11 @@ static gcry_md_oid_spec_t oid_spec_sha384[] = { NULL }, }; -gcry_md_spec_t _gcry_digest_spec_sha384 = +gcry_md_spec_t _gcry_digest_spec_sha384 = { + GCRY_MD_SHA384, {0, 1}, "SHA384", sha384_asn, DIM (sha384_asn), oid_spec_sha384, 48, - sha384_init, sha512_write, sha512_final, sha512_read, + sha384_init, _gcry_md_block_write, sha512_final, sha512_read, sizeof (SHA512_CONTEXT), - }; -md_extra_spec_t _gcry_digest_extraspec_sha384 = - { run_selftests }; diff --git a/plugins/MirOTR/Libgcrypt/cipher/stribog.c b/plugins/MirOTR/Libgcrypt/cipher/stribog.c new file mode 100644 index 0000000000..e277cd642c --- /dev/null +++ b/plugins/MirOTR/Libgcrypt/cipher/stribog.c @@ -0,0 +1,1323 @@ +/* stribog.c - GOST R 34.11-2012 (Stribog) hash function + * Copyright (C) 2013 Dmitry Eremin-Solenikov + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "g10lib.h" +#include "bithelp.h" +#include "bufhelp.h" +#include "cipher.h" +#include "hash-common.h" + + +typedef struct +{ + gcry_md_block_ctx_t bctx; + union + { + u64 h[8]; + unsigned char result[64]; + }; + u64 N[8]; + u64 Sigma[8]; +} STRIBOG_CONTEXT; + + +/* Pre-computed results of multiplication of bytes on A and reordered with + Pi[]. */ +static const u64 stribog_table[8][256] = +{ + /* 0 */ + { U64_C(0xd01f715b5c7ef8e6), U64_C(0x16fa240980778325), + U64_C(0xa8a42e857ee049c8), U64_C(0x6ac1068fa186465b), + U64_C(0x6e417bd7a2e9320b), U64_C(0x665c8167a437daab), + U64_C(0x7666681aa89617f6), U64_C(0x4b959163700bdcf5), + U64_C(0xf14be6b78df36248), U64_C(0xc585bd689a625cff), + U64_C(0x9557d7fca67d82cb), U64_C(0x89f0b969af6dd366), + U64_C(0xb0833d48749f6c35), U64_C(0xa1998c23b1ecbc7c), + U64_C(0x8d70c431ac02a736), U64_C(0xd6dfbc2fd0a8b69e), + U64_C(0x37aeb3e551fa198b), U64_C(0x0b7d128a40b5cf9c), + U64_C(0x5a8f2008b5780cbc), U64_C(0xedec882284e333e5), + U64_C(0xd25fc177d3c7c2ce), U64_C(0x5e0f5d50b61778ec), + U64_C(0x1d873683c0c24cb9), U64_C(0xad040bcbb45d208c), + U64_C(0x2f89a0285b853c76), U64_C(0x5732fff6791b8d58), + U64_C(0x3e9311439ef6ec3f), U64_C(0xc9183a809fd3c00f), + U64_C(0x83adf3f5260a01ee), U64_C(0xa6791941f4e8ef10), + U64_C(0x103ae97d0ca1cd5d), U64_C(0x2ce948121dee1b4a), + U64_C(0x39738421dbf2bf53), U64_C(0x093da2a6cf0cf5b4), + U64_C(0xcd9847d89cbcb45f), U64_C(0xf9561c078b2d8ae8), + U64_C(0x9c6a755a6971777f), U64_C(0xbc1ebaa0712ef0c5), + U64_C(0x72e61542abf963a6), U64_C(0x78bb5fde229eb12e), + U64_C(0x14ba94250fceb90d), U64_C(0x844d6697630e5282), + U64_C(0x98ea08026a1e032f), U64_C(0xf06bbea144217f5c), + U64_C(0xdb6263d11ccb377a), U64_C(0x641c314b2b8ee083), + U64_C(0x320e96ab9b4770cf), U64_C(0x1ee7deb986a96b85), + U64_C(0xe96cf57a878c47b5), U64_C(0xfdd6615f8842feb8), + U64_C(0xc83862965601dd1b), U64_C(0x2ea9f83e92572162), + U64_C(0xf876441142ff97fc), U64_C(0xeb2c455608357d9d), + U64_C(0x5612a7e0b0c9904c), U64_C(0x6c01cbfb2d500823), + U64_C(0x4548a6a7fa037a2d), U64_C(0xabc4c6bf388b6ef4), + U64_C(0xbade77d4fdf8bebd), U64_C(0x799b07c8eb4cac3a), + U64_C(0x0c9d87e805b19cf0), U64_C(0xcb588aac106afa27), + U64_C(0xea0c1d40c1e76089), U64_C(0x2869354a1e816f1a), + U64_C(0xff96d17307fbc490), U64_C(0x9f0a9d602f1a5043), + U64_C(0x96373fc6e016a5f7), U64_C(0x5292dab8b3a6e41c), + U64_C(0x9b8ae0382c752413), U64_C(0x4f15ec3b7364a8a5), + U64_C(0x3fb349555724f12b), U64_C(0xc7c50d4415db66d7), + U64_C(0x92b7429ee379d1a7), U64_C(0xd37f99611a15dfda), + U64_C(0x231427c05e34a086), U64_C(0xa439a96d7b51d538), + U64_C(0xb403401077f01865), U64_C(0xdda2aea5901d7902), + U64_C(0x0a5d4a9c8967d288), U64_C(0xc265280adf660f93), + U64_C(0x8bb0094520d4e94e), U64_C(0x2a29856691385532), + U64_C(0x42a833c5bf072941), U64_C(0x73c64d54622b7eb2), + U64_C(0x07e095624504536c), U64_C(0x8a905153e906f45a), + U64_C(0x6f6123c16b3b2f1f), U64_C(0xc6e55552dc097bc3), + U64_C(0x4468feb133d16739), U64_C(0xe211e7f0c7398829), + U64_C(0xa2f96419f7879b40), U64_C(0x19074bdbc3ad38e9), + U64_C(0xf4ebc3f9474e0b0c), U64_C(0x43886bd376d53455), + U64_C(0xd8028beb5aa01046), U64_C(0x51f23282f5cdc320), + U64_C(0xe7b1c2be0d84e16d), U64_C(0x081dfab006dee8a0), + U64_C(0x3b33340d544b857b), U64_C(0x7f5bcabc679ae242), + U64_C(0x0edd37c48a08a6d8), U64_C(0x81ed43d9a9b33bc6), + U64_C(0xb1a3655ebd4d7121), U64_C(0x69a1eeb5e7ed6167), + U64_C(0xf6ab73d5c8f73124), U64_C(0x1a67a3e185c61fd5), + U64_C(0x2dc91004d43c065e), U64_C(0x0240b02c8fb93a28), + U64_C(0x90f7f2b26cc0eb8f), U64_C(0x3cd3a16f114fd617), + U64_C(0xaae49ea9f15973e0), U64_C(0x06c0cd748cd64e78), + U64_C(0xda423bc7d5192a6e), U64_C(0xc345701c16b41287), + U64_C(0x6d2193ede4821537), U64_C(0xfcf639494190e3ac), + U64_C(0x7c3b228621f1c57e), U64_C(0xfb16ac2b0494b0c0), + U64_C(0xbf7e529a3745d7f9), U64_C(0x6881b6a32e3f7c73), + U64_C(0xca78d2bad9b8e733), U64_C(0xbbfe2fc2342aa3a9), + U64_C(0x0dbddffecc6381e4), U64_C(0x70a6a56e2440598e), + U64_C(0xe4d12a844befc651), U64_C(0x8c509c2765d0ba22), + U64_C(0xee8c6018c28814d9), U64_C(0x17da7c1f49a59e31), + U64_C(0x609c4c1328e194d3), U64_C(0xb3e3d57232f44b09), + U64_C(0x91d7aaa4a512f69b), U64_C(0x0ffd6fd243dabbcc), + U64_C(0x50d26a943c1fde34), U64_C(0x6be15e9968545b4f), + U64_C(0x94778fea6faf9fdf), U64_C(0x2b09dd7058ea4826), + U64_C(0x677cd9716de5c7bf), U64_C(0x49d5214fffb2e6dd), + U64_C(0x0360e83a466b273c), U64_C(0x1fc786af4f7b7691), + U64_C(0xa0b9d435783ea168), U64_C(0xd49f0c035f118cb6), + U64_C(0x01205816c9d21d14), U64_C(0xac2453dd7d8f3d98), + U64_C(0x545217cc3f70aa64), U64_C(0x26b4028e9489c9c2), + U64_C(0xdec2469fd6765e3e), U64_C(0x04807d58036f7450), + U64_C(0xe5f17292823ddb45), U64_C(0xf30b569b024a5860), + U64_C(0x62dcfc3fa758aefb), U64_C(0xe84cad6c4e5e5aa1), + U64_C(0xccb81fce556ea94b), U64_C(0x53b282ae7a74f908), + U64_C(0x1b47fbf74c1402c1), U64_C(0x368eebf39828049f), + U64_C(0x7afbeff2ad278b06), U64_C(0xbe5e0a8cfe97caed), + U64_C(0xcfd8f7f413058e77), U64_C(0xf78b2bc301252c30), + U64_C(0x4d555c17fcdd928d), U64_C(0x5f2f05467fc565f8), + U64_C(0x24f4b2a21b30f3ea), U64_C(0x860dd6bbecb768aa), + U64_C(0x4c750401350f8f99), U64_C(0x0000000000000000), + U64_C(0xecccd0344d312ef1), U64_C(0xb5231806be220571), + U64_C(0xc105c030990d28af), U64_C(0x653c695de25cfd97), + U64_C(0x159acc33c61ca419), U64_C(0xb89ec7f872418495), + U64_C(0xa9847693b73254dc), U64_C(0x58cf90243ac13694), + U64_C(0x59efc832f3132b80), U64_C(0x5c4fed7c39ae42c4), + U64_C(0x828dabe3efd81cfa), U64_C(0xd13f294d95ace5f2), + U64_C(0x7d1b7a90e823d86a), U64_C(0xb643f03cf849224d), + U64_C(0x3df3f979d89dcb03), U64_C(0x7426d836272f2dde), + U64_C(0xdfe21e891fa4432a), U64_C(0x3a136c1b9d99986f), + U64_C(0xfa36f43dcd46add4), U64_C(0xc025982650df35bb), + U64_C(0x856d3e81aadc4f96), U64_C(0xc4a5e57e53b041eb), + U64_C(0x4708168b75ba4005), U64_C(0xaf44bbe73be41aa4), + U64_C(0x971767d029c4b8e3), U64_C(0xb9be9feebb939981), + U64_C(0x215497ecd18d9aae), U64_C(0x316e7e91dd2c57f3), + U64_C(0xcef8afe2dad79363), U64_C(0x3853dc371220a247), + U64_C(0x35ee03c9de4323a3), U64_C(0xe6919aa8c456fc79), + U64_C(0xe05157dc4880b201), U64_C(0x7bdbb7e464f59612), + U64_C(0x127a59518318f775), U64_C(0x332ecebd52956ddb), + U64_C(0x8f30741d23bb9d1e), U64_C(0xd922d3fd93720d52), + U64_C(0x7746300c61440ae2), U64_C(0x25d4eab4d2e2eefe), + U64_C(0x75068020eefd30ca), U64_C(0x135a01474acaea61), + U64_C(0x304e268714fe4ae7), U64_C(0xa519f17bb283c82c), + U64_C(0xdc82f6b359cf6416), U64_C(0x5baf781e7caa11a8), + U64_C(0xb2c38d64fb26561d), U64_C(0x34ce5bdf17913eb7), + U64_C(0x5d6fb56af07c5fd0), U64_C(0x182713cd0a7f25fd), + U64_C(0x9e2ac576e6c84d57), U64_C(0x9aaab82ee5a73907), + U64_C(0xa3d93c0f3e558654), U64_C(0x7e7b92aaae48ff56), + U64_C(0x872d8ead256575be), U64_C(0x41c8dbfff96c0e7d), + U64_C(0x99ca5014a3cc1e3b), U64_C(0x40e883e930be1369), + U64_C(0x1ca76e95091051ad), U64_C(0x4e35b42dbab6b5b1), + U64_C(0x05a0254ecabd6944), U64_C(0xe1710fca8152af15), + U64_C(0xf22b0e8dcb984574), U64_C(0xb763a82a319b3f59), + U64_C(0x63fca4296e8ab3ef), U64_C(0x9d4a2d4ca0a36a6b), + U64_C(0xe331bfe60eeb953d), U64_C(0xd5bf541596c391a2), + U64_C(0xf5cb9bef8e9c1618), U64_C(0x46284e9dbc685d11), + U64_C(0x2074cffa185f87ba), U64_C(0xbd3ee2b6b8fcedd1), + U64_C(0xae64e3f1f23607b0), U64_C(0xfeb68965ce29d984), + U64_C(0x55724fdaf6a2b770), U64_C(0x29496d5cd753720e), + U64_C(0xa75941573d3af204), U64_C(0x8e102c0bea69800a), + U64_C(0x111ab16bc573d049), U64_C(0xd7ffe439197aab8a), + U64_C(0xefac380e0b5a09cd), U64_C(0x48f579593660fbc9), + U64_C(0x22347fd697e6bd92), U64_C(0x61bc1405e13389c7), + U64_C(0x4ab5c975b9d9c1e1), U64_C(0x80cd1bcf606126d2), + U64_C(0x7186fd78ed92449a), U64_C(0x93971a882aabccb3), + U64_C(0x88d0e17f66bfce72), U64_C(0x27945a985d5bd4d6) }, + /* 1 */ + { U64_C(0xde553f8c05a811c8), U64_C(0x1906b59631b4f565), + U64_C(0x436e70d6b1964ff7), U64_C(0x36d343cb8b1e9d85), + U64_C(0x843dfacc858aab5a), U64_C(0xfdfc95c299bfc7f9), + U64_C(0x0f634bdea1d51fa2), U64_C(0x6d458b3b76efb3cd), + U64_C(0x85c3f77cf8593f80), U64_C(0x3c91315fbe737cb2), + U64_C(0x2148b03366ace398), U64_C(0x18f8b8264c6761bf), + U64_C(0xc830c1c495c9fb0f), U64_C(0x981a76102086a0aa), + U64_C(0xaa16012142f35760), U64_C(0x35cc54060c763cf6), + U64_C(0x42907d66cc45db2d), U64_C(0x8203d44b965af4bc), + U64_C(0x3d6f3cefc3a0e868), U64_C(0xbc73ff69d292bda7), + U64_C(0x8722ed0102e20a29), U64_C(0x8f8185e8cd34deb7), + U64_C(0x9b0561dda7ee01d9), U64_C(0x5335a0193227fad6), + U64_C(0xc9cecc74e81a6fd5), U64_C(0x54f5832e5c2431ea), + U64_C(0x99e47ba05d553470), U64_C(0xf7bee756acd226ce), + U64_C(0x384e05a5571816fd), U64_C(0xd1367452a47d0e6a), + U64_C(0xf29fde1c386ad85b), U64_C(0x320c77316275f7ca), + U64_C(0xd0c879e2d9ae9ab0), U64_C(0xdb7406c69110ef5d), + U64_C(0x45505e51a2461011), U64_C(0xfc029872e46c5323), + U64_C(0xfa3cb6f5f7bc0cc5), U64_C(0x031f17cd8768a173), + U64_C(0xbd8df2d9af41297d), U64_C(0x9d3b4f5ab43e5e3f), + U64_C(0x4071671b36feee84), U64_C(0x716207e7d3e3b83d), + U64_C(0x48d20ff2f9283a1a), U64_C(0x27769eb4757cbc7e), + U64_C(0x5c56ebc793f2e574), U64_C(0xa48b474f9ef5dc18), + U64_C(0x52cbada94ff46e0c), U64_C(0x60c7da982d8199c6), + U64_C(0x0e9d466edc068b78), U64_C(0x4eec2175eaf865fc), + U64_C(0x550b8e9e21f7a530), U64_C(0x6b7ba5bc653fec2b), + U64_C(0x5eb7f1ba6949d0dd), U64_C(0x57ea94e3db4c9099), + U64_C(0xf640eae6d101b214), U64_C(0xdd4a284182c0b0bb), + U64_C(0xff1d8fbf6304f250), U64_C(0xb8accb933bf9d7e8), + U64_C(0xe8867c478eb68c4d), U64_C(0x3f8e2692391bddc1), + U64_C(0xcb2fd60912a15a7c), U64_C(0xaec935dbab983d2f), + U64_C(0xf55ffd2b56691367), U64_C(0x80e2ce366ce1c115), + U64_C(0x179bf3f8edb27e1d), U64_C(0x01fe0db07dd394da), + U64_C(0xda8a0b76ecc37b87), U64_C(0x44ae53e1df9584cb), + U64_C(0xb310b4b77347a205), U64_C(0xdfab323c787b8512), + U64_C(0x3b511268d070b78e), U64_C(0x65e6e3d2b9396753), + U64_C(0x6864b271e2574d58), U64_C(0x259784c98fc789d7), + U64_C(0x02e11a7dfabb35a9), U64_C(0x8841a6dfa337158b), + U64_C(0x7ade78c39b5dcdd0), U64_C(0xb7cf804d9a2cc84a), + U64_C(0x20b6bd831b7f7742), U64_C(0x75bd331d3a88d272), + U64_C(0x418f6aab4b2d7a5e), U64_C(0xd9951cbb6babdaf4), + U64_C(0xb6318dfde7ff5c90), U64_C(0x1f389b112264aa83), + U64_C(0x492c024284fbaec0), U64_C(0xe33a0363c608f9a0), + U64_C(0x2688930408af28a4), U64_C(0xc7538a1a341ce4ad), + U64_C(0x5da8e677ee2171ae), U64_C(0x8c9e92254a5c7fc4), + U64_C(0x63d8cd55aae938b5), U64_C(0x29ebd8daa97a3706), + U64_C(0x959827b37be88aa1), U64_C(0x1484e4356adadf6e), + U64_C(0xa7945082199d7d6b), U64_C(0xbf6ce8a455fa1cd4), + U64_C(0x9cc542eac9edcae5), U64_C(0x79c16f0e1c356ca3), + U64_C(0x89bfab6fdee48151), U64_C(0xd4174d1830c5f0ff), + U64_C(0x9258048415eb419d), U64_C(0x6139d72850520d1c), + U64_C(0x6a85a80c18ec78f1), U64_C(0xcd11f88e0171059a), + U64_C(0xcceff53e7ca29140), U64_C(0xd229639f2315af19), + U64_C(0x90b91ef9ef507434), U64_C(0x5977d28d074a1be1), + U64_C(0x311360fce51d56b9), U64_C(0xc093a92d5a1f2f91), + U64_C(0x1a19a25bb6dc5416), U64_C(0xeb996b8a09de2d3e), + U64_C(0xfee3820f1ed7668a), U64_C(0xd7085ad5b7ad518c), + U64_C(0x7fff41890fe53345), U64_C(0xec5948bd67dde602), + U64_C(0x2fd5f65dbaaa68e0), U64_C(0xa5754affe32648c2), + U64_C(0xf8ddac880d07396c), U64_C(0x6fa491468c548664), + U64_C(0x0c7c5c1326bdbed1), U64_C(0x4a33158f03930fb3), + U64_C(0x699abfc19f84d982), U64_C(0xe4fa2054a80b329c), + U64_C(0x6707f9af438252fa), U64_C(0x08a368e9cfd6d49e), + U64_C(0x47b1442c58fd25b8), U64_C(0xbbb3dc5ebc91769b), + U64_C(0x1665fe489061eac7), U64_C(0x33f27a811fa66310), + U64_C(0x93a609346838d547), U64_C(0x30ed6d4c98cec263), + U64_C(0x1dd9816cd8df9f2a), U64_C(0x94662a03063b1e7b), + U64_C(0x83fdd9fbeb896066), U64_C(0x7b207573e68e590a), + U64_C(0x5f49fc0a149a4407), U64_C(0x343259b671a5a82c), + U64_C(0xfbc2bb458a6f981f), U64_C(0xc272b350a0a41a38), + U64_C(0x3aaf1fd8ada32354), U64_C(0x6cbb868b0b3c2717), + U64_C(0xa2b569c88d2583fe), U64_C(0xf180c9d1bf027928), + U64_C(0xaf37386bd64ba9f5), U64_C(0x12bacab2790a8088), + U64_C(0x4c0d3b0810435055), U64_C(0xb2eeb9070e9436df), + U64_C(0xc5b29067cea7d104), U64_C(0xdcb425f1ff132461), + U64_C(0x4f122cc5972bf126), U64_C(0xac282fa651230886), + U64_C(0xe7e537992f6393ef), U64_C(0xe61b3a2952b00735), + U64_C(0x709c0a57ae302ce7), U64_C(0xe02514ae416058d3), + U64_C(0xc44c9dd7b37445de), U64_C(0x5a68c5408022ba92), + U64_C(0x1c278cdca50c0bf0), U64_C(0x6e5a9cf6f18712be), + U64_C(0x86dce0b17f319ef3), U64_C(0x2d34ec2040115d49), + U64_C(0x4bcd183f7e409b69), U64_C(0x2815d56ad4a9a3dc), + U64_C(0x24698979f2141d0d), U64_C(0x0000000000000000), + U64_C(0x1ec696a15fb73e59), U64_C(0xd86b110b16784e2e), + U64_C(0x8e7f8858b0e74a6d), U64_C(0x063e2e8713d05fe6), + U64_C(0xe2c40ed3bbdb6d7a), U64_C(0xb1f1aeca89fc97ac), + U64_C(0xe1db191e3cb3cc09), U64_C(0x6418ee62c4eaf389), + U64_C(0xc6ad87aa49cf7077), U64_C(0xd6f65765ca7ec556), + U64_C(0x9afb6c6dda3d9503), U64_C(0x7ce05644888d9236), + U64_C(0x8d609f95378feb1e), U64_C(0x23a9aa4e9c17d631), + U64_C(0x6226c0e5d73aac6f), U64_C(0x56149953a69f0443), + U64_C(0xeeb852c09d66d3ab), U64_C(0x2b0ac2a753c102af), + U64_C(0x07c023376e03cb3c), U64_C(0x2ccae1903dc2c993), + U64_C(0xd3d76e2f5ec63bc3), U64_C(0x9e2458973356ff4c), + U64_C(0xa66a5d32644ee9b1), U64_C(0x0a427294356de137), + U64_C(0x783f62be61e6f879), U64_C(0x1344c70204d91452), + U64_C(0x5b96c8f0fdf12e48), U64_C(0xa90916ecc59bf613), + U64_C(0xbe92e5142829880e), U64_C(0x727d102a548b194e), + U64_C(0x1be7afebcb0fc0cc), U64_C(0x3e702b2244c8491b), + U64_C(0xd5e940a84d166425), U64_C(0x66f9f41f3e51c620), + U64_C(0xabe80c913f20c3ba), U64_C(0xf07ec461c2d1edf2), + U64_C(0xf361d3ac45b94c81), U64_C(0x0521394a94b8fe95), + U64_C(0xadd622162cf09c5c), U64_C(0xe97871f7f3651897), + U64_C(0xf4a1f09b2bba87bd), U64_C(0x095d6559b2054044), + U64_C(0x0bbc7f2448be75ed), U64_C(0x2af4cf172e129675), + U64_C(0x157ae98517094bb4), U64_C(0x9fda55274e856b96), + U64_C(0x914713499283e0ee), U64_C(0xb952c623462a4332), + U64_C(0x74433ead475b46a8), U64_C(0x8b5eb112245fb4f8), + U64_C(0xa34b6478f0f61724), U64_C(0x11a5dd7ffe6221fb), + U64_C(0xc16da49d27ccbb4b), U64_C(0x76a224d0bde07301), + U64_C(0x8aa0bca2598c2022), U64_C(0x4df336b86d90c48f), + U64_C(0xea67663a740db9e4), U64_C(0xef465f70e0b54771), + U64_C(0x39b008152acb8227), U64_C(0x7d1e5bf4f55e06ec), + U64_C(0x105bd0cf83b1b521), U64_C(0x775c2960c033e7db), + U64_C(0x7e014c397236a79f), U64_C(0x811cc386113255cf), + U64_C(0xeda7450d1a0e72d8), U64_C(0x5889df3d7a998f3b), + U64_C(0x2e2bfbedc779fc3a), U64_C(0xce0eef438619a4e9), + U64_C(0x372d4e7bf6cd095f), U64_C(0x04df34fae96b6a4f), + U64_C(0xf923a13870d4adb6), U64_C(0xa1aa7e050a4d228d), + U64_C(0xa8f71b5cb84862c9), U64_C(0xb52e9a306097fde3), + U64_C(0x0d8251a35b6e2a0b), U64_C(0x2257a7fee1c442eb), + U64_C(0x73831d9a29588d94), U64_C(0x51d4ba64c89ccf7f), + U64_C(0x502ab7d4b54f5ba5), U64_C(0x97793dce8153bf08), + U64_C(0xe5042de4d5d8a646), U64_C(0x9687307efc802bd2), + U64_C(0xa05473b5779eb657), U64_C(0xb4d097801d446939), + U64_C(0xcff0e2f3fbca3033), U64_C(0xc38cbee0dd778ee2), + U64_C(0x464f499c252eb162), U64_C(0xcad1dbb96f72cea6), + U64_C(0xba4dd1eec142e241), U64_C(0xb00fa37af42f0376) }, + /* 2 */ + { U64_C(0xcce4cd3aa968b245), U64_C(0x089d5484e80b7faf), + U64_C(0x638246c1b3548304), U64_C(0xd2fe0ec8c2355492), + U64_C(0xa7fbdf7ff2374eee), U64_C(0x4df1600c92337a16), + U64_C(0x84e503ea523b12fb), U64_C(0x0790bbfd53ab0c4a), + U64_C(0x198a780f38f6ea9d), U64_C(0x2ab30c8f55ec48cb), + U64_C(0xe0f7fed6b2c49db5), U64_C(0xb6ecf3f422cadbdc), + U64_C(0x409c9a541358df11), U64_C(0xd3ce8a56dfde3fe3), + U64_C(0xc3e9224312c8c1a0), U64_C(0x0d6dfa58816ba507), + U64_C(0xddf3e1b179952777), U64_C(0x04c02a42748bb1d9), + U64_C(0x94c2abff9f2decb8), U64_C(0x4f91752da8f8acf4), + U64_C(0x78682befb169bf7b), U64_C(0xe1c77a48af2ff6c4), + U64_C(0x0c5d7ec69c80ce76), U64_C(0x4cc1e4928fd81167), + U64_C(0xfeed3d24d9997b62), U64_C(0x518bb6dfc3a54a23), + U64_C(0x6dbf2d26151f9b90), U64_C(0xb5bc624b05ea664f), + U64_C(0xe86aaa525acfe21a), U64_C(0x4801ced0fb53a0be), + U64_C(0xc91463e6c00868ed), U64_C(0x1027a815cd16fe43), + U64_C(0xf67069a0319204cd), U64_C(0xb04ccc976c8abce7), + U64_C(0xc0b9b3fc35e87c33), U64_C(0xf380c77c58f2de65), + U64_C(0x50bb3241de4e2152), U64_C(0xdf93f490435ef195), + U64_C(0xf1e0d25d62390887), U64_C(0xaf668bfb1a3c3141), + U64_C(0xbc11b251f00a7291), U64_C(0x73a5eed47e427d47), + U64_C(0x25bee3f6ee4c3b2e), U64_C(0x43cc0beb34786282), + U64_C(0xc824e778dde3039c), U64_C(0xf97d86d98a327728), + U64_C(0xf2b043e24519b514), U64_C(0xe297ebf7880f4b57), + U64_C(0x3a94a49a98fab688), U64_C(0x868516cb68f0c419), + U64_C(0xeffa11af0964ee50), U64_C(0xa4ab4ec0d517f37d), + U64_C(0xa9c6b498547c567a), U64_C(0x8e18424f80fbbbb6), + U64_C(0x0bcdc53bcf2bc23c), U64_C(0x137739aaea3643d0), + U64_C(0x2c1333ec1bac2ff0), U64_C(0x8d48d3f0a7db0625), + U64_C(0x1e1ac3f26b5de6d7), U64_C(0xf520f81f16b2b95e), + U64_C(0x9f0f6ec450062e84), U64_C(0x0130849e1deb6b71), + U64_C(0xd45e31ab8c7533a9), U64_C(0x652279a2fd14e43f), + U64_C(0x3209f01e70f1c927), U64_C(0xbe71a770cac1a473), + U64_C(0x0e3d6be7a64b1894), U64_C(0x7ec8148cff29d840), + U64_C(0xcb7476c7fac3be0f), U64_C(0x72956a4a63a91636), + U64_C(0x37f95ec21991138f), U64_C(0x9e3fea5a4ded45f5), + U64_C(0x7b38ba50964902e8), U64_C(0x222e580bbde73764), + U64_C(0x61e253e0899f55e6), U64_C(0xfc8d2805e352ad80), + U64_C(0x35994be3235ac56d), U64_C(0x09add01af5e014de), + U64_C(0x5e8659a6780539c6), U64_C(0xb17c48097161d796), + U64_C(0x026015213acbd6e2), U64_C(0xd1ae9f77e515e901), + U64_C(0xb7dc776a3f21b0ad), U64_C(0xaba6a1b96eb78098), + U64_C(0x9bcf4486248d9f5d), U64_C(0x582666c536455efd), + U64_C(0xfdbdac9bfeb9c6f1), U64_C(0xc47999be4163cdea), + U64_C(0x765540081722a7ef), U64_C(0x3e548ed8ec710751), + U64_C(0x3d041f67cb51bac2), U64_C(0x7958af71ac82d40a), + U64_C(0x36c9da5c047a78fe), U64_C(0xed9a048e33af38b2), + U64_C(0x26ee7249c96c86bd), U64_C(0x900281bdeba65d61), + U64_C(0x11172c8bd0fd9532), U64_C(0xea0abf73600434f8), + U64_C(0x42fc8f75299309f3), U64_C(0x34a9cf7d3eb1ae1c), + U64_C(0x2b838811480723ba), U64_C(0x5ce64c8742ceef24), + U64_C(0x1adae9b01fd6570e), U64_C(0x3c349bf9d6bad1b3), + U64_C(0x82453c891c7b75c0), U64_C(0x97923a40b80d512b), + U64_C(0x4a61dbf1c198765c), U64_C(0xb48ce6d518010d3e), + U64_C(0xcfb45c858e480fd6), U64_C(0xd933cbf30d1e96ae), + U64_C(0xd70ea014ab558e3a), U64_C(0xc189376228031742), + U64_C(0x9262949cd16d8b83), U64_C(0xeb3a3bed7def5f89), + U64_C(0x49314a4ee6b8cbcf), U64_C(0xdcc3652f647e4c06), + U64_C(0xda635a4c2a3e2b3d), U64_C(0x470c21a940f3d35b), + U64_C(0x315961a157d174b4), U64_C(0x6672e81dda3459ac), + U64_C(0x5b76f77a1165e36e), U64_C(0x445cb01667d36ec8), + U64_C(0xc5491d205c88a69b), U64_C(0x456c34887a3805b9), + U64_C(0xffddb9bac4721013), U64_C(0x99af51a71e4649bf), + U64_C(0xa15be01cbc7729d5), U64_C(0x52db2760e485f7b0), + U64_C(0x8c78576eba306d54), U64_C(0xae560f6507d75a30), + U64_C(0x95f22f6182c687c9), U64_C(0x71c5fbf54489aba5), + U64_C(0xca44f259e728d57e), U64_C(0x88b87d2ccebbdc8d), + U64_C(0xbab18d32be4a15aa), U64_C(0x8be8ec93e99b611e), + U64_C(0x17b713e89ebdf209), U64_C(0xb31c5d284baa0174), + U64_C(0xeeca9531148f8521), U64_C(0xb8d198138481c348), + U64_C(0x8988f9b2d350b7fc), U64_C(0xb9e11c8d996aa839), + U64_C(0x5a4673e40c8e881f), U64_C(0x1687977683569978), + U64_C(0xbf4123eed72acf02), U64_C(0x4ea1f1b3b513c785), + U64_C(0xe767452be16f91ff), U64_C(0x7505d1b730021a7c), + U64_C(0xa59bca5ec8fc980c), U64_C(0xad069eda20f7e7a3), + U64_C(0x38f4b1bba231606a), U64_C(0x60d2d77e94743e97), + U64_C(0x9affc0183966f42c), U64_C(0x248e6768f3a7505f), + U64_C(0xcdd449a4b483d934), U64_C(0x87b59255751baf68), + U64_C(0x1bea6d2e023d3c7f), U64_C(0x6b1f12455b5ffcab), + U64_C(0x743555292de9710d), U64_C(0xd8034f6d10f5fddf), + U64_C(0xc6198c9f7ba81b08), U64_C(0xbb8109aca3a17edb), + U64_C(0xfa2d1766ad12cabb), U64_C(0xc729080166437079), + U64_C(0x9c5fff7b77269317), U64_C(0x0000000000000000), + U64_C(0x15d706c9a47624eb), U64_C(0x6fdf38072fd44d72), + U64_C(0x5fb6dd3865ee52b7), U64_C(0xa33bf53d86bcff37), + U64_C(0xe657c1b5fc84fa8e), U64_C(0xaa962527735cebe9), + U64_C(0x39c43525bfda0b1b), U64_C(0x204e4d2a872ce186), + U64_C(0x7a083ece8ba26999), U64_C(0x554b9c9db72efbfa), + U64_C(0xb22cd9b656416a05), U64_C(0x96a2bedea5e63a5a), + U64_C(0x802529a826b0a322), U64_C(0x8115ad363b5bc853), + U64_C(0x8375b81701901eb1), U64_C(0x3069e53f4a3a1fc5), + U64_C(0xbd2136cfede119e0), U64_C(0x18bafc91251d81ec), + U64_C(0x1d4a524d4c7d5b44), U64_C(0x05f0aedc6960daa8), + U64_C(0x29e39d3072ccf558), U64_C(0x70f57f6b5962c0d4), + U64_C(0x989fd53903ad22ce), U64_C(0xf84d024797d91c59), + U64_C(0x547b1803aac5908b), U64_C(0xf0d056c37fd263f6), + U64_C(0xd56eb535919e58d8), U64_C(0x1c7ad6d351963035), + U64_C(0x2e7326cd2167f912), U64_C(0xac361a443d1c8cd2), + U64_C(0x697f076461942a49), U64_C(0x4b515f6fdc731d2d), + U64_C(0x8ad8680df4700a6f), U64_C(0x41ac1eca0eb3b460), + U64_C(0x7d988533d80965d3), U64_C(0xa8f6300649973d0b), + U64_C(0x7765c4960ac9cc9e), U64_C(0x7ca801adc5e20ea2), + U64_C(0xdea3700e5eb59ae4), U64_C(0xa06b6482a19c42a4), + U64_C(0x6a2f96db46b497da), U64_C(0x27def6d7d487edcc), + U64_C(0x463ca5375d18b82a), U64_C(0xa6cb5be1efdc259f), + U64_C(0x53eba3fef96e9cc1), U64_C(0xce84d81b93a364a7), + U64_C(0xf4107c810b59d22f), U64_C(0x333974806d1aa256), + U64_C(0x0f0def79bba073e5), U64_C(0x231edc95a00c5c15), + U64_C(0xe437d494c64f2c6c), U64_C(0x91320523f64d3610), + U64_C(0x67426c83c7df32dd), U64_C(0x6eefbc99323f2603), + U64_C(0x9d6f7be56acdf866), U64_C(0x5916e25b2bae358c), + U64_C(0x7ff89012e2c2b331), U64_C(0x035091bf2720bd93), + U64_C(0x561b0d22900e4669), U64_C(0x28d319ae6f279e29), + U64_C(0x2f43a2533c8c9263), U64_C(0xd09e1be9f8fe8270), + U64_C(0xf740ed3e2c796fbc), U64_C(0xdb53ded237d5404c), + U64_C(0x62b2c25faebfe875), U64_C(0x0afd41a5d2c0a94d), + U64_C(0x6412fd3ce0ff8f4e), U64_C(0xe3a76f6995e42026), + U64_C(0x6c8fa9b808f4f0e1), U64_C(0xc2d9a6dd0f23aad1), + U64_C(0x8f28c6d19d10d0c7), U64_C(0x85d587744fd0798a), + U64_C(0xa20b71a39b579446), U64_C(0x684f83fa7c7f4138), + U64_C(0xe507500adba4471d), U64_C(0x3f640a46f19a6c20), + U64_C(0x1247bd34f7dd28a1), U64_C(0x2d23b77206474481), + U64_C(0x93521002cc86e0f2), U64_C(0x572b89bc8de52d18), + U64_C(0xfb1d93f8b0f9a1ca), U64_C(0xe95a2ecc4724896b), + U64_C(0x3ba420048511ddf9), U64_C(0xd63e248ab6bee54b), + U64_C(0x5dd6c8195f258455), U64_C(0x06a03f634e40673b), + U64_C(0x1f2a476c76b68da6), U64_C(0x217ec9b49ac78af7), + U64_C(0xecaa80102e4453c3), U64_C(0x14e78257b99d4f9a) }, + /* 3 */ + { U64_C(0x20329b2cc87bba05), U64_C(0x4f5eb6f86546a531), + U64_C(0xd4f44775f751b6b1), U64_C(0x8266a47b850dfa8b), + U64_C(0xbb986aa15a6ca985), U64_C(0xc979eb08f9ae0f99), + U64_C(0x2da6f447a2375ea1), U64_C(0x1e74275dcd7d8576), + U64_C(0xbc20180a800bc5f8), U64_C(0xb4a2f701b2dc65be), + U64_C(0xe726946f981b6d66), U64_C(0x48e6c453bf21c94c), + U64_C(0x42cad9930f0a4195), U64_C(0xefa47b64aacccd20), + U64_C(0x71180a8960409a42), U64_C(0x8bb3329bf6a44e0c), + U64_C(0xd34c35de2d36dacc), U64_C(0xa92f5b7cbc23dc96), + U64_C(0xb31a85aa68bb09c3), U64_C(0x13e04836a73161d2), + U64_C(0xb24dfc4129c51d02), U64_C(0x8ae44b70b7da5acd), + U64_C(0xe671ed84d96579a7), U64_C(0xa4bb3417d66f3832), + U64_C(0x4572ab38d56d2de8), U64_C(0xb1b47761ea47215c), + U64_C(0xe81c09cf70aba15d), U64_C(0xffbdb872ce7f90ac), + U64_C(0xa8782297fd5dc857), U64_C(0x0d946f6b6a4ce4a4), + U64_C(0xe4df1f4f5b995138), U64_C(0x9ebc71edca8c5762), + U64_C(0x0a2c1dc0b02b88d9), U64_C(0x3b503c115d9d7b91), + U64_C(0xc64376a8111ec3a2), U64_C(0xcec199a323c963e4), + U64_C(0xdc76a87ec58616f7), U64_C(0x09d596e073a9b487), + U64_C(0x14583a9d7d560daf), U64_C(0xf4c6dc593f2a0cb4), + U64_C(0xdd21d19584f80236), U64_C(0x4a4836983ddde1d3), + U64_C(0xe58866a41ae745f9), U64_C(0xf591a5b27e541875), + U64_C(0x891dc05074586693), U64_C(0x5b068c651810a89e), + U64_C(0xa30346bc0c08544f), U64_C(0x3dbf3751c684032d), + U64_C(0x2a1e86ec785032dc), U64_C(0xf73f5779fca830ea), + U64_C(0xb60c05ca30204d21), U64_C(0x0cc316802b32f065), + U64_C(0x8770241bdd96be69), U64_C(0xb861e18199ee95db), + U64_C(0xf805cad91418fcd1), U64_C(0x29e70dccbbd20e82), + U64_C(0xc7140f435060d763), U64_C(0x0f3a9da0e8b0cc3b), + U64_C(0xa2543f574d76408e), U64_C(0xbd7761e1c175d139), + U64_C(0x4b1f4f737ca3f512), U64_C(0x6dc2df1f2fc137ab), + U64_C(0xf1d05c3967b14856), U64_C(0xa742bf3715ed046c), + U64_C(0x654030141d1697ed), U64_C(0x07b872abda676c7d), + U64_C(0x3ce84eba87fa17ec), U64_C(0xc1fb0403cb79afdf), + U64_C(0x3e46bc7105063f73), U64_C(0x278ae987121cd678), + U64_C(0xa1adb4778ef47cd0), U64_C(0x26dd906c5362c2b9), + U64_C(0x05168060589b44e2), U64_C(0xfbfc41f9d79ac08f), + U64_C(0x0e6de44ba9ced8fa), U64_C(0x9feb08068bf243a3), + U64_C(0x7b341749d06b129b), U64_C(0x229c69e74a87929a), + U64_C(0xe09ee6c4427c011b), U64_C(0x5692e30e725c4c3a), + U64_C(0xda99a33e5e9f6e4b), U64_C(0x353dd85af453a36b), + U64_C(0x25241b4c90e0fee7), U64_C(0x5de987258309d022), + U64_C(0xe230140fc0802984), U64_C(0x93281e86a0c0b3c6), + U64_C(0xf229d719a4337408), U64_C(0x6f6c2dd4ad3d1f34), + U64_C(0x8ea5b2fbae3f0aee), U64_C(0x8331dd90c473ee4a), + U64_C(0x346aa1b1b52db7aa), U64_C(0xdf8f235e06042aa9), + U64_C(0xcc6f6b68a1354b7b), U64_C(0x6c95a6f46ebf236a), + U64_C(0x52d31a856bb91c19), U64_C(0x1a35ded6d498d555), + U64_C(0xf37eaef2e54d60c9), U64_C(0x72e181a9a3c2a61c), + U64_C(0x98537aad51952fde), U64_C(0x16f6c856ffaa2530), + U64_C(0xd960281e9d1d5215), U64_C(0x3a0745fa1ce36f50), + U64_C(0x0b7b642bf1559c18), U64_C(0x59a87eae9aec8001), + U64_C(0x5e100c05408bec7c), U64_C(0x0441f98b19e55023), + U64_C(0xd70dcc5534d38aef), U64_C(0x927f676de1bea707), + U64_C(0x9769e70db925e3e5), U64_C(0x7a636ea29115065a), + U64_C(0x468b201816ef11b6), U64_C(0xab81a9b73edff409), + U64_C(0xc0ac7de88a07bb1e), U64_C(0x1f235eb68c0391b7), + U64_C(0x6056b074458dd30f), U64_C(0xbe8eeac102f7ed67), + U64_C(0xcd381283e04b5fba), U64_C(0x5cbefecec277c4e3), + U64_C(0xd21b4c356c48ce0d), U64_C(0x1019c31664b35d8c), + U64_C(0x247362a7d19eea26), U64_C(0xebe582efb3299d03), + U64_C(0x02aef2cb82fc289f), U64_C(0x86275df09ce8aaa8), + U64_C(0x28b07427faac1a43), U64_C(0x38a9b7319e1f47cf), + U64_C(0xc82e92e3b8d01b58), U64_C(0x06ef0b409b1978bc), + U64_C(0x62f842bfc771fb90), U64_C(0x9904034610eb3b1f), + U64_C(0xded85ab5477a3e68), U64_C(0x90d195a663428f98), + U64_C(0x5384636e2ac708d8), U64_C(0xcbd719c37b522706), + U64_C(0xae9729d76644b0eb), U64_C(0x7c8c65e20a0c7ee6), + U64_C(0x80c856b007f1d214), U64_C(0x8c0b40302cc32271), + U64_C(0xdbcedad51fe17a8a), U64_C(0x740e8ae938dbdea0), + U64_C(0xa615c6dc549310ad), U64_C(0x19cc55f6171ae90b), + U64_C(0x49b1bdb8fe5fdd8d), U64_C(0xed0a89af2830e5bf), + U64_C(0x6a7aadb4f5a65bd6), U64_C(0x7e22972988f05679), + U64_C(0xf952b3325566e810), U64_C(0x39fecedadf61530e), + U64_C(0x6101c99f04f3c7ce), U64_C(0x2e5f7f6761b562ff), + U64_C(0xf08725d226cf5c97), U64_C(0x63af3b54860fef51), + U64_C(0x8ff2cb10ef411e2f), U64_C(0x884ab9bb35267252), + U64_C(0x4df04433e7ba8dae), U64_C(0x9afd8866d3690741), + U64_C(0x66b9bb34de94abb3), U64_C(0x9baaf18d92171380), + U64_C(0x543c11c5f0a064a5), U64_C(0x17a1b1bdbed431f1), + U64_C(0xb5f58eeaf3a2717f), U64_C(0xc355f6c849858740), + U64_C(0xec5df044694ef17e), U64_C(0xd83751f5dc6346d4), + U64_C(0xfc4433520dfdacf2), U64_C(0x0000000000000000), + U64_C(0x5a51f58e596ebc5f), U64_C(0x3285aaf12e34cf16), + U64_C(0x8d5c39db6dbd36b0), U64_C(0x12b731dde64f7513), + U64_C(0x94906c2d7aa7dfbb), U64_C(0x302b583aacc8e789), + U64_C(0x9d45facd090e6b3c), U64_C(0x2165e2c78905aec4), + U64_C(0x68d45f7f775a7349), U64_C(0x189b2c1d5664fdca), + U64_C(0xe1c99f2f030215da), U64_C(0x6983269436246788), + U64_C(0x8489af3b1e148237), U64_C(0xe94b702431d5b59c), + U64_C(0x33d2d31a6f4adbd7), U64_C(0xbfd9932a4389f9a6), + U64_C(0xb0e30e8aab39359d), U64_C(0xd1e2c715afcaf253), + U64_C(0x150f43763c28196e), U64_C(0xc4ed846393e2eb3d), + U64_C(0x03f98b20c3823c5e), U64_C(0xfd134ab94c83b833), + U64_C(0x556b682eb1de7064), U64_C(0x36c4537a37d19f35), + U64_C(0x7559f30279a5ca61), U64_C(0x799ae58252973a04), + U64_C(0x9c12832648707ffd), U64_C(0x78cd9c6913e92ec5), + U64_C(0x1d8dac7d0effb928), U64_C(0x439da0784e745554), + U64_C(0x413352b3cc887dcb), U64_C(0xbacf134a1b12bd44), + U64_C(0x114ebafd25cd494d), U64_C(0x2f08068c20cb763e), + U64_C(0x76a07822ba27f63f), U64_C(0xeab2fb04f25789c2), + U64_C(0xe3676de481fe3d45), U64_C(0x1b62a73d95e6c194), + U64_C(0x641749ff5c68832c), U64_C(0xa5ec4dfc97112cf3), + U64_C(0xf6682e92bdd6242b), U64_C(0x3f11c59a44782bb2), + U64_C(0x317c21d1edb6f348), U64_C(0xd65ab5be75ad9e2e), + U64_C(0x6b2dd45fb4d84f17), U64_C(0xfaab381296e4d44e), + U64_C(0xd0b5befeeeb4e692), U64_C(0x0882ef0b32d7a046), + U64_C(0x512a91a5a83b2047), U64_C(0x963e9ee6f85bf724), + U64_C(0x4e09cf132438b1f0), U64_C(0x77f701c9fb59e2fe), + U64_C(0x7ddb1c094b726a27), U64_C(0x5f4775ee01f5f8bd), + U64_C(0x9186ec4d223c9b59), U64_C(0xfeeac1998f01846d), + U64_C(0xac39db1ce4b89874), U64_C(0xb75b7c21715e59e0), + U64_C(0xafc0503c273aa42a), U64_C(0x6e3b543fec430bf5), + U64_C(0x704f7362213e8e83), U64_C(0x58ff0745db9294c0), + U64_C(0x67eec2df9feabf72), U64_C(0xa0facd9ccf8a6811), + U64_C(0xb936986ad890811a), U64_C(0x95c715c63bd9cb7a), + U64_C(0xca8060283a2c33c7), U64_C(0x507de84ee9453486), + U64_C(0x85ded6d05f6a96f6), U64_C(0x1cdad5964f81ade9), + U64_C(0xd5a33e9eb62fa270), U64_C(0x40642b588df6690a), + U64_C(0x7f75eec2c98e42b8), U64_C(0x2cf18dace3494a60), + U64_C(0x23cb100c0bf9865b), U64_C(0xeef3028febb2d9e1), + U64_C(0x4425d2d394133929), U64_C(0xaad6d05c7fa1e0c8), + U64_C(0xad6ea2f7a5c68cb5), U64_C(0xc2028f2308fb9381), + U64_C(0x819f2f5b468fc6d5), U64_C(0xc5bafd88d29cfffc), + U64_C(0x47dc59f357910577), U64_C(0x2b49ff07392e261d), + U64_C(0x57c59ae5332258fb), U64_C(0x73b6f842e2bcb2dd), + U64_C(0xcf96e04862b77725), U64_C(0x4ca73dd8a6c4996f), + U64_C(0x015779eb417e14c1), U64_C(0x37932a9176af8bf4) }, + /* 4 */ + { U64_C(0x190a2c9b249df23e), U64_C(0x2f62f8b62263e1e9), + U64_C(0x7a7f754740993655), U64_C(0x330b7ba4d5564d9f), + U64_C(0x4c17a16a46672582), U64_C(0xb22f08eb7d05f5b8), + U64_C(0x535f47f40bc148cc), U64_C(0x3aec5d27d4883037), + U64_C(0x10ed0a1825438f96), U64_C(0x516101f72c233d17), + U64_C(0x13cc6f949fd04eae), U64_C(0x739853c441474bfd), + U64_C(0x653793d90d3f5b1b), U64_C(0x5240647b96b0fc2f), + U64_C(0x0c84890ad27623e0), U64_C(0xd7189b32703aaea3), + U64_C(0x2685de3523bd9c41), U64_C(0x99317c5b11bffefa), + U64_C(0x0d9baa854f079703), U64_C(0x70b93648fbd48ac5), + U64_C(0xa80441fce30bc6be), U64_C(0x7287704bdc36ff1e), + U64_C(0xb65384ed33dc1f13), U64_C(0xd36417343ee34408), + U64_C(0x39cd38ab6e1bf10f), U64_C(0x5ab861770a1f3564), + U64_C(0x0ebacf09f594563b), U64_C(0xd04572b884708530), + U64_C(0x3cae9722bdb3af47), U64_C(0x4a556b6f2f5cbaf2), + U64_C(0xe1704f1f76c4bd74), U64_C(0x5ec4ed7144c6dfcf), + U64_C(0x16afc01d4c7810e6), U64_C(0x283f113cd629ca7a), + U64_C(0xaf59a8761741ed2d), U64_C(0xeed5a3991e215fac), + U64_C(0x3bf37ea849f984d4), U64_C(0xe413e096a56ce33c), + U64_C(0x2c439d3a98f020d1), U64_C(0x637559dc6404c46b), + U64_C(0x9e6c95d1e5f5d569), U64_C(0x24bb9836045fe99a), + U64_C(0x44efa466dac8ecc9), U64_C(0xc6eab2a5c80895d6), + U64_C(0x803b50c035220cc4), U64_C(0x0321658cba93c138), + U64_C(0x8f9ebc465dc7ee1c), U64_C(0xd15a5137190131d3), + U64_C(0x0fa5ec8668e5e2d8), U64_C(0x91c979578d1037b1), + U64_C(0x0642ca05693b9f70), U64_C(0xefca80168350eb4f), + U64_C(0x38d21b24f36a45ec), U64_C(0xbeab81e1af73d658), + U64_C(0x8cbfd9cae7542f24), U64_C(0xfd19cc0d81f11102), + U64_C(0x0ac6430fbb4dbc90), U64_C(0x1d76a09d6a441895), + U64_C(0x2a01573ff1cbbfa1), U64_C(0xb572e161894fde2b), + U64_C(0x8124734fa853b827), U64_C(0x614b1fdf43e6b1b0), + U64_C(0x68ac395c4238cc18), U64_C(0x21d837bfd7f7b7d2), + U64_C(0x20c714304a860331), U64_C(0x5cfaab726324aa14), + U64_C(0x74c5ba4eb50d606e), U64_C(0xf3a3030474654739), + U64_C(0x23e671bcf015c209), U64_C(0x45f087e947b9582a), + U64_C(0xd8bd77b418df4c7b), U64_C(0xe06f6c90ebb50997), + U64_C(0x0bd96080263c0873), U64_C(0x7e03f9410e40dcfe), + U64_C(0xb8e94be4c6484928), U64_C(0xfb5b0608e8ca8e72), + U64_C(0x1a2b49179e0e3306), U64_C(0x4e29e76961855059), + U64_C(0x4f36c4e6fcf4e4ba), U64_C(0x49740ee395cf7bca), + U64_C(0xc2963ea386d17f7d), U64_C(0x90d65ad810618352), + U64_C(0x12d34c1b02a1fa4d), U64_C(0xfa44258775bb3a91), + U64_C(0x18150f14b9ec46dd), U64_C(0x1491861e6b9a653d), + U64_C(0x9a1019d7ab2c3fc2), U64_C(0x3668d42d06fe13d7), + U64_C(0xdcc1fbb25606a6d0), U64_C(0x969490dd795a1c22), + U64_C(0x3549b1a1bc6dd2ef), U64_C(0xc94f5e23a0ed770e), + U64_C(0xb9f6686b5b39fdcb), U64_C(0xc4d4f4a6efeae00d), + U64_C(0xe732851a1fff2204), U64_C(0x94aad6de5eb869f9), + U64_C(0x3f8ff2ae07206e7f), U64_C(0xfe38a9813b62d03a), + U64_C(0xa7a1ad7a8bee2466), U64_C(0x7b6056c8dde882b6), + U64_C(0x302a1e286fc58ca7), U64_C(0x8da0fa457a259bc7), + U64_C(0xb3302b64e074415b), U64_C(0x5402ae7eff8b635f), + U64_C(0x08f8050c9cafc94b), U64_C(0xae468bf98a3059ce), + U64_C(0x88c355cca98dc58f), U64_C(0xb10e6d67c7963480), + U64_C(0xbad70de7e1aa3cf3), U64_C(0xbfb4a26e320262bb), + U64_C(0xcb711820870f02d5), U64_C(0xce12b7a954a75c9d), + U64_C(0x563ce87dd8691684), U64_C(0x9f73b65e7884618a), + U64_C(0x2b1e74b06cba0b42), U64_C(0x47cec1ea605b2df1), + U64_C(0x1c698312f735ac76), U64_C(0x5fdbcefed9b76b2c), + U64_C(0x831a354c8fb1cdfc), U64_C(0x820516c312c0791f), + U64_C(0xb74ca762aeadabf0), U64_C(0xfc06ef821c80a5e1), + U64_C(0x5723cbf24518a267), U64_C(0x9d4df05d5f661451), + U64_C(0x588627742dfd40bf), U64_C(0xda8331b73f3d39a0), + U64_C(0x17b0e392d109a405), U64_C(0xf965400bcf28fba9), + U64_C(0x7c3dbf4229a2a925), U64_C(0x023e460327e275db), + U64_C(0x6cd0b55a0ce126b3), U64_C(0xe62da695828e96e7), + U64_C(0x42ad6e63b3f373b9), U64_C(0xe50cc319381d57df), + U64_C(0xc5cbd729729b54ee), U64_C(0x46d1e265fd2a9912), + U64_C(0x6428b056904eeff8), U64_C(0x8be23040131e04b7), + U64_C(0x6709d5da2add2ec0), U64_C(0x075de98af44a2b93), + U64_C(0x8447dcc67bfbe66f), U64_C(0x6616f655b7ac9a23), + U64_C(0xd607b8bded4b1a40), U64_C(0x0563af89d3a85e48), + U64_C(0x3db1b4ad20c21ba4), U64_C(0x11f22997b8323b75), + U64_C(0x292032b34b587e99), U64_C(0x7f1cdace9331681d), + U64_C(0x8e819fc9c0b65aff), U64_C(0xa1e3677fe2d5bb16), + U64_C(0xcd33d225ee349da5), U64_C(0xd9a2543b85aef898), + U64_C(0x795e10cbfa0af76d), U64_C(0x25a4bbb9992e5d79), + U64_C(0x78413344677b438e), U64_C(0xf0826688cef68601), + U64_C(0xd27b34bba392f0eb), U64_C(0x551d8df162fad7bc), + U64_C(0x1e57c511d0d7d9ad), U64_C(0xdeffbdb171e4d30b), + U64_C(0xf4feea8e802f6caa), U64_C(0xa480c8f6317de55e), + U64_C(0xa0fc44f07fa40ff5), U64_C(0x95b5f551c3c9dd1a), + U64_C(0x22f952336d6476ea), U64_C(0x0000000000000000), + U64_C(0xa6be8ef5169f9085), U64_C(0xcc2cf1aa73452946), + U64_C(0x2e7ddb39bf12550a), U64_C(0xd526dd3157d8db78), + U64_C(0x486b2d6c08becf29), U64_C(0x9b0f3a58365d8b21), + U64_C(0xac78cdfaadd22c15), U64_C(0xbc95c7e28891a383), + U64_C(0x6a927f5f65dab9c3), U64_C(0xc3891d2c1ba0cb9e), + U64_C(0xeaa92f9f50f8b507), U64_C(0xcf0d9426c9d6e87e), + U64_C(0xca6e3baf1a7eb636), U64_C(0xab25247059980786), + U64_C(0x69b31ad3df4978fb), U64_C(0xe2512a93cc577c4c), + U64_C(0xff278a0ea61364d9), U64_C(0x71a615c766a53e26), + U64_C(0x89dc764334fc716c), U64_C(0xf87a638452594f4a), + U64_C(0xf2bc208be914f3da), U64_C(0x8766b94ac1682757), + U64_C(0xbbc82e687cdb8810), U64_C(0x626a7a53f9757088), + U64_C(0xa2c202f358467a2e), U64_C(0x4d0882e5db169161), + U64_C(0x09e7268301de7da8), U64_C(0xe897699c771ac0dc), + U64_C(0xc8507dac3d9cc3ed), U64_C(0xc0a878a0a1330aa6), + U64_C(0x978bb352e42ba8c1), U64_C(0xe9884a13ea6b743f), + U64_C(0x279afdbabecc28a2), U64_C(0x047c8c064ed9eaab), + U64_C(0x507e2278b15289f4), U64_C(0x599904fbb08cf45c), + U64_C(0xbd8ae46d15e01760), U64_C(0x31353da7f2b43844), + U64_C(0x8558ff49e68a528c), U64_C(0x76fbfc4d92ef15b5), + U64_C(0x3456922e211c660c), U64_C(0x86799ac55c1993b4), + U64_C(0x3e90d1219a51da9c), U64_C(0x2d5cbeb505819432), + U64_C(0x982e5fd48cce4a19), U64_C(0xdb9c1238a24c8d43), + U64_C(0xd439febecaa96f9b), U64_C(0x418c0bef0960b281), + U64_C(0x158ea591f6ebd1de), U64_C(0x1f48e69e4da66d4e), + U64_C(0x8afd13cf8e6fb054), U64_C(0xf5e1c9011d5ed849), + U64_C(0xe34e091c5126c8af), U64_C(0xad67ee7530a398f6), + U64_C(0x43b24dec2e82c75a), U64_C(0x75da99c1287cd48d), + U64_C(0x92e81cdb3783f689), U64_C(0xa3dd217cc537cecd), + U64_C(0x60543c50de970553), U64_C(0x93f73f54aaf2426a), + U64_C(0xa91b62737e7a725d), U64_C(0xf19d4507538732e2), + U64_C(0x77e4dfc20f9ea156), U64_C(0x7d229ccdb4d31dc6), + U64_C(0x1b346a98037f87e5), U64_C(0xedf4c615a4b29e94), + U64_C(0x4093286094110662), U64_C(0xb0114ee85ae78063), + U64_C(0x6ff1d0d6b672e78b), U64_C(0x6dcf96d591909250), + U64_C(0xdfe09e3eec9567e8), U64_C(0x3214582b4827f97c), + U64_C(0xb46dc2ee143e6ac8), U64_C(0xf6c0ac8da7cd1971), + U64_C(0xebb60c10cd8901e4), U64_C(0xf7df8f023abcad92), + U64_C(0x9c52d3d2c217a0b2), U64_C(0x6b8d5cd0f8ab0d20), + U64_C(0x3777f7a29b8fa734), U64_C(0x011f238f9d71b4e3), + U64_C(0xc1b75b2f3c42be45), U64_C(0x5de588fdfe551ef7), + U64_C(0x6eeef3592b035368), U64_C(0xaa3a07ffc4e9b365), + U64_C(0xecebe59a39c32a77), U64_C(0x5ba742f8976e8187), + U64_C(0x4b4a48e0b22d0e11), U64_C(0xddded83dcb771233), + U64_C(0xa59feb79ac0c51bd), U64_C(0xc7f5912a55792135) }, + /* 5 */ + { U64_C(0x6d6ae04668a9b08a), U64_C(0x3ab3f04b0be8c743), + U64_C(0xe51e166b54b3c908), U64_C(0xbe90a9eb35c2f139), + U64_C(0xb2c7066637f2bec1), U64_C(0xaa6945613392202c), + U64_C(0x9a28c36f3b5201eb), U64_C(0xddce5a93ab536994), + U64_C(0x0e34133ef6382827), U64_C(0x52a02ba1ec55048b), + U64_C(0xa2f88f97c4b2a177), U64_C(0x8640e513ca2251a5), + U64_C(0xcdf1d36258137622), U64_C(0xfe6cb708dedf8ddb), + U64_C(0x8a174a9ec8121e5d), U64_C(0x679896036b81560e), + U64_C(0x59ed033395795fee), U64_C(0x1dd778ab8b74edaf), + U64_C(0xee533ef92d9f926d), U64_C(0x2a8c79baf8a8d8f5), + U64_C(0x6bcf398e69b119f6), U64_C(0xe20491742fafdd95), + U64_C(0x276488e0809c2aec), U64_C(0xea955b82d88f5cce), + U64_C(0x7102c63a99d9e0c4), U64_C(0xf9763017a5c39946), + U64_C(0x429fa2501f151b3d), U64_C(0x4659c72bea05d59e), + U64_C(0x984b7fdccf5a6634), U64_C(0xf742232953fbb161), + U64_C(0x3041860e08c021c7), U64_C(0x747bfd9616cd9386), + U64_C(0x4bb1367192312787), U64_C(0x1b72a1638a6c44d3), + U64_C(0x4a0e68a6e8359a66), U64_C(0x169a5039f258b6ca), + U64_C(0xb98a2ef44edee5a4), U64_C(0xd9083fe85e43a737), + U64_C(0x967f6ce239624e13), U64_C(0x8874f62d3c1a7982), + U64_C(0x3c1629830af06e3f), U64_C(0x9165ebfd427e5a8e), + U64_C(0xb5dd81794ceeaa5c), U64_C(0x0de8f15a7834f219), + U64_C(0x70bd98ede3dd5d25), U64_C(0xaccc9ca9328a8950), + U64_C(0x56664eda1945ca28), U64_C(0x221db34c0f8859ae), + U64_C(0x26dbd637fa98970d), U64_C(0x1acdffb4f068f932), + U64_C(0x4585254f64090fa0), U64_C(0x72de245e17d53afa), + U64_C(0x1546b25d7c546cf4), U64_C(0x207e0ffffb803e71), + U64_C(0xfaaad2732bcf4378), U64_C(0xb462dfae36ea17bd), + U64_C(0xcf926fd1ac1b11fd), U64_C(0xe0672dc7dba7ba4a), + U64_C(0xd3fa49ad5d6b41b3), U64_C(0x8ba81449b216a3bc), + U64_C(0x14f9ec8a0650d115), U64_C(0x40fc1ee3eb1d7ce2), + U64_C(0x23a2ed9b758ce44f), U64_C(0x782c521b14fddc7e), + U64_C(0x1c68267cf170504e), U64_C(0xbcf31558c1ca96e6), + U64_C(0xa781b43b4ba6d235), U64_C(0xf6fd7dfe29ff0c80), + U64_C(0xb0a4bad5c3fad91e), U64_C(0xd199f51ea963266c), + U64_C(0x414340349119c103), U64_C(0x5405f269ed4dadf7), + U64_C(0xabd61bb649969dcd), U64_C(0x6813dbeae7bdc3c8), + U64_C(0x65fb2ab09f8931d1), U64_C(0xf1e7fae152e3181d), + U64_C(0xc1a67cef5a2339da), U64_C(0x7a4feea8e0f5bba1), + U64_C(0x1e0b9acf05783791), U64_C(0x5b8ebf8061713831), + U64_C(0x80e53cdbcb3af8d9), U64_C(0x7e898bd315e57502), + U64_C(0xc6bcfbf0213f2d47), U64_C(0x95a38e86b76e942d), + U64_C(0x092e94218d243cba), U64_C(0x8339debf453622e7), + U64_C(0xb11be402b9fe64ff), U64_C(0x57d9100d634177c9), + U64_C(0xcc4e8db52217cbc3), U64_C(0x3b0cae9c71ec7aa2), + U64_C(0xfb158ca451cbfe99), U64_C(0x2b33276d82ac6514), + U64_C(0x01bf5ed77a04bde1), U64_C(0xc5601994af33f779), + U64_C(0x75c4a3416cc92e67), U64_C(0xf3844652a6eb7fc2), + U64_C(0x3487e375fdd0ef64), U64_C(0x18ae430704609eed), + U64_C(0x4d14efb993298efb), U64_C(0x815a620cb13e4538), + U64_C(0x125c354207487869), U64_C(0x9eeea614ce42cf48), + U64_C(0xce2d3106d61fac1c), U64_C(0xbbe99247bad6827b), + U64_C(0x071a871f7b1c149d), U64_C(0x2e4a1cc10db81656), + U64_C(0x77a71ff298c149b8), U64_C(0x06a5d9c80118a97c), + U64_C(0xad73c27e488e34b1), U64_C(0x443a7b981e0db241), + U64_C(0xe3bbcfa355ab6074), U64_C(0x0af276450328e684), + U64_C(0x73617a896dd1871b), U64_C(0x58525de4ef7de20f), + U64_C(0xb7be3dcab8e6cd83), U64_C(0x19111dd07e64230c), + U64_C(0x842359a03e2a367a), U64_C(0x103f89f1f3401fb6), + U64_C(0xdc710444d157d475), U64_C(0xb835702334da5845), + U64_C(0x4320fc876511a6dc), U64_C(0xd026abc9d3679b8d), + U64_C(0x17250eee885c0b2b), U64_C(0x90dab52a387ae76f), + U64_C(0x31fed8d972c49c26), U64_C(0x89cba8fa461ec463), + U64_C(0x2ff5421677bcabb7), U64_C(0x396f122f85e41d7d), + U64_C(0xa09b332430bac6a8), U64_C(0xc888e8ced7070560), + U64_C(0xaeaf201ac682ee8f), U64_C(0x1180d7268944a257), + U64_C(0xf058a43628e7a5fc), U64_C(0xbd4c4b8fbbce2b07), + U64_C(0xa1246df34abe7b49), U64_C(0x7d5569b79be9af3c), + U64_C(0xa9b5a705bd9efa12), U64_C(0xdb6b835baa4bc0e8), + U64_C(0x05793bac8f147342), U64_C(0x21c1512881848390), + U64_C(0xfdb0556c50d357e5), U64_C(0x613d4fcb6a99ff72), + U64_C(0x03dce2648e0cda3e), U64_C(0xe949b9e6568386f0), + U64_C(0xfc0f0bbb2ad7ea04), U64_C(0x6a70675913b5a417), + U64_C(0x7f36d5046fe1c8e3), U64_C(0x0c57af8d02304ff8), + U64_C(0x32223abdfcc84618), U64_C(0x0891caf6f720815b), + U64_C(0xa63eeaec31a26fd4), U64_C(0x2507345374944d33), + U64_C(0x49d28ac266394058), U64_C(0xf5219f9aa7f3d6be), + U64_C(0x2d96fea583b4cc68), U64_C(0x5a31e1571b7585d0), + U64_C(0x8ed12fe53d02d0fe), U64_C(0xdfade6205f5b0e4b), + U64_C(0x4cabb16ee92d331a), U64_C(0x04c6657bf510cea3), + U64_C(0xd73c2cd6a87b8f10), U64_C(0xe1d87310a1a307ab), + U64_C(0x6cd5be9112ad0d6b), U64_C(0x97c032354366f3f2), + U64_C(0xd4e0ceb22677552e), U64_C(0x0000000000000000), + U64_C(0x29509bde76a402cb), U64_C(0xc27a9e8bd42fe3e4), + U64_C(0x5ef7842cee654b73), U64_C(0xaf107ecdbc86536e), + U64_C(0x3fcacbe784fcb401), U64_C(0xd55f90655c73e8cf), + U64_C(0xe6c2f40fdabf1336), U64_C(0xe8f6e7312c873b11), + U64_C(0xeb2a0555a28be12f), U64_C(0xe4a148bc2eb774e9), + U64_C(0x9b979db84156bc0a), U64_C(0x6eb60222e6a56ab4), + U64_C(0x87ffbbc4b026ec44), U64_C(0xc703a5275b3b90a6), + U64_C(0x47e699fc9001687f), U64_C(0x9c8d1aa73a4aa897), + U64_C(0x7cea3760e1ed12dd), U64_C(0x4ec80ddd1d2554c5), + U64_C(0x13e36b957d4cc588), U64_C(0x5d2b66486069914d), + U64_C(0x92b90999cc7280b0), U64_C(0x517cc9c56259deb5), + U64_C(0xc937b619ad03b881), U64_C(0xec30824ad997f5b2), + U64_C(0xa45d565fc5aa080b), U64_C(0xd6837201d27f32f1), + U64_C(0x635ef3789e9198ad), U64_C(0x531f75769651b96a), + U64_C(0x4f77530a6721e924), U64_C(0x486dd4151c3dfdb9), + U64_C(0x5f48dafb9461f692), U64_C(0x375b011173dc355a), + U64_C(0x3da9775470f4d3de), U64_C(0x8d0dcd81b30e0ac0), + U64_C(0x36e45fc609d888bb), U64_C(0x55baacbe97491016), + U64_C(0x8cb29356c90ab721), U64_C(0x76184125e2c5f459), + U64_C(0x99f4210bb55edbd5), U64_C(0x6f095cf59ca1d755), + U64_C(0x9f51f8c3b44672a9), U64_C(0x3538bda287d45285), + U64_C(0x50c39712185d6354), U64_C(0xf23b1885dcefc223), + U64_C(0x79930ccc6ef9619f), U64_C(0xed8fdc9da3934853), + U64_C(0xcb540aaa590bdf5e), U64_C(0x5c94389f1a6d2cac), + U64_C(0xe77daad8a0bbaed7), U64_C(0x28efc5090ca0bf2a), + U64_C(0xbf2ff73c4fc64cd8), U64_C(0xb37858b14df60320), + U64_C(0xf8c96ec0dfc724a7), U64_C(0x828680683f329f06), + U64_C(0x941cd051cd6a29cc), U64_C(0xc3c5c05cae2b5e05), + U64_C(0xb601631dc2e27062), U64_C(0xc01922382027843b), + U64_C(0x24b86a840e90f0d2), U64_C(0xd245177a276ffc52), + U64_C(0x0f8b4de98c3c95c6), U64_C(0x3e759530fef809e0), + U64_C(0x0b4d2892792c5b65), U64_C(0xc4df4743d5374a98), + U64_C(0xa5e20888bfaeb5ea), U64_C(0xba56cc90c0d23f9a), + U64_C(0x38d04cf8ffe0a09c), U64_C(0x62e1adafe495254c), + U64_C(0x0263bcb3f40867df), U64_C(0xcaeb547d230f62bf), + U64_C(0x6082111c109d4293), U64_C(0xdad4dd8cd04f7d09), + U64_C(0xefec602e579b2f8c), U64_C(0x1fb4c4187f7c8a70), + U64_C(0xffd3e9dfa4db303a), U64_C(0x7bf0b07f9af10640), + U64_C(0xf49ec14dddf76b5f), U64_C(0x8f6e713247066d1f), + U64_C(0x339d646a86ccfbf9), U64_C(0x64447467e58d8c30), + U64_C(0x2c29a072f9b07189), U64_C(0xd8b7613f24471ad6), + U64_C(0x6627c8d41185ebef), U64_C(0xa347d140beb61c96), + U64_C(0xde12b8f7255fb3aa), U64_C(0x9d324470404e1576), + U64_C(0x9306574eb6763d51), U64_C(0xa80af9d2c79a47f3), + U64_C(0x859c0777442e8b9b), U64_C(0x69ac853d9db97e29) }, + /* 6 */ + { U64_C(0xc3407dfc2de6377e), U64_C(0x5b9e93eea4256f77), + U64_C(0xadb58fdd50c845e0), U64_C(0x5219ff11a75bed86), + U64_C(0x356b61cfd90b1de9), U64_C(0xfb8f406e25abe037), + U64_C(0x7a5a0231c0f60796), U64_C(0x9d3cd216e1f5020b), + U64_C(0x0c6550fb6b48d8f3), U64_C(0xf57508c427ff1c62), + U64_C(0x4ad35ffa71cb407d), U64_C(0x6290a2da1666aa6d), + U64_C(0xe284ec2349355f9f), U64_C(0xb3c307c53d7c84ec), + U64_C(0x05e23c0468365a02), U64_C(0x190bac4d6c9ebfa8), + U64_C(0x94bbbee9e28b80fa), U64_C(0xa34fc777529cb9b5), + U64_C(0xcc7b39f095bcd978), U64_C(0x2426addb0ce532e3), + U64_C(0x7e79329312ce4fc7), U64_C(0xab09a72eebec2917), + U64_C(0xf8d15499f6b9d6c2), U64_C(0x1a55b8babf8c895d), + U64_C(0xdb8add17fb769a85), U64_C(0xb57f2f368658e81b), + U64_C(0x8acd36f18f3f41f6), U64_C(0x5ce3b7bba50f11d3), + U64_C(0x114dcc14d5ee2f0a), U64_C(0xb91a7fcded1030e8), + U64_C(0x81d5425fe55de7a1), U64_C(0xb6213bc1554adeee), + U64_C(0x80144ef95f53f5f2), U64_C(0x1e7688186db4c10c), + U64_C(0x3b912965db5fe1bc), U64_C(0xc281715a97e8252d), + U64_C(0x54a5d7e21c7f8171), U64_C(0x4b12535ccbc5522e), + U64_C(0x1d289cefbea6f7f9), U64_C(0x6ef5f2217d2e729e), + U64_C(0xe6a7dc819b0d17ce), U64_C(0x1b94b41c05829b0e), + U64_C(0x33d7493c622f711e), U64_C(0xdcf7f942fa5ce421), + U64_C(0x600fba8b7f7a8ecb), U64_C(0x46b60f011a83988e), + U64_C(0x235b898e0dcf4c47), U64_C(0x957ab24f588592a9), + U64_C(0x4354330572b5c28c), U64_C(0xa5f3ef84e9b8d542), + U64_C(0x8c711e02341b2d01), U64_C(0x0b1874ae6a62a657), + U64_C(0x1213d8e306fc19ff), U64_C(0xfe6d7c6a4d9dba35), + U64_C(0x65ed868f174cd4c9), U64_C(0x88522ea0e6236550), + U64_C(0x899322065c2d7703), U64_C(0xc01e690bfef4018b), + U64_C(0x915982ed8abddaf8), U64_C(0xbe675b98ec3a4e4c), + U64_C(0xa996bf7f82f00db1), U64_C(0xe1daf8d49a27696a), + U64_C(0x2effd5d3dc8986e7), U64_C(0xd153a51f2b1a2e81), + U64_C(0x18caa0ebd690adfb), U64_C(0x390e3134b243c51a), + U64_C(0x2778b92cdff70416), U64_C(0x029f1851691c24a6), + U64_C(0x5e7cafeacc133575), U64_C(0xfa4e4cc89fa5f264), + U64_C(0x5a5f9f481e2b7d24), U64_C(0x484c47ab18d764db), + U64_C(0x400a27f2a1a7f479), U64_C(0xaeeb9b2a83da7315), + U64_C(0x721c626879869734), U64_C(0x042330a2d2384851), + U64_C(0x85f672fd3765aff0), U64_C(0xba446b3a3e02061d), + U64_C(0x73dd6ecec3888567), U64_C(0xffac70ccf793a866), + U64_C(0xdfa9edb5294ed2d4), U64_C(0x6c6aea7014325638), + U64_C(0x834a5a0e8c41c307), U64_C(0xcdba35562fb2cb2b), + U64_C(0x0ad97808d06cb404), U64_C(0x0f3b440cb85aee06), + U64_C(0xe5f9c876481f213b), U64_C(0x98deee1289c35809), + U64_C(0x59018bbfcd394bd1), U64_C(0xe01bf47220297b39), + U64_C(0xde68e1139340c087), U64_C(0x9fa3ca4788e926ad), + U64_C(0xbb85679c840c144e), U64_C(0x53d8f3b71d55ffd5), + U64_C(0x0da45c5dd146caa0), U64_C(0x6f34fe87c72060cd), + U64_C(0x57fbc315cf6db784), U64_C(0xcee421a1fca0fdde), + U64_C(0x3d2d0196607b8d4b), U64_C(0x642c8a29ad42c69a), + U64_C(0x14aff010bdd87508), U64_C(0xac74837beac657b3), + U64_C(0x3216459ad821634d), U64_C(0x3fb219c70967a9ed), + U64_C(0x06bc28f3bb246cf7), U64_C(0xf2082c9126d562c6), + U64_C(0x66b39278c45ee23c), U64_C(0xbd394f6f3f2878b9), + U64_C(0xfd33689d9e8f8cc0), U64_C(0x37f4799eb017394f), + U64_C(0x108cc0b26fe03d59), U64_C(0xda4bd1b1417888d6), + U64_C(0xb09d1332ee6eb219), U64_C(0x2f3ed975668794b4), + U64_C(0x58c0871977375982), U64_C(0x7561463d78ace990), + U64_C(0x09876cff037e82f1), U64_C(0x7fb83e35a8c05d94), + U64_C(0x26b9b58a65f91645), U64_C(0xef20b07e9873953f), + U64_C(0x3148516d0b3355b8), U64_C(0x41cb2b541ba9e62a), + U64_C(0x790416c613e43163), U64_C(0xa011d380818e8f40), + U64_C(0x3a5025c36151f3ef), U64_C(0xd57095bdf92266d0), + U64_C(0x498d4b0da2d97688), U64_C(0x8b0c3a57353153a5), + U64_C(0x21c491df64d368e1), U64_C(0x8f2f0af5e7091bf4), + U64_C(0x2da1c1240f9bb012), U64_C(0xc43d59a92ccc49da), + U64_C(0xbfa6573e56345c1f), U64_C(0x828b56a8364fd154), + U64_C(0x9a41f643e0df7caf), U64_C(0xbcf843c985266aea), + U64_C(0x2b1de9d7b4bfdce5), U64_C(0x20059d79dedd7ab2), + U64_C(0x6dabe6d6ae3c446b), U64_C(0x45e81bf6c991ae7b), + U64_C(0x6351ae7cac68b83e), U64_C(0xa432e32253b6c711), + U64_C(0xd092a9b991143cd2), U64_C(0xcac711032e98b58f), + U64_C(0xd8d4c9e02864ac70), U64_C(0xc5fc550f96c25b89), + U64_C(0xd7ef8dec903e4276), U64_C(0x67729ede7e50f06f), + U64_C(0xeac28c7af045cf3d), U64_C(0xb15c1f945460a04a), + U64_C(0x9cfddeb05bfb1058), U64_C(0x93c69abce3a1fe5e), + U64_C(0xeb0380dc4a4bdd6e), U64_C(0xd20db1e8f8081874), + U64_C(0x229a8528b7c15e14), U64_C(0x44291750739fbc28), + U64_C(0xd3ccbd4e42060a27), U64_C(0xf62b1c33f4ed2a97), + U64_C(0x86a8660ae4779905), U64_C(0xd62e814a2a305025), + U64_C(0x477703a7a08d8add), U64_C(0x7b9b0e977af815c5), + U64_C(0x78c51a60a9ea2330), U64_C(0xa6adfb733aaae3b7), + U64_C(0x97e5aa1e3199b60f), U64_C(0x0000000000000000), + U64_C(0xf4b404629df10e31), U64_C(0x5564db44a6719322), + U64_C(0x9207961a59afec0d), U64_C(0x9624a6b88b97a45c), + U64_C(0x363575380a192b1c), U64_C(0x2c60cd82b595a241), + U64_C(0x7d272664c1dc7932), U64_C(0x7142769faa94a1c1), + U64_C(0xa1d0df263b809d13), U64_C(0x1630e841d4c451ae), + U64_C(0xc1df65ad44fa13d8), U64_C(0x13d2d445bcf20bac), + U64_C(0xd915c546926abe23), U64_C(0x38cf3d92084dd749), + U64_C(0xe766d0272103059d), U64_C(0xc7634d5effde7f2f), + U64_C(0x077d2455012a7ea4), U64_C(0xedbfa82ff16fb199), + U64_C(0xaf2a978c39d46146), U64_C(0x42953fa3c8bbd0df), + U64_C(0xcb061da59496a7dc), U64_C(0x25e7a17db6eb20b0), + U64_C(0x34aa6d6963050fba), U64_C(0xa76cf7d580a4f1e4), + U64_C(0xf7ea10954ee338c4), U64_C(0xfcf2643b24819e93), + U64_C(0xcf252d0746aeef8d), U64_C(0x4ef06f58a3f3082c), + U64_C(0x563acfb37563a5d7), U64_C(0x5086e740ce47c920), + U64_C(0x2982f186dda3f843), U64_C(0x87696aac5e798b56), + U64_C(0x5d22bb1d1f010380), U64_C(0x035e14f7d31236f5), + U64_C(0x3cec0d30da759f18), U64_C(0xf3c920379cdb7095), + U64_C(0xb8db736b571e22bb), U64_C(0xdd36f5e44052f672), + U64_C(0xaac8ab8851e23b44), U64_C(0xa857b3d938fe1fe2), + U64_C(0x17f1e4e76eca43fd), U64_C(0xec7ea4894b61a3ca), + U64_C(0x9e62c6e132e734fe), U64_C(0xd4b1991b432c7483), + U64_C(0x6ad6c283af163acf), U64_C(0x1ce9904904a8e5aa), + U64_C(0x5fbda34c761d2726), U64_C(0xf910583f4cb7c491), + U64_C(0xc6a241f845d06d7c), U64_C(0x4f3163fe19fd1a7f), + U64_C(0xe99c988d2357f9c8), U64_C(0x8eee06535d0709a7), + U64_C(0x0efa48aa0254fc55), U64_C(0xb4be23903c56fa48), + U64_C(0x763f52caabbedf65), U64_C(0xeee1bcd8227d876c), + U64_C(0xe345e085f33b4dcc), U64_C(0x3e731561b369bbbe), + U64_C(0x2843fd2067adea10), U64_C(0x2adce5710eb1ceb6), + U64_C(0xb7e03767ef44ccbd), U64_C(0x8db012a48e153f52), + U64_C(0x61ceb62dc5749c98), U64_C(0xe85d942b9959eb9b), + U64_C(0x4c6f7709caef2c8a), U64_C(0x84377e5b8d6bbda3), + U64_C(0x30895dcbb13d47eb), U64_C(0x74a04a9bc2a2fbc3), + U64_C(0x6b17ce251518289c), U64_C(0xe438c4d0f2113368), + U64_C(0x1fb784bed7bad35f), U64_C(0x9b80fae55ad16efc), + U64_C(0x77fe5e6c11b0cd36), U64_C(0xc858095247849129), + U64_C(0x08466059b97090a2), U64_C(0x01c10ca6ba0e1253), + U64_C(0x6988d6747c040c3a), U64_C(0x6849dad2c60a1e69), + U64_C(0x5147ebe67449db73), U64_C(0xc99905f4fd8a837a), + U64_C(0x991fe2b433cd4a5a), U64_C(0xf09734c04fc94660), + U64_C(0xa28ecbd1e892abe6), U64_C(0xf1563866f5c75433), + U64_C(0x4dae7baf70e13ed9), U64_C(0x7ce62ac27bd26b61), + U64_C(0x70837a39109ab392), U64_C(0x90988e4b30b3c8ab), + U64_C(0xb2020b63877296bf), U64_C(0x156efcb607d6675b) }, + /* 7 */ + { U64_C(0xe63f55ce97c331d0), U64_C(0x25b506b0015bba16), + U64_C(0xc8706e29e6ad9ba8), U64_C(0x5b43d3775d521f6a), + U64_C(0x0bfa3d577035106e), U64_C(0xab95fc172afb0e66), + U64_C(0xf64b63979e7a3276), U64_C(0xf58b4562649dad4b), + U64_C(0x48f7c3dbae0c83f1), U64_C(0xff31916642f5c8c5), + U64_C(0xcbb048dc1c4a0495), U64_C(0x66b8f83cdf622989), + U64_C(0x35c130e908e2b9b0), U64_C(0x7c761a61f0b34fa1), + U64_C(0x3601161cf205268d), U64_C(0x9e54ccfe2219b7d6), + U64_C(0x8b7d90a538940837), U64_C(0x9cd403588ea35d0b), + U64_C(0xbc3c6fea9ccc5b5a), U64_C(0xe5ff733b6d24aeed), + U64_C(0xceed22de0f7eb8d2), U64_C(0xec8581cab1ab545e), + U64_C(0xb96105e88ff8e71d), U64_C(0x8ca03501871a5ead), + U64_C(0x76ccce65d6db2a2f), U64_C(0x5883f582a7b58057), + U64_C(0x3f7be4ed2e8adc3e), U64_C(0x0fe7be06355cd9c9), + U64_C(0xee054e6c1d11be83), U64_C(0x1074365909b903a6), + U64_C(0x5dde9f80b4813c10), U64_C(0x4a770c7d02b6692c), + U64_C(0x5379c8d5d7809039), U64_C(0xb4067448161ed409), + U64_C(0x5f5e5026183bd6cd), U64_C(0xe898029bf4c29df9), + U64_C(0x7fb63c940a54d09c), U64_C(0xc5171f897f4ba8bc), + U64_C(0xa6f28db7b31d3d72), U64_C(0x2e4f3be7716eaa78), + U64_C(0x0d6771a099e63314), U64_C(0x82076254e41bf284), + U64_C(0x2f0fd2b42733df98), U64_C(0x5c9e76d3e2dc49f0), + U64_C(0x7aeb569619606cdb), U64_C(0x83478b07b2468764), + U64_C(0xcfadcb8d5923cd32), U64_C(0x85dac7f05b95a41e), + U64_C(0xb5469d1b4043a1e9), U64_C(0xb821ecbbd9a592fd), + U64_C(0x1b8e0b0e798c13c8), U64_C(0x62a57b6d9a0be02e), + U64_C(0xfcf1b793b81257f8), U64_C(0x9d94ea0bd8fe28eb), + U64_C(0x4cea408aeb654a56), U64_C(0x23284a47e888996c), + U64_C(0x2d8f1d128b893545), U64_C(0xf4cbac3132c0d8ab), + U64_C(0xbd7c86b9ca912eba), U64_C(0x3a268eef3dbe6079), + U64_C(0xf0d62f6077a9110c), U64_C(0x2735c916ade150cb), + U64_C(0x89fd5f03942ee2ea), U64_C(0x1acee25d2fd16628), + U64_C(0x90f39bab41181bff), U64_C(0x430dfe8cde39939f), + U64_C(0xf70b8ac4c8274796), U64_C(0x1c53aeaac6024552), + U64_C(0x13b410acf35e9c9b), U64_C(0xa532ab4249faa24f), + U64_C(0x2b1251e5625a163f), U64_C(0xd7e3e676da4841c7), + U64_C(0xa7b264e4e5404892), U64_C(0xda8497d643ae72d3), + U64_C(0x861ae105a1723b23), U64_C(0x38a6414991048aa4), + U64_C(0x6578dec92585b6b4), U64_C(0x0280cfa6acbaeadd), + U64_C(0x88bdb650c273970a), U64_C(0x9333bd5ebbff84c2), + U64_C(0x4e6a8f2c47dfa08b), U64_C(0x321c954db76cef2a), + U64_C(0x418d312a72837942), U64_C(0xb29b38bfffcdf773), + U64_C(0x6c022c38f90a4c07), U64_C(0x5a033a240b0f6a8a), + U64_C(0x1f93885f3ce5da6f), U64_C(0xc38a537e96988bc6), + U64_C(0x39e6a81ac759ff44), U64_C(0x29929e43cee0fce2), + U64_C(0x40cdd87924de0ca2), U64_C(0xe9d8ebc8a29fe819), + U64_C(0x0c2798f3cfbb46f4), U64_C(0x55e484223e53b343), + U64_C(0x4650948ecd0d2fd8), U64_C(0x20e86cb2126f0651), + U64_C(0x6d42c56baf5739e7), U64_C(0xa06fc1405ace1e08), + U64_C(0x7babbfc54f3d193b), U64_C(0x424d17df8864e67f), + U64_C(0xd8045870ef14980e), U64_C(0xc6d7397c85ac3781), + U64_C(0x21a885e1443273b1), U64_C(0x67f8116f893f5c69), + U64_C(0x24f5efe35706cff6), U64_C(0xd56329d076f2ab1a), + U64_C(0x5e1eb9754e66a32d), U64_C(0x28d2771098bd8902), + U64_C(0x8f6013f47dfdc190), U64_C(0x17a993fdb637553c), + U64_C(0xe0a219397e1012aa), U64_C(0x786b9930b5da8606), + U64_C(0x6e82e39e55b0a6da), U64_C(0x875a0856f72f4ec3), + U64_C(0x3741ff4fa458536d), U64_C(0xac4859b3957558fc), + U64_C(0x7ef6d5c75c09a57c), U64_C(0xc04a758b6c7f14fb), + U64_C(0xf9acdd91ab26ebbf), U64_C(0x7391a467c5ef9668), + U64_C(0x335c7c1ee1319aca), U64_C(0xa91533b18641e4bb), + U64_C(0xe4bf9a683b79db0d), U64_C(0x8e20faa72ba0b470), + U64_C(0x51f907737b3a7ae4), U64_C(0x2268a314bed5ec8c), + U64_C(0xd944b123b949edee), U64_C(0x31dcb3b84d8b7017), + U64_C(0xd3fe65279f218860), U64_C(0x097af2f1dc8ffab3), + U64_C(0x9b09a6fc312d0b91), U64_C(0xcc6ded78a3c4520f), + U64_C(0x3481d9ba5ebfcc50), U64_C(0x4f2a667f1182d56b), + U64_C(0xdfd9fdd4509ace94), U64_C(0x26752045fbbc252b), + U64_C(0xbffc491f662bc467), U64_C(0xdd593272fc202449), + U64_C(0x3cbbc218d46d4303), U64_C(0x91b372f817456e1f), + U64_C(0x681faf69bc6385a0), U64_C(0xb686bbeebaa43ed4), + U64_C(0x1469b5084cd0ca01), U64_C(0x98c98009cbca94ac), + U64_C(0x6438379a73d8c354), U64_C(0xc2caba2dc0c5fe26), + U64_C(0x3e3b0dbe78d7a9de), U64_C(0x50b9ee202d670f04), + U64_C(0x4590b27b37eab0e5), U64_C(0x6025b4cb36b10af3), + U64_C(0xfb2c1237079c0162), U64_C(0xa12f28130c936be8), + U64_C(0x4b37e52e54eb1ccc), U64_C(0x083a1ba28ad28f53), + U64_C(0xc10a9cd83a22611b), U64_C(0x9f1425ad7444c236), + U64_C(0x069d4cf7e9d3237a), U64_C(0xedc56899e7f621be), + U64_C(0x778c273680865fcf), U64_C(0x309c5aeb1bd605f7), + U64_C(0x8de0dc52d1472b4d), U64_C(0xf8ec34c2fd7b9e5f), + U64_C(0xea18cd3d58787724), U64_C(0xaad515447ca67b86), + U64_C(0x9989695a9d97e14c), U64_C(0x0000000000000000), + U64_C(0xf196c63321f464ec), U64_C(0x71116bc169557cb5), + U64_C(0xaf887f466f92c7c1), U64_C(0x972e3e0ffe964d65), + U64_C(0x190ec4a8d536f915), U64_C(0x95aef1a9522ca7b8), + U64_C(0xdc19db21aa7d51a9), U64_C(0x94ee18fa0471d258), + U64_C(0x8087adf248a11859), U64_C(0xc457f6da2916dd5c), + U64_C(0xfa6cfb6451c17482), U64_C(0xf256e0c6db13fbd1), + U64_C(0x6a9f60cf10d96f7d), U64_C(0x4daaa9d9bd383fb6), + U64_C(0x03c026f5fae79f3d), U64_C(0xde99148706c7bb74), + U64_C(0x2a52b8b6340763df), U64_C(0x6fc20acd03edd33a), + U64_C(0xd423c08320afdefa), U64_C(0xbbe1ca4e23420dc0), + U64_C(0x966ed75ca8cb3885), U64_C(0xeb58246e0e2502c4), + U64_C(0x055d6a021334bc47), U64_C(0xa47242111fa7d7af), + U64_C(0xe3623fcc84f78d97), U64_C(0x81c744a11efc6db9), + U64_C(0xaec8961539cfb221), U64_C(0xf31609958d4e8e31), + U64_C(0x63e5923ecc5695ce), U64_C(0x47107ddd9b505a38), + U64_C(0xa3afe7b5a0298135), U64_C(0x792b7063e387f3e6), + U64_C(0x0140e953565d75e0), U64_C(0x12f4f9ffa503e97b), + U64_C(0x750ce8902c3cb512), U64_C(0xdbc47e8515f30733), + U64_C(0x1ed3610c6ab8af8f), U64_C(0x5239218681dde5d9), + U64_C(0xe222d69fd2aaf877), U64_C(0xfe71783514a8bd25), + U64_C(0xcaf0a18f4a177175), U64_C(0x61655d9860ec7f13), + U64_C(0xe77fbc9dc19e4430), U64_C(0x2ccff441ddd440a5), + U64_C(0x16e97aaee06a20dc), U64_C(0xa855dae2d01c915b), + U64_C(0x1d1347f9905f30b2), U64_C(0xb7c652bdecf94b34), + U64_C(0xd03e43d265c6175d), U64_C(0xfdb15ec0ee4f2218), + U64_C(0x57644b8492e9599e), U64_C(0x07dda5a4bf8e569a), + U64_C(0x54a46d71680ec6a3), U64_C(0x5624a2d7c4b42c7e), + U64_C(0xbebca04c3076b187), U64_C(0x7d36f332a6ee3a41), + U64_C(0x3b6667bc6be31599), U64_C(0x695f463aea3ef040), + U64_C(0xad08b0e0c3282d1c), U64_C(0xb15b1e4a052a684e), + U64_C(0x44d05b2861b7c505), U64_C(0x15295c5b1a8dbfe1), + U64_C(0x744c01c37a61c0f2), U64_C(0x59c31cd1f1e8f5b7), + U64_C(0xef45a73f4b4ccb63), U64_C(0x6bdf899c46841a9d), + U64_C(0x3dfb2b4b823036e3), U64_C(0xa2ef0ee6f674f4d5), + U64_C(0x184e2dfb836b8cf5), U64_C(0x1134df0a5fe47646), + U64_C(0xbaa1231d751f7820), U64_C(0xd17eaa81339b62bd), + U64_C(0xb01bf71953771dae), U64_C(0x849a2ea30dc8d1fe), + U64_C(0x705182923f080955), U64_C(0x0ea757556301ac29), + U64_C(0x041d83514569c9a7), U64_C(0x0abad4042668658e), + U64_C(0x49b72a88f851f611), U64_C(0x8a3d79f66ec97dd7), + U64_C(0xcd2d042bf59927ef), U64_C(0xc930877ab0f0ee48), + U64_C(0x9273540deda2f122), U64_C(0xc797d02fd3f14261), + U64_C(0xe1e2f06a284d674a), U64_C(0xd2be8c74c97cfd80), + U64_C(0x9a494faf67707e71), U64_C(0xb3dbd1eca9908293), + U64_C(0x72d14d3493b2e388), U64_C(0xd6a30f258c153427) }, +}; + +static const u64 C16[13][16] = +{ + { U64_C(0xdd806559f2a64507), U64_C(0x05767436cc744d23), + U64_C(0xa2422a08a460d315), U64_C(0x4b7ce09192676901), + U64_C(0x714eb88d7585c4fc), U64_C(0x2f6a76432e45d016), + U64_C(0xebcb2f81c0657c1f), U64_C(0xb1085bda1ecadae9) }, + { U64_C(0xe679047021b19bb7), U64_C(0x55dda21bd7cbcd56), + U64_C(0x5cb561c2db0aa7ca), U64_C(0x9ab5176b12d69958), + U64_C(0x61d55e0f16b50131), U64_C(0xf3feea720a232b98), + U64_C(0x4fe39d460f70b5d7), U64_C(0x6fa3b58aa99d2f1a) }, + { U64_C(0x991e96f50aba0ab2), U64_C(0xc2b6f443867adb31), + U64_C(0xc1c93a376062db09), U64_C(0xd3e20fe490359eb1), + U64_C(0xf2ea7514b1297b7b), U64_C(0x06f15e5f529c1f8b), + U64_C(0x0a39fc286a3d8435), U64_C(0xf574dcac2bce2fc7) }, + { U64_C(0x220cbebc84e3d12e), U64_C(0x3453eaa193e837f1), + U64_C(0xd8b71333935203be), U64_C(0xa9d72c82ed03d675), + U64_C(0x9d721cad685e353f), U64_C(0x488e857e335c3c7d), + U64_C(0xf948e1a05d71e4dd), U64_C(0xef1fdfb3e81566d2) }, + { U64_C(0x601758fd7c6cfe57), U64_C(0x7a56a27ea9ea63f5), + U64_C(0xdfff00b723271a16), U64_C(0xbfcd1747253af5a3), + U64_C(0x359e35d7800fffbd), U64_C(0x7f151c1f1686104a), + U64_C(0x9a3f410c6ca92363), U64_C(0x4bea6bacad474799) }, + { U64_C(0xfa68407a46647d6e), U64_C(0xbf71c57236904f35), + U64_C(0x0af21f66c2bec6b6), U64_C(0xcffaa6b71c9ab7b4), + U64_C(0x187f9ab49af08ec6), U64_C(0x2d66c4f95142a46c), + U64_C(0x6fa4c33b7a3039c0), U64_C(0xae4faeae1d3ad3d9) }, + { U64_C(0x8886564d3a14d493), U64_C(0x3517454ca23c4af3), + U64_C(0x06476983284a0504), U64_C(0x0992abc52d822c37), + U64_C(0xd3473e33197a93c9), U64_C(0x399ec6c7e6bf87c9), + U64_C(0x51ac86febf240954), U64_C(0xf4c70e16eeaac5ec) }, + { U64_C(0xa47f0dd4bf02e71e), U64_C(0x36acc2355951a8d9), + U64_C(0x69d18d2bd1a5c42f), U64_C(0xf4892bcb929b0690), + U64_C(0x89b4443b4ddbc49a), U64_C(0x4eb7f8719c36de1e), + U64_C(0x03e7aa020c6e4141), U64_C(0x9b1f5b424d93c9a7) }, + { U64_C(0x7261445183235adb), U64_C(0x0e38dc92cb1f2a60), + U64_C(0x7b2b8a9aa6079c54), U64_C(0x800a440bdbb2ceb1), + U64_C(0x3cd955b7e00d0984), U64_C(0x3a7d3a1b25894224), + U64_C(0x944c9ad8ec165fde), U64_C(0x378f5a541631229b) }, + { U64_C(0x74b4c7fb98459ced), U64_C(0x3698fad1153bb6c3), + U64_C(0x7a1e6c303b7652f4), U64_C(0x9fe76702af69334b), + U64_C(0x1fffe18a1b336103), U64_C(0x8941e71cff8a78db), + U64_C(0x382ae548b2e4f3f3), U64_C(0xabbedea680056f52) }, + { U64_C(0x6bcaa4cd81f32d1b), U64_C(0xdea2594ac06fd85d), + U64_C(0xefbacd1d7d476e98), U64_C(0x8a1d71efea48b9ca), + U64_C(0x2001802114846679), U64_C(0xd8fa6bbbebab0761), + U64_C(0x3002c6cd635afe94), U64_C(0x7bcd9ed0efc889fb) }, + { U64_C(0x48bc924af11bd720), U64_C(0xfaf417d5d9b21b99), + U64_C(0xe71da4aa88e12852), U64_C(0x5d80ef9d1891cc86), + U64_C(0xf82012d430219f9b), U64_C(0xcda43c32bcdf1d77), + U64_C(0xd21380b00449b17a), U64_C(0x378ee767f11631ba) }, +}; + + +#define strido(out, temp, i) do { \ + u64 t; \ + t = stribog_table[0][(temp[0] >> (i * 8)) & 0xff]; \ + t ^= stribog_table[1][(temp[1] >> (i * 8)) & 0xff]; \ + t ^= stribog_table[2][(temp[2] >> (i * 8)) & 0xff]; \ + t ^= stribog_table[3][(temp[3] >> (i * 8)) & 0xff]; \ + t ^= stribog_table[4][(temp[4] >> (i * 8)) & 0xff]; \ + t ^= stribog_table[5][(temp[5] >> (i * 8)) & 0xff]; \ + t ^= stribog_table[6][(temp[6] >> (i * 8)) & 0xff]; \ + t ^= stribog_table[7][(temp[7] >> (i * 8)) & 0xff]; \ + out[i] = t; } while(0) + +static void LPSX (u64 *out, const u64 *a, const u64 *b) +{ + u64 temp[8]; + temp[0] = a[0] ^ b[0]; + temp[1] = a[1] ^ b[1]; + temp[2] = a[2] ^ b[2]; + temp[3] = a[3] ^ b[3]; + temp[4] = a[4] ^ b[4]; + temp[5] = a[5] ^ b[5]; + temp[6] = a[6] ^ b[6]; + temp[7] = a[7] ^ b[7]; + strido (out, temp, 0); + strido (out, temp, 1); + strido (out, temp, 2); + strido (out, temp, 3); + strido (out, temp, 4); + strido (out, temp, 5); + strido (out, temp, 6); + strido (out, temp, 7); +} + +static inline void g (u64 *h, u64 *m, u64 *N) +{ + u64 K[8]; + u64 T[8]; + int i; + + LPSX (K, h, N); + + LPSX (T, K, m); + LPSX (K, K, C16[0]); + for (i = 1; i < 12; i++) + { + LPSX (T, K, T); + LPSX (K, K, C16[i]); + } + + h[0] ^= T[0] ^ K[0] ^ m[0]; + h[1] ^= T[1] ^ K[1] ^ m[1]; + h[2] ^= T[2] ^ K[2] ^ m[2]; + h[3] ^= T[3] ^ K[3] ^ m[3]; + h[4] ^= T[4] ^ K[4] ^ m[4]; + h[5] ^= T[5] ^ K[5] ^ m[5]; + h[6] ^= T[6] ^ K[6] ^ m[6]; + h[7] ^= T[7] ^ K[7] ^ m[7]; +} + + +static unsigned int +transform64 (void *context, const unsigned char *inbuf_arg); + + +static void +stribog_init_512 (void *context, unsigned int flags) +{ + STRIBOG_CONTEXT *hd = context; + + (void)flags; + + memset (hd, 0, sizeof (*hd)); + + hd->bctx.blocksize = 64; + hd->bctx.bwrite = transform64; +} + +static void +stribog_init_256 (void *context, unsigned int flags) +{ + STRIBOG_CONTEXT *hd = context; + + stribog_init_512 (context, flags); + memset (hd->h, 1, 64); +} + +static void +transform (STRIBOG_CONTEXT *hd, const unsigned char *data, unsigned count) +{ + u64 M[8]; + u64 l; + int i; + + for (i = 0; i < 8; i++) + M[i] = buf_get_le64(data + i * 8); + + g (hd->h, M, hd->N); + l = hd->N[0]; + hd->N[0] += count; + if (hd->N[0] < l) + { /* overflow */ + for (i = 1; i < 8; i++) + { + hd->N[i]++; + if (hd->N[i] != 0) + break; + } + } + + hd->Sigma[0] += M[0]; + for (i = 1; i < 8; i++) + if (hd->Sigma[i-1] < M[i-1]) + hd->Sigma[i] += M[i] + 1; + else + hd->Sigma[i] += M[i]; +} + +static unsigned int +transform64 (void *context, const unsigned char *inbuf_arg) +{ + STRIBOG_CONTEXT *hd = context; + + transform (hd, inbuf_arg, 64 * 8); + + return /* burn_stack */ 768; +} + +/* + The routine finally terminates the computation and returns the + digest. The handle is prepared for a new cycle, but adding bytes + to the handle will the destroy the returned buffer. Returns: 32 + bytes with the message the digest. */ +static void +stribog_final (void *context) +{ + STRIBOG_CONTEXT *hd = context; + u64 Z[8] = {0}; + int i; + + _gcry_md_block_write (context, NULL, 0); /* flush */ ; + /* PAD. It does not count towards message length */ + i = hd->bctx.count; + /* After flush we have at least one byte free) */ + hd->bctx.buf[i++] = 1; + while (i < 64) + hd->bctx.buf[i++] = 0; + transform (hd, hd->bctx.buf, hd->bctx.count * 8); + + g (hd->h, hd->N, Z); + g (hd->h, hd->Sigma, Z); + + for (i = 0; i < 8; i++) + hd->h[i] = le_bswap64(hd->h[i]); + + _gcry_burn_stack (768); +} + +static byte * +stribog_read_512 (void *context) +{ + STRIBOG_CONTEXT *hd = context; + + return hd->result; +} + +static byte * +stribog_read_256 (void *context) +{ + STRIBOG_CONTEXT *hd = context; + + return hd->result + 32; +} + +gcry_md_spec_t _gcry_digest_spec_stribog_256 = + { + GCRY_MD_STRIBOG256, {0, 0}, + "STRIBOG256", NULL, 0, NULL, 32, + stribog_init_256, _gcry_md_block_write, stribog_final, stribog_read_256, + sizeof (STRIBOG_CONTEXT) + }; + +gcry_md_spec_t _gcry_digest_spec_stribog_512 = + { + GCRY_MD_STRIBOG512, {0, 0}, + "STRIBOG512", NULL, 0, NULL, 64, + stribog_init_512, _gcry_md_block_write, stribog_final, stribog_read_512, + sizeof (STRIBOG_CONTEXT) + }; diff --git a/plugins/MirOTR/Libgcrypt/cipher/tiger.c b/plugins/MirOTR/Libgcrypt/cipher/tiger.c index a6feb316c2..414dcc4a19 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/tiger.c +++ b/plugins/MirOTR/Libgcrypt/cipher/tiger.c @@ -14,7 +14,8 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see <http://www.gnu.org/licenses/>. + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /* See http://www.cs.technion.ac.il/~biham/Reports/Tiger/ */ @@ -25,20 +26,19 @@ #include <string.h> #include "g10lib.h" -#include "memory.h" #include "cipher.h" +#include "hash-common.h" +#include "bithelp.h" +#include "bufhelp.h" +/* We really need a 64 bit type for this code. */ #ifdef HAVE_U64_TYPEDEF -/* we really need it here, but as this is only experiment we - * can live without Tiger */ - -typedef struct { - u64 a, b, c; - byte buf[64]; - int count; - u32 nblocks; - int variant; /* 0 = old code, 1 = fixed code, 2 - TIGER2. */ +typedef struct +{ + gcry_md_block_ctx_t bctx; + u64 a, b, c; + int variant; /* 0 = old code, 1 = fixed code, 2 - TIGER2. */ } TIGER_CONTEXT; @@ -589,6 +589,9 @@ static u64 sbox4[256] = { U64_C(0xc83223f1720aef96) /* 1022 */, U64_C(0xc3a0396f7363a51f) /* 1023 */ }; +static unsigned int +transform ( void *ctx, const unsigned char *data ); + static void do_init (void *context, int variant) { @@ -597,26 +600,36 @@ do_init (void *context, int variant) hd->a = 0x0123456789abcdefLL; hd->b = 0xfedcba9876543210LL; hd->c = 0xf096a5b4c3b2e187LL; - hd->nblocks = 0; - hd->count = 0; + + hd->bctx.nblocks = 0; + hd->bctx.nblocks_high = 0; + hd->bctx.count = 0; + hd->bctx.blocksize = 64; + hd->bctx.bwrite = transform; hd->variant = variant; } static void -tiger_init( void *context ) +tiger_init (void *context, unsigned int flags) { + (void)flags; + do_init (context, 0); } static void -tiger1_init( void *context ) +tiger1_init (void *context, unsigned int flags) { + (void)flags; + do_init (context, 1); } static void -tiger2_init( void *context ) +tiger2_init (void *context, unsigned int flags) { + (void)flags; + do_init (context, 2); } @@ -626,14 +639,14 @@ tiger_round( u64 *ra, u64 *rb, u64 *rc, u64 x, int mul ) u64 a = *ra; u64 b = *rb; u64 c = *rc; - + c ^= x; a -= ( sbox1[ c & 0xff ] ^ sbox2[ (c >> 16) & 0xff ] ^ sbox3[ (c >> 32) & 0xff ] ^ sbox4[ (c >> 48) & 0xff ]); b += ( sbox4[ (c >> 8) & 0xff ] ^ sbox3[ (c >> 24) & 0xff ] ^ sbox2[ (c >> 40) & 0xff ] ^ sbox1[ (c >> 56) & 0xff ]); b *= mul; - + *ra = a; *rb = b; *rc = c; @@ -687,29 +700,16 @@ key_schedule( u64 *x ) /**************** * Transform the message DATA which consists of 512 bytes (8 words) */ -static void -transform ( TIGER_CONTEXT *hd, const unsigned char *data ) +static unsigned int +transform ( void *ctx, const unsigned char *data ) { + TIGER_CONTEXT *hd = ctx; u64 a,b,c,aa,bb,cc; u64 x[8]; -#ifdef WORDS_BIGENDIAN -#define MKWORD(d,n) \ - ( ((u64)(d)[8*(n)+7]) << 56 | ((u64)(d)[8*(n)+6]) << 48 \ - | ((u64)(d)[8*(n)+5]) << 40 | ((u64)(d)[8*(n)+4]) << 32 \ - | ((u64)(d)[8*(n)+3]) << 24 | ((u64)(d)[8*(n)+2]) << 16 \ - | ((u64)(d)[8*(n)+1]) << 8 | ((u64)(d)[8*(n) ]) ) - x[0] = MKWORD(data, 0); - x[1] = MKWORD(data, 1); - x[2] = MKWORD(data, 2); - x[3] = MKWORD(data, 3); - x[4] = MKWORD(data, 4); - x[5] = MKWORD(data, 5); - x[6] = MKWORD(data, 6); - x[7] = MKWORD(data, 7); -#undef MKWORD -#else - memcpy( &x[0], data, 64 ); -#endif + int i; + + for ( i = 0; i < 8; i++ ) + x[i] = buf_get_le64(data + i * 8); /* save */ a = aa = hd->a; @@ -730,48 +730,8 @@ transform ( TIGER_CONTEXT *hd, const unsigned char *data ) hd->a = a; hd->b = b; hd->c = c; -} - - -/* Update the message digest with the contents - * of INBUF with length INLEN. - */ -static void -tiger_write ( void *context, const void *inbuf_arg, size_t inlen) -{ - const unsigned char *inbuf = inbuf_arg; - TIGER_CONTEXT *hd = context; - - if( hd->count == 64 ) /* flush the buffer */ - { - transform( hd, hd->buf ); - _gcry_burn_stack (21*8+11*sizeof(void*)); - hd->count = 0; - hd->nblocks++; - } - if( !inbuf ) - return; - if( hd->count ) - { - for( ; inlen && hd->count < 64; inlen-- ) - hd->buf[hd->count++] = *inbuf++; - tiger_write( hd, NULL, 0 ); - if( !inlen ) - return; - } - - while( inlen >= 64 ) - { - transform( hd, inbuf ); - hd->count = 0; - hd->nblocks++; - inlen -= 64; - inbuf += 64; - } - _gcry_burn_stack (21*8+11*sizeof(void*)); - for( ; inlen && hd->count < 64; inlen-- ) - hd->buf[hd->count++] = *inbuf++; + return /*burn_stack*/ 21*8+11*sizeof(void*); } @@ -782,19 +742,25 @@ static void tiger_final( void *context ) { TIGER_CONTEXT *hd = context; - u32 t, msb, lsb; + u32 t, th, msb, lsb; byte *p; + unsigned int burn; byte pad = hd->variant == 2? 0x80 : 0x01; - tiger_write(hd, NULL, 0); /* flush */; + _gcry_md_block_write(hd, NULL, 0); /* flush */; + + t = hd->bctx.nblocks; + if (sizeof t == sizeof hd->bctx.nblocks) + th = hd->bctx.nblocks_high; + else + th = hd->bctx.nblocks >> 32; - t = hd->nblocks; /* multiply by 64 to make a byte count */ lsb = t << 6; - msb = t >> 26; + msb = (th << 6) | (t >> 26); /* add the count */ t = lsb; - if( (lsb += hd->count) < t ) + if( (lsb += hd->bctx.count) < t ) msb++; /* multiply by 8 to make a bit count */ t = lsb; @@ -802,45 +768,29 @@ tiger_final( void *context ) msb <<= 3; msb |= t >> 29; - if( hd->count < 56 ) /* enough room */ + if( hd->bctx.count < 56 ) /* enough room */ { - hd->buf[hd->count++] = pad; - while( hd->count < 56 ) - hd->buf[hd->count++] = 0; /* pad */ + hd->bctx.buf[hd->bctx.count++] = pad; + while( hd->bctx.count < 56 ) + hd->bctx.buf[hd->bctx.count++] = 0; /* pad */ } else /* need one extra block */ { - hd->buf[hd->count++] = pad; - while( hd->count < 64 ) - hd->buf[hd->count++] = 0; - tiger_write(hd, NULL, 0); /* flush */; - memset(hd->buf, 0, 56 ); /* fill next block with zeroes */ + hd->bctx.buf[hd->bctx.count++] = pad; /* pad character */ + while( hd->bctx.count < 64 ) + hd->bctx.buf[hd->bctx.count++] = 0; + _gcry_md_block_write(hd, NULL, 0); /* flush */; + memset(hd->bctx.buf, 0, 56 ); /* fill next block with zeroes */ } /* append the 64 bit count */ - hd->buf[56] = lsb ; - hd->buf[57] = lsb >> 8; - hd->buf[58] = lsb >> 16; - hd->buf[59] = lsb >> 24; - hd->buf[60] = msb ; - hd->buf[61] = msb >> 8; - hd->buf[62] = msb >> 16; - hd->buf[63] = msb >> 24; - transform( hd, hd->buf ); - _gcry_burn_stack (21*8+11*sizeof(void*)); - - p = hd->buf; -#ifdef WORDS_BIGENDIAN -#define X(a) do { *(u64*)p = hd->a ; p += 8; } while(0) -#else /* little endian */ -#define X(a) do { *p++ = hd->a >> 56; *p++ = hd->a >> 48; \ - *p++ = hd->a >> 40; *p++ = hd->a >> 32; \ - *p++ = hd->a >> 24; *p++ = hd->a >> 16; \ - *p++ = hd->a >> 8; *p++ = hd->a; } while(0) -#endif -#define Y(a) do { *p++ = hd->a ; *p++ = hd->a >> 8; \ - *p++ = hd->a >> 16; *p++ = hd->a >> 24; \ - *p++ = hd->a >> 32; *p++ = hd->a >> 40; \ - *p++ = hd->a >> 48; *p++ = hd->a >> 56; } while(0) + buf_put_le32(hd->bctx.buf + 56, lsb); + buf_put_le32(hd->bctx.buf + 60, msb); + burn = transform( hd, hd->bctx.buf ); + _gcry_burn_stack (burn); + + p = hd->bctx.buf; +#define X(a) do { *(u64*)p = be_bswap64(hd->a); p += 8; } while(0) +#define Y(a) do { *(u64*)p = le_bswap64(hd->a); p += 8; } while(0) if (hd->variant == 0) { X(a); @@ -862,17 +812,19 @@ tiger_read( void *context ) { TIGER_CONTEXT *hd = context; - return hd->buf; + return hd->bctx.buf; } + /* This is the old TIGER variant based on the unfixed reference - implementation. It was used in GnuPG up to 1.3.2. We don't provide + implementation. IT was used in GnupG up to 1.3.2. We don't provide an OID anymore because that would not be correct. */ gcry_md_spec_t _gcry_digest_spec_tiger = { + GCRY_MD_TIGER, {0, 0}, "TIGER192", NULL, 0, NULL, 24, - tiger_init, tiger_write, tiger_final, tiger_read, + tiger_init, _gcry_md_block_write, tiger_final, tiger_read, sizeof (TIGER_CONTEXT) }; @@ -893,21 +845,21 @@ static gcry_md_oid_spec_t oid_spec_tiger1[] = gcry_md_spec_t _gcry_digest_spec_tiger1 = { + GCRY_MD_TIGER1, {0, 0}, "TIGER", asn1, DIM (asn1), oid_spec_tiger1, 24, - tiger1_init, tiger_write, tiger_final, tiger_read, + tiger1_init, _gcry_md_block_write, tiger_final, tiger_read, sizeof (TIGER_CONTEXT) }; -/* This is TIGER2 which uses a changed padding algorithm. */ +/* This is TIGER2 which usues a changed padding algorithm. */ gcry_md_spec_t _gcry_digest_spec_tiger2 = { + GCRY_MD_TIGER2, {0, 0}, "TIGER2", NULL, 0, NULL, 24, - tiger2_init, tiger_write, tiger_final, tiger_read, + tiger2_init, _gcry_md_block_write, tiger_final, tiger_read, sizeof (TIGER_CONTEXT) }; - - #endif /* HAVE_U64_TYPEDEF */ diff --git a/plugins/MirOTR/Libgcrypt/cipher/twofish.c b/plugins/MirOTR/Libgcrypt/cipher/twofish.c index 5274c4001d..ecd76e359e 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/twofish.c +++ b/plugins/MirOTR/Libgcrypt/cipher/twofish.c @@ -44,6 +44,27 @@ #include "types.h" /* for byte and u32 typedefs */ #include "g10lib.h" #include "cipher.h" +#include "bufhelp.h" +#include "cipher-selftest.h" + + +#define TWOFISH_BLOCKSIZE 16 + + +/* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */ +#undef USE_AMD64_ASM +#if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) +# define USE_AMD64_ASM 1 +#endif + +/* USE_ARM_ASM indicates whether to use ARM assembly code. */ +#undef USE_ARM_ASM +#if defined(__ARMEL__) +# if defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) +# define USE_ARM_ASM 1 +# endif +#endif + /* Prototype for the self-test function. */ static const char *selftest(void); @@ -522,7 +543,7 @@ static byte calc_sb_tbl[512] = { * preprocessed through q0 and q1 respectively; for longer keys they are the * output of previous stages. j is the index of the first key byte to use. * CALC_K computes a pair of subkeys for 128-bit Twofish, by calling CALC_K_2 - * twice, doing the Psuedo-Hadamard Transform, and doing the necessary + * twice, doing the Pseudo-Hadamard Transform, and doing the necessary * rotations. Its parameters are: a, the array to write the results into, * j, the index of the first output entry, k and l, the preprocessed indices * for index 2i, and m and n, the preprocessed indices for index 2i+1. @@ -575,10 +596,10 @@ do_twofish_setkey (TWOFISH_context *ctx, const byte *key, const unsigned keylen) * 128-bit keys use only sa through sh; 256-bit use all of them. */ byte sa = 0, sb = 0, sc = 0, sd = 0, se = 0, sf = 0, sg = 0, sh = 0; byte si = 0, sj = 0, sk = 0, sl = 0, sm = 0, sn = 0, so = 0, sp = 0; - + /* Temporary for CALC_S. */ byte tmp; - + /* Flags for self-test. */ static int initialized = 0; static const char *selftest_failed=0; @@ -668,7 +689,7 @@ do_twofish_setkey (TWOFISH_context *ctx, const byte *key, const unsigned keylen) CALC_K256 (k, 28, 0x84, 0x8A, 0x54, 0x00); CALC_K256 (k, 30, 0xDF, 0xBC, 0x23, 0x9D); } - else + else { /* Compute the S-boxes. */ for(i=j=0,k=1; i < 256; i++, j += 2, k += 2 ) @@ -714,6 +735,36 @@ twofish_setkey (void *context, const byte *key, unsigned int keylen) +#ifdef USE_AMD64_ASM + +/* Assembly implementations of Twofish. */ +extern void _gcry_twofish_amd64_encrypt_block(const TWOFISH_context *c, + byte *out, const byte *in); + +extern void _gcry_twofish_amd64_decrypt_block(const TWOFISH_context *c, + byte *out, const byte *in); + +/* These assembly implementations process three blocks in parallel. */ +extern void _gcry_twofish_amd64_ctr_enc(const TWOFISH_context *c, byte *out, + const byte *in, byte *ctr); + +extern void _gcry_twofish_amd64_cbc_dec(const TWOFISH_context *c, byte *out, + const byte *in, byte *iv); + +extern void _gcry_twofish_amd64_cfb_dec(const TWOFISH_context *c, byte *out, + const byte *in, byte *iv); + +#elif defined(USE_ARM_ASM) + +/* Assembly implementations of Twofish. */ +extern void _gcry_twofish_arm_encrypt_block(const TWOFISH_context *c, + byte *out, const byte *in); + +extern void _gcry_twofish_arm_decrypt_block(const TWOFISH_context *c, + byte *out, const byte *in); + +#else /*!USE_AMD64_ASM && !USE_ARM_ASM*/ + /* Macros to compute the g() function in the encryption and decryption * rounds. G1 is the straight g() function; G2 includes the 8-bit * rotation for the high 32-bit word. */ @@ -764,16 +815,40 @@ twofish_setkey (void *context, const byte *key, unsigned int keylen) * whitening subkey number m. */ #define INPACK(n, x, m) \ - x = in[4 * (n)] ^ (in[4 * (n) + 1] << 8) \ - ^ (in[4 * (n) + 2] << 16) ^ (in[4 * (n) + 3] << 24) ^ ctx->w[m] + x = buf_get_le32(in + (n) * 4); \ + x ^= ctx->w[m] #define OUTUNPACK(n, x, m) \ x ^= ctx->w[m]; \ - out[4 * (n)] = x; out[4 * (n) + 1] = x >> 8; \ - out[4 * (n) + 2] = x >> 16; out[4 * (n) + 3] = x >> 24 + buf_put_le32(out + (n) * 4, x) + +#endif /*!USE_AMD64_ASM*/ + /* Encrypt one block. in and out may be the same. */ +#ifdef USE_AMD64_ASM + +static unsigned int +twofish_encrypt (void *context, byte *out, const byte *in) +{ + TWOFISH_context *ctx = context; + _gcry_twofish_amd64_encrypt_block(ctx, out, in); + return /*burn_stack*/ (4*sizeof (void*)); +} + +#elif defined(USE_ARM_ASM) + +static unsigned int +twofish_encrypt (void *context, byte *out, const byte *in) +{ + TWOFISH_context *ctx = context; + _gcry_twofish_arm_encrypt_block(ctx, out, in); + return /*burn_stack*/ (4*sizeof (void*)); +} + +#else /*!USE_AMD64_ASM && !USE_ARM_ASM*/ + static void do_twofish_encrypt (const TWOFISH_context *ctx, byte *out, const byte *in) { @@ -806,17 +881,41 @@ do_twofish_encrypt (const TWOFISH_context *ctx, byte *out, const byte *in) OUTUNPACK (3, b, 7); } -static void +static unsigned int twofish_encrypt (void *context, byte *out, const byte *in) { TWOFISH_context *ctx = context; do_twofish_encrypt (ctx, out, in); - _gcry_burn_stack (24+3*sizeof (void*)); + return /*burn_stack*/ (24+3*sizeof (void*)); } +#endif /*!USE_AMD64_ASM && !USE_ARM_ASM*/ + /* Decrypt one block. in and out may be the same. */ +#ifdef USE_AMD64_ASM + +static unsigned int +twofish_decrypt (void *context, byte *out, const byte *in) +{ + TWOFISH_context *ctx = context; + _gcry_twofish_amd64_decrypt_block(ctx, out, in); + return /*burn_stack*/ (4*sizeof (void*)); +} + +#elif defined(USE_ARM_ASM) + +static unsigned int +twofish_decrypt (void *context, byte *out, const byte *in) +{ + TWOFISH_context *ctx = context; + _gcry_twofish_arm_decrypt_block(ctx, out, in); + return /*burn_stack*/ (4*sizeof (void*)); +} + +#else /*!USE_AMD64_ASM && !USE_ARM_ASM*/ + static void do_twofish_decrypt (const TWOFISH_context *ctx, byte *out, const byte *in) { @@ -849,13 +948,216 @@ do_twofish_decrypt (const TWOFISH_context *ctx, byte *out, const byte *in) OUTUNPACK (3, d, 3); } -static void +static unsigned int twofish_decrypt (void *context, byte *out, const byte *in) { TWOFISH_context *ctx = context; do_twofish_decrypt (ctx, out, in); - _gcry_burn_stack (24+3*sizeof (void*)); + return /*burn_stack*/ (24+3*sizeof (void*)); +} + +#endif /*!USE_AMD64_ASM && !USE_ARM_ASM*/ + + + +/* Bulk encryption of complete blocks in CTR mode. This function is only + intended for the bulk encryption feature of cipher.c. CTR is expected to be + of size TWOFISH_BLOCKSIZE. */ +void +_gcry_twofish_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks) +{ + TWOFISH_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char tmpbuf[TWOFISH_BLOCKSIZE]; + unsigned int burn, burn_stack_depth = 0; + int i; + +#ifdef USE_AMD64_ASM + { + /* Process data in 3 block chunks. */ + while (nblocks >= 3) + { + _gcry_twofish_amd64_ctr_enc(ctx, outbuf, inbuf, ctr); + + nblocks -= 3; + outbuf += 3 * TWOFISH_BLOCKSIZE; + inbuf += 3 * TWOFISH_BLOCKSIZE; + + burn = 8 * sizeof(void*); + if (burn > burn_stack_depth) + burn_stack_depth = burn; + } + + /* Use generic code to handle smaller chunks... */ + /* TODO: use caching instead? */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* Encrypt the counter. */ + burn = twofish_encrypt(ctx, tmpbuf, ctr); + if (burn > burn_stack_depth) + burn_stack_depth = burn; + + /* XOR the input with the encrypted counter and store in output. */ + buf_xor(outbuf, tmpbuf, inbuf, TWOFISH_BLOCKSIZE); + outbuf += TWOFISH_BLOCKSIZE; + inbuf += TWOFISH_BLOCKSIZE; + /* Increment the counter. */ + for (i = TWOFISH_BLOCKSIZE; i > 0; i--) + { + ctr[i-1]++; + if (ctr[i-1]) + break; + } + } + + wipememory(tmpbuf, sizeof(tmpbuf)); + _gcry_burn_stack(burn_stack_depth); +} + + +/* Bulk decryption of complete blocks in CBC mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +void +_gcry_twofish_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks) +{ + TWOFISH_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned char savebuf[TWOFISH_BLOCKSIZE]; + unsigned int burn, burn_stack_depth = 0; + +#ifdef USE_AMD64_ASM + { + /* Process data in 3 block chunks. */ + while (nblocks >= 3) + { + _gcry_twofish_amd64_cbc_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 3; + outbuf += 3 * TWOFISH_BLOCKSIZE; + inbuf += 3 * TWOFISH_BLOCKSIZE; + + burn = 9 * sizeof(void*); + if (burn > burn_stack_depth) + burn_stack_depth = burn; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + /* INBUF is needed later and it may be identical to OUTBUF, so store + the intermediate result to SAVEBUF. */ + burn = twofish_decrypt (ctx, savebuf, inbuf); + if (burn > burn_stack_depth) + burn_stack_depth = burn; + + buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, TWOFISH_BLOCKSIZE); + inbuf += TWOFISH_BLOCKSIZE; + outbuf += TWOFISH_BLOCKSIZE; + } + + wipememory(savebuf, sizeof(savebuf)); + _gcry_burn_stack(burn_stack_depth); +} + + +/* Bulk decryption of complete blocks in CFB mode. This function is only + intended for the bulk encryption feature of cipher.c. */ +void +_gcry_twofish_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks) +{ + TWOFISH_context *ctx = context; + unsigned char *outbuf = outbuf_arg; + const unsigned char *inbuf = inbuf_arg; + unsigned int burn, burn_stack_depth = 0; + +#ifdef USE_AMD64_ASM + { + /* Process data in 3 block chunks. */ + while (nblocks >= 3) + { + _gcry_twofish_amd64_cfb_dec(ctx, outbuf, inbuf, iv); + + nblocks -= 3; + outbuf += 3 * TWOFISH_BLOCKSIZE; + inbuf += 3 * TWOFISH_BLOCKSIZE; + + burn = 8 * sizeof(void*); + if (burn > burn_stack_depth) + burn_stack_depth = burn; + } + + /* Use generic code to handle smaller chunks... */ + } +#endif + + for ( ;nblocks; nblocks-- ) + { + burn = twofish_encrypt(ctx, iv, iv); + if (burn > burn_stack_depth) + burn_stack_depth = burn; + + buf_xor_n_copy(outbuf, iv, inbuf, TWOFISH_BLOCKSIZE); + outbuf += TWOFISH_BLOCKSIZE; + inbuf += TWOFISH_BLOCKSIZE; + } + + _gcry_burn_stack(burn_stack_depth); +} + + + +/* Run the self-tests for TWOFISH-CTR, tests IV increment of bulk CTR + encryption. Returns NULL on success. */ +static const char * +selftest_ctr (void) +{ + const int nblocks = 3+1; + const int blocksize = TWOFISH_BLOCKSIZE; + const int context_size = sizeof(TWOFISH_context); + + return _gcry_selftest_helper_ctr("TWOFISH", &twofish_setkey, + &twofish_encrypt, &_gcry_twofish_ctr_enc, nblocks, blocksize, + context_size); +} + +/* Run the self-tests for TWOFISH-CBC, tests bulk CBC decryption. + Returns NULL on success. */ +static const char * +selftest_cbc (void) +{ + const int nblocks = 3+2; + const int blocksize = TWOFISH_BLOCKSIZE; + const int context_size = sizeof(TWOFISH_context); + + return _gcry_selftest_helper_cbc("TWOFISH", &twofish_setkey, + &twofish_encrypt, &_gcry_twofish_cbc_dec, nblocks, blocksize, + context_size); +} + +/* Run the self-tests for TWOFISH-CFB, tests bulk CBC decryption. + Returns NULL on success. */ +static const char * +selftest_cfb (void) +{ + const int nblocks = 3+2; + const int blocksize = TWOFISH_BLOCKSIZE; + const int context_size = sizeof(TWOFISH_context); + + return _gcry_selftest_helper_cfb("TWOFISH", &twofish_setkey, + &twofish_encrypt, &_gcry_twofish_cfb_dec, nblocks, blocksize, + context_size); } @@ -866,6 +1168,7 @@ selftest (void) { TWOFISH_context ctx; /* Expanded key. */ byte scratch[16]; /* Encryption/decryption result buffer. */ + const char *r; /* Test vectors for single encryption/decryption. Note that I am using * the vectors from the Twofish paper's "known answer test", I=3 for @@ -915,6 +1218,13 @@ selftest (void) if (memcmp (scratch, plaintext_256, sizeof (plaintext_256))) return "Twofish-256 test decryption failed."; + if ((r = selftest_ctr()) != NULL) + return r; + if ((r = selftest_cbc()) != NULL) + return r; + if ((r = selftest_cfb()) != NULL) + return r; + return NULL; } @@ -980,7 +1290,7 @@ main() timer = clock (); /* Encryption test. */ - for (i = 0; i < 125; i++) + for (i = 0; i < 125; i++) { twofish_setkey (&ctx, buffer[0], sizeof (buffer[0])); for (j = 0; j < 1000; j++) @@ -998,7 +1308,7 @@ main() "encryption failure!\n" : "encryption OK!\n"; /* Decryption test. */ - for (i = 0; i < 125; i++) + for (i = 0; i < 125; i++) { twofish_setkey (&ctx, buffer[2], sizeof (buffer[2])*2); for (j = 0; j < 1000; j++) { @@ -1029,12 +1339,14 @@ main() gcry_cipher_spec_t _gcry_cipher_spec_twofish = { + GCRY_CIPHER_TWOFISH, {0, 0}, "TWOFISH", NULL, NULL, 16, 256, sizeof (TWOFISH_context), twofish_setkey, twofish_encrypt, twofish_decrypt }; gcry_cipher_spec_t _gcry_cipher_spec_twofish128 = { + GCRY_CIPHER_TWOFISH128, {0, 0}, "TWOFISH128", NULL, NULL, 16, 128, sizeof (TWOFISH_context), twofish_setkey, twofish_encrypt, twofish_decrypt }; diff --git a/plugins/MirOTR/Libgcrypt/cipher/whirlpool.c b/plugins/MirOTR/Libgcrypt/cipher/whirlpool.c index 9b029ee367..338d44e0c4 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/whirlpool.c +++ b/plugins/MirOTR/Libgcrypt/cipher/whirlpool.c @@ -14,20 +14,19 @@ * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * + * License along with this program; if not, see <http://www.gnu.org/licenses/>. */ /* This is an implementation of the Whirlpool hashing algorithm, which has been developed by Vincent Rijmen and Paulo S. L. M. Barreto; it's homepage is located at: - http://planeta.terra.com.br/informatica/paulobarreto/WhirlpoolPage.html. + http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html The S-Boxes and the structure of the main transformation function, which implements an optimized version of the algorithm, is taken from the reference implementation available from - http://planeta.terra.com.br/informatica/paulobarreto/whirlpool.zip. */ + http://www.larc.usp.br/~pbarreto/whirlpool.zip + */ #include <config.h> #include <stdio.h> @@ -36,10 +35,10 @@ #include "types.h" #include "g10lib.h" -#include "memory.h" #include "cipher.h" -#include "bithelp.h" +#include "bufhelp.h" +#include "hash-common.h" /* Size of a whirlpool block (in bytes). */ #define BLOCK_SIZE 64 @@ -47,16 +46,19 @@ /* Number of rounds. */ #define R 10 - + /* Types. */ typedef u64 whirlpool_block_t[BLOCK_SIZE / 8]; typedef struct { + gcry_md_block_ctx_t bctx; whirlpool_block_t hash_state; - unsigned char buffer[BLOCK_SIZE]; - size_t count; - unsigned char length[32]; + int use_bugemu; + struct { + size_t count; + unsigned char length[32]; + } bugemu; } whirlpool_context_t; @@ -67,30 +69,13 @@ typedef struct { counter. */ #define buffer_to_block(buffer, block, i) \ for (i = 0; i < 8; i++) \ - (block)[i] = ((u64) (0 \ - | (((u64) (buffer)[i * 8 + 0]) << 56) \ - | (((u64) (buffer)[i * 8 + 1]) << 48) \ - | (((u64) (buffer)[i * 8 + 2]) << 40) \ - | (((u64) (buffer)[i * 8 + 3]) << 32) \ - | (((u64) (buffer)[i * 8 + 4]) << 24) \ - | (((u64) (buffer)[i * 8 + 5]) << 16) \ - | (((u64) (buffer)[i * 8 + 6]) << 8) \ - | (((u64) (buffer)[i * 8 + 7]) << 0))); + (block)[i] = buf_get_be64((buffer) + i * 8); /* Convert the block BLOCK into a buffer BUFFER, using I as counter. */ #define block_to_buffer(buffer, block, i) \ for (i = 0; i < 8; i++) \ - { \ - (buffer)[i * 8 + 0] = (block[i] >> 56) & 0xFF; \ - (buffer)[i * 8 + 1] = (block[i] >> 48) & 0xFF; \ - (buffer)[i * 8 + 2] = (block[i] >> 40) & 0xFF; \ - (buffer)[i * 8 + 3] = (block[i] >> 32) & 0xFF; \ - (buffer)[i * 8 + 4] = (block[i] >> 24) & 0xFF; \ - (buffer)[i * 8 + 5] = (block[i] >> 16) & 0xFF; \ - (buffer)[i * 8 + 6] = (block[i] >> 8) & 0xFF; \ - (buffer)[i * 8 + 7] = (block[i] >> 0) & 0xFF; \ - } + buf_put_be64((buffer) + i * 8, (block)[i]); /* Copy the block BLOCK_SRC to BLOCK_DST, using I as counter. */ #define block_copy(block_dst, block_src, i) \ @@ -118,7 +103,7 @@ static const u64 rc[R] = U64_C (0xfbee7c66dd17479e), U64_C (0xca2dbf07ad5a8333), }; - + /* Main lookup boxes. */ @@ -1178,23 +1163,15 @@ static const u64 C7[256] = U64_C (0xf8c7f8933fed6bf8), U64_C (0x86228644a411c286), }; - - -static void -whirlpool_init (void *ctx) -{ - whirlpool_context_t *context = ctx; - - memset (context, 0, sizeof (*context)); -} - + /* * Transform block. */ -static void -whirlpool_transform (whirlpool_context_t *context, const unsigned char *data) +static unsigned int +whirlpool_transform (void *ctx, const unsigned char *data) { + whirlpool_context_t *context = ctx; whirlpool_block_t data_block; whirlpool_block_t key; whirlpool_block_t state; @@ -1286,11 +1263,35 @@ whirlpool_transform (whirlpool_context_t *context, const unsigned char *data) block_xor (context->hash_state, data_block, i); block_xor (context->hash_state, state, i); + + return /*burn_stack*/ 4 * sizeof(whirlpool_block_t) + 2 * sizeof(int) + + 4 * sizeof(void*); } + +static void +whirlpool_init (void *ctx, unsigned int flags) +{ + whirlpool_context_t *context = ctx; + + memset (context, 0, sizeof (*context)); + + context->bctx.blocksize = BLOCK_SIZE; + context->bctx.bwrite = whirlpool_transform; + if ((flags & GCRY_MD_FLAG_BUGEMU1)) + { + memset (&context->bugemu, 0, sizeof context->bugemu); + context->use_bugemu = 1; + } + else + context->use_bugemu = 0; +} + + +/* Bug compatibility Whirlpool version. */ static void -whirlpool_add (whirlpool_context_t *context, - const void *buffer_arg, size_t buffer_n) +whirlpool_add_bugemu (whirlpool_context_t *context, + const void *buffer_arg, size_t buffer_n) { const unsigned char *buffer = buffer_arg; u64 buffer_size; @@ -1299,40 +1300,37 @@ whirlpool_add (whirlpool_context_t *context, buffer_size = buffer_n; - if (context->count == BLOCK_SIZE) + if (context->bugemu.count == BLOCK_SIZE) { /* Flush the buffer. */ - whirlpool_transform (context, context->buffer); - /*_gcry_burn_stack (80+6*sizeof(void*));*/ /* FIXME */ - context->count = 0; + whirlpool_transform (context, context->bctx.buf); + context->bugemu.count = 0; } if (! buffer) return; /* Nothing to add. */ - if (context->count) + if (context->bugemu.count) { - while (buffer_n && (context->count < BLOCK_SIZE)) + while (buffer_n && (context->bugemu.count < BLOCK_SIZE)) { - context->buffer[context->count++] = *buffer++; + context->bctx.buf[context->bugemu.count++] = *buffer++; buffer_n--; } - whirlpool_add (context, NULL, 0); + whirlpool_add_bugemu (context, NULL, 0); if (!buffer_n) - /* Done. */ - return; + return; /* Done. This is the bug we emulate. */ } - /*_gcry_burn_stack (80+6*sizeof(void*));*/ /* FIXME */ - while (buffer_n >= BLOCK_SIZE) + while (buffer_n >= BLOCK_SIZE) { whirlpool_transform (context, buffer); - context->count = 0; + context->bugemu.count = 0; buffer_n -= BLOCK_SIZE; buffer += BLOCK_SIZE; } - while (buffer_n && (context->count < BLOCK_SIZE)) + while (buffer_n && (context->bugemu.count < BLOCK_SIZE)) { - context->buffer[context->count++] = *buffer++; + context->bctx.buf[context->bugemu.count++] = *buffer++; buffer_n--; } @@ -1344,20 +1342,65 @@ whirlpool_add (whirlpool_context_t *context, if (! (buffer_size || carry)) break; - carry += context->length[32 - i] + (buffer_size & 0xFF); - context->length[32 - i] = carry; + carry += context->bugemu.length[32 - i] + (buffer_size & 0xFF); + context->bugemu.length[32 - i] = carry; buffer_size >>= 8; carry >>= 8; } gcry_assert (! (buffer_size || carry)); } + +/* Bug compatibility Whirlpool version. */ +static void +whirlpool_final_bugemu (void *ctx) +{ + whirlpool_context_t *context = ctx; + unsigned int i; + + /* Flush. */ + whirlpool_add_bugemu (context, NULL, 0); + + /* Pad. */ + context->bctx.buf[context->bugemu.count++] = 0x80; + + if (context->bugemu.count > 32) + { + /* An extra block is necessary. */ + while (context->bugemu.count < 64) + context->bctx.buf[context->bugemu.count++] = 0; + whirlpool_add_bugemu (context, NULL, 0); + } + while (context->bugemu.count < 32) + context->bctx.buf[context->bugemu.count++] = 0; + + /* Add length of message. */ + memcpy (context->bctx.buf + context->bugemu.count, + context->bugemu.length, 32); + context->bugemu.count += 32; + whirlpool_add_bugemu (context, NULL, 0); + + block_to_buffer (context->bctx.buf, context->hash_state, i); +} + + static void whirlpool_write (void *ctx, const void *buffer, size_t buffer_n) { whirlpool_context_t *context = ctx; - whirlpool_add (context, buffer, buffer_n); + if (context->use_bugemu) + { + whirlpool_add_bugemu (context, buffer, buffer_n); + } + else + { + u64 old_nblocks = context->bctx.nblocks; + + _gcry_md_block_write (context, buffer, buffer_n); + + gcry_assert (old_nblocks <= context->bctx.nblocks); + } } static void @@ -1365,29 +1408,60 @@ whirlpool_final (void *ctx) { whirlpool_context_t *context = ctx; unsigned int i; + u64 t, th, lsb, msb; + unsigned char *length; + + if (context->use_bugemu) + { + whirlpool_final_bugemu (ctx); + return; + } + + t = context->bctx.nblocks; + /* if (sizeof t == sizeof context->bctx.nblocks) */ + th = context->bctx.nblocks_high; + /* else */ + /* th = context->bctx.nblocks >> 64; In case we ever use u128 */ + + /* multiply by 64 to make a byte count */ + lsb = t << 6; + msb = (th << 6) | (t >> 58); + /* add the count */ + t = lsb; + if ((lsb += context->bctx.count) < t) + msb++; + /* multiply by 8 to make a bit count */ + t = lsb; + lsb <<= 3; + msb <<= 3; + msb |= t >> 61; /* Flush. */ - whirlpool_add (context, NULL, 0); + whirlpool_write (context, NULL, 0); /* Pad. */ - context->buffer[context->count++] = 0x80; + context->bctx.buf[context->bctx.count++] = 0x80; - if (context->count > 32) + if (context->bctx.count > 32) { /* An extra block is necessary. */ - while (context->count < 64) - context->buffer[context->count++] = 0; - whirlpool_add (context, NULL, 0); + while (context->bctx.count < 64) + context->bctx.buf[context->bctx.count++] = 0; + whirlpool_write (context, NULL, 0); } - while (context->count < 32) - context->buffer[context->count++] = 0; + while (context->bctx.count < 32) + context->bctx.buf[context->bctx.count++] = 0; /* Add length of message. */ - memcpy (context->buffer + context->count, context->length, 32); - context->count += 32; - whirlpool_add (context, NULL, 0); + length = context->bctx.buf + context->bctx.count; + buf_put_be64(&length[0 * 8], 0); + buf_put_be64(&length[1 * 8], 0); + buf_put_be64(&length[2 * 8], msb); + buf_put_be64(&length[3 * 8], lsb); + context->bctx.count += 32; + whirlpool_write (context, NULL, 0); - block_to_buffer (context->buffer, context->hash_state, i); + block_to_buffer (context->bctx.buf, context->hash_state, i); } static byte * @@ -1395,11 +1469,12 @@ whirlpool_read (void *ctx) { whirlpool_context_t *context = ctx; - return context->buffer; + return context->bctx.buf; } gcry_md_spec_t _gcry_digest_spec_whirlpool = { + GCRY_MD_WHIRLPOOL, {0, 0}, "WHIRLPOOL", NULL, 0, NULL, 64, whirlpool_init, whirlpool_write, whirlpool_final, whirlpool_read, sizeof (whirlpool_context_t) |