From debb4a3cb95014ef3442116434f8209f778bbdae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20=C5=A0abata?= Date: Thu, 15 Oct 2020 16:01:31 +0200 Subject: [PATCH] RHEL 9.0.0 Alpha bootstrap The content of this branch was automatically imported from Fedora ELN with the following as its source: https://src.fedoraproject.org/rpms/libgcrypt#42e8971b6466fdb92f842f1859d5ae803430d7ef --- .gitignore | 24 + curves.c | 144 + ecc-curves.c | 1211 ++++ hobble-libgcrypt | 11 + libgcrypt-1.6.1-mpicoder-gccopt.patch | 104 + libgcrypt-1.7.3-ecc-test-fix.patch | 122 + libgcrypt-1.7.3-fips-cavs.patch | 1311 ++++ libgcrypt-1.7.3-fips-reqs.patch | 35 + libgcrypt-1.8.3-cmac-selftest.patch | 322 + libgcrypt-1.8.3-fips-ctor.patch | 60 + libgcrypt-1.8.3-fips-enttest.patch | 113 + libgcrypt-1.8.3-md-fips-enforce.patch | 18 + libgcrypt-1.8.4-fips-keygen.patch | 65 + libgcrypt-1.8.4-tests-fipsmode.patch | 184 + libgcrypt-1.8.4-use-poll.patch | 77 + libgcrypt-1.8.5-aes-perf.patch | 8156 +++++++++++++++++++++++++ libgcrypt-1.8.5-fips-module.patch | 139 + libgcrypt-1.8.5-getrandom.patch | 285 + libgcrypt-1.8.5-intel-cet.patch | 348 ++ libgcrypt-1.8.5-use-fipscheck.patch | 89 + libgcrypt.spec | 637 ++ random.conf | 4 + sources | 1 + t-mpi-point.c | 1213 ++++ tests/smoke-test/Makefile | 71 + tests/smoke-test/PURPOSE | 3 + tests/smoke-test/runtest.sh | 71 + tests/tests.yml | 20 + wk@g10code.com | 2007 ++++++ 29 files changed, 16845 insertions(+) create mode 100644 curves.c create mode 100644 ecc-curves.c create mode 100755 hobble-libgcrypt create mode 100644 libgcrypt-1.6.1-mpicoder-gccopt.patch create mode 100644 libgcrypt-1.7.3-ecc-test-fix.patch create mode 100644 libgcrypt-1.7.3-fips-cavs.patch create mode 100644 libgcrypt-1.7.3-fips-reqs.patch create mode 100644 libgcrypt-1.8.3-cmac-selftest.patch create mode 100644 libgcrypt-1.8.3-fips-ctor.patch create mode 100644 libgcrypt-1.8.3-fips-enttest.patch create mode 100644 libgcrypt-1.8.3-md-fips-enforce.patch create mode 100644 libgcrypt-1.8.4-fips-keygen.patch create mode 100644 libgcrypt-1.8.4-tests-fipsmode.patch create mode 100644 libgcrypt-1.8.4-use-poll.patch create mode 100644 libgcrypt-1.8.5-aes-perf.patch create mode 100644 libgcrypt-1.8.5-fips-module.patch create mode 100644 libgcrypt-1.8.5-getrandom.patch create mode 100644 libgcrypt-1.8.5-intel-cet.patch create mode 100644 libgcrypt-1.8.5-use-fipscheck.patch create mode 100644 libgcrypt.spec create mode 100644 random.conf create mode 100644 sources create mode 100644 t-mpi-point.c create mode 100644 tests/smoke-test/Makefile create mode 100644 tests/smoke-test/PURPOSE create mode 100755 tests/smoke-test/runtest.sh create mode 100644 tests/tests.yml create mode 100644 wk@g10code.com diff --git a/.gitignore b/.gitignore index e69de29..48ec3ad 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,24 @@ +libgcrypt-1.4.5-hobbled.tar.bz2 +/libgcrypt-1.4.6-hobbled.tar.bz2 +/libgcrypt-1.5.0-hobbled.tar.bz2 +/libgcrypt-1.5.1-hobbled.tar.xz +/libgcrypt-1.5.2-hobbled.tar.xz +/libgcrypt-1.5.3-hobbled.tar.xz +/libgcrypt-1.6.1-hobbled.tar.xz +/libgcrypt-1.6.2-hobbled.tar.xz +/libgcrypt-1.6.3-hobbled.tar.xz +/libgcrypt-1.6.4-hobbled.tar.xz +/libgcrypt-1.6.5-hobbled.tar.xz +/libgcrypt-1.6.6-hobbled.tar.xz +/libgcrypt-1.7.3-hobbled.tar.xz +/libgcrypt-1.7.5-hobbled.tar.xz +/libgcrypt-1.7.6-hobbled.tar.xz +/libgcrypt-1.7.7-hobbled.tar.xz +/libgcrypt-1.7.8-hobbled.tar.xz +/libgcrypt-1.8.0-hobbled.tar.xz +/libgcrypt-1.8.1-hobbled.tar.xz +/libgcrypt-1.8.2-hobbled.tar.xz +/libgcrypt-1.8.3-hobbled.tar.xz +/libgcrypt-1.8.4-hobbled.tar.xz +/libgcrypt-1.8.5-hobbled.tar.xz +/libgcrypt-1.8.6-hobbled.tar.xz diff --git a/curves.c b/curves.c new file mode 100644 index 0000000..b68e0e2 --- /dev/null +++ b/curves.c @@ -0,0 +1,144 @@ +/* curves.c - ECC curves regression tests + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include + +#include "../src/gcrypt-int.h" + + +#define PGM "curves" +#include "t-common.h" + +/* Number of curves defined in ../cipger/ecc.c */ +#define N_CURVES 14 + +/* A real world sample public key. */ +static char const sample_key_1[] = +"(public-key\n" +" (ecdsa\n" +" (p #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF#)\n" +" (a #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC#)\n" +" (b #5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B#)\n" +" (g #046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296" + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5#)\n" +" (n #00FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551#)\n" +" (h #000000000000000000000000000000000000000000000000000000000000000001#)\n" +" (q #0442B927242237639A36CE9221B340DB1A9AB76DF2FE3E171277F6A4023DED146EE" + "86525E38CCECFF3FB8D152CC6334F70D23A525175C1BCBDDE6E023B2228770E#)\n" +" ))"; +static char const sample_key_1_curve[] = "NIST P-256"; +static unsigned int sample_key_1_nbits = 256; + + + +static void +list_curves (void) +{ + int idx; + const char *name; + unsigned int nbits; + + for (idx=0; (name = gcry_pk_get_curve (NULL, idx, &nbits)); idx++) + { + if (verbose) + printf ("%s - %u bits\n", name, nbits); + } + if (idx != N_CURVES) + fail ("expected %d curves but got %d\n", N_CURVES, idx); + if (gcry_pk_get_curve (NULL, -1, NULL)) + fail ("curve iteration failed\n"); +} + + +static void +check_matching (void) +{ + gpg_error_t err; + gcry_sexp_t key; + const char *name; + unsigned int nbits; + + err = gcry_sexp_new (&key, sample_key_1, 0, 1); + if (err) + die ("parsing s-expression string failed: %s\n", gpg_strerror (err)); + name = gcry_pk_get_curve (key, 0, &nbits); + if (!name) + fail ("curve name not found for sample_key_1\n"); + else if (strcmp (name, sample_key_1_curve)) + fail ("expected curve name %s but got %s for sample_key_1\n", + sample_key_1_curve, name); + else if (nbits != sample_key_1_nbits) + fail ("expected curve size %u but got %u for sample_key_1\n", + sample_key_1_nbits, nbits); + + gcry_sexp_release (key); + +} + + +static void +check_get_params (void) +{ + gcry_sexp_t param; + const char *name; + + param = gcry_pk_get_param (GCRY_PK_ECDSA, sample_key_1_curve); + if (!param) + fail ("error gerring parameters for `%s'\n", sample_key_1_curve); + + name = gcry_pk_get_curve (param, 0, NULL); + if (!name) + fail ("get_param: curve name not found for sample_key_1\n"); + else if (strcmp (name, sample_key_1_curve)) + fail ("get_param: expected curve name %s but got %s for sample_key_1\n", + sample_key_1_curve, name); + + gcry_sexp_release (param); + +} + + +int +main (int argc, char **argv) +{ + if (argc > 1 && !strcmp (argv[1], "--verbose")) + verbose = 1; + else if (argc > 1 && !strcmp (argv[1], "--debug")) + verbose = debug = 1; + + if (!gcry_check_version (GCRYPT_VERSION)) + die ("version mismatch\n"); + + xgcry_control (GCRYCTL_DISABLE_SECMEM, 0); + xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); + if (debug) + xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0); + list_curves (); + check_matching (); + check_get_params (); + + return error_count ? 1 : 0; +} diff --git a/ecc-curves.c b/ecc-curves.c new file mode 100644 index 0000000..666ebc1 --- /dev/null +++ b/ecc-curves.c @@ -0,0 +1,1211 @@ +/* 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 . + */ + +#include +#include +#include +#include +#include + +#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" }, /* OpenPGP */ + { "Curve25519", "1.3.101.110" }, /* rfc8410 */ + { "Curve25519", "X25519" }, /* rfc8410 */ + + { "Ed25519", "1.3.6.1.4.1.11591.15.1" },/* OpenPGP */ + { "Ed25519", "1.3.101.112" }, /* rfc8410 */ + + { "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. */ + + { "GOST2001-test", "1.2.643.2.2.35.0" }, + { "GOST2001-CryptoPro-A", "1.2.643.2.2.35.1" }, + { "GOST2001-CryptoPro-B", "1.2.643.2.2.35.2" }, + { "GOST2001-CryptoPro-C", "1.2.643.2.2.35.3" }, + { "GOST2001-CryptoPro-A", "GOST2001-CryptoPro-XchA" }, + { "GOST2001-CryptoPro-C", "GOST2001-CryptoPro-XchB" }, + { "GOST2001-CryptoPro-A", "1.2.643.2.2.36.0" }, + { "GOST2001-CryptoPro-C", "1.2.643.2.2.36.1" }, + + { "GOST2012-tc26-A", "1.2.643.7.1.2.1.2.1" }, + { "GOST2012-tc26-B", "1.2.643.7.1.2.1.2.2" }, + + { "secp256k1", "1.3.132.0.10" }, + + { 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. For Montgomery + Curves (a,b) has ((A-2)/4,B^-1). */ + const char *n; /* The order of the base point. */ + const char *g_x, *g_y; /* Base point. */ + const char *h; /* Cofactor. */ +} 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_EDWARDS, ECC_DIALECT_ED25519, + "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED", + "-0x01", + "-0x2DFC9311D490018C7338BF8688861767FF8FF5B2BEBE27548A14B235ECA6874A", + "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED", + "0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A", + "0x6666666666666666666666666666666666666666666666666666666666666658", + "0x08" + }, + { + /* (y^2 = x^3 + 486662*x^2 + x) */ + "Curve25519", 256, 0, + MPI_EC_MONTGOMERY, ECC_DIALECT_STANDARD, + "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED", + "0x01DB41", + "0x01", + "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED", + "0x0000000000000000000000000000000000000000000000000000000000000009", + "0x20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9", + "0x08" + }, + { + "NIST P-224", 224, 1, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xffffffffffffffffffffffffffffffff000000000000000000000001", + "0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe", + "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", + "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d" , + + "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", + "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34", + "0x01" + }, + { + "NIST P-256", 256, 1, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff", + "0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc", + "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", + "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + + "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", + "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", + "0x01" + }, + { + "NIST P-384", 384, 1, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe" + "ffffffff0000000000000000ffffffff", + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe" + "ffffffff0000000000000000fffffffc", + "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a" + "c656398d8a2ed19d2a85c8edd3ec2aef", + "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf" + "581a0db248b0a77aecec196accc52973", + + "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38" + "5502f25dbf55296c3a545e3872760ab7", + "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0" + "0a60b1ce1d7e819d7a431d7c90ea0e5f", + "0x01" + }, + { + "NIST P-521", 521, 1, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc", + "0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef10" + "9e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", + "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "ffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409", + + "0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d" + "3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", + "0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e" + "662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", + "0x01" + }, + + { + "GOST2001-test", 256, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x8000000000000000000000000000000000000000000000000000000000000431", + "0x0000000000000000000000000000000000000000000000000000000000000007", + "0x5fbff498aa938ce739b8e022fbafef40563f6e6a3472fc2a514c0ce9dae23b7e", + "0x8000000000000000000000000000000150fe8a1892976154c59cfc193accf5b3", + + "0x0000000000000000000000000000000000000000000000000000000000000002", + "0x08e2a8a0e65147d4bd6316030e16d19c85c97f0a9ca267122b96abbcea7e8fc8", + "0x01" + }, + { + "GOST2001-CryptoPro-A", 256, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd97", + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd94", + "0x00000000000000000000000000000000000000000000000000000000000000a6", + "0xffffffffffffffffffffffffffffffff6c611070995ad10045841b09b761b893", + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x8d91e471e0989cda27df505a453f2b7635294f2ddf23e3b122acc99c9e9f1e14", + "0x01" + }, + { + "GOST2001-CryptoPro-B", 256, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x8000000000000000000000000000000000000000000000000000000000000c99", + "0x8000000000000000000000000000000000000000000000000000000000000c96", + "0x3e1af419a269a5f866a7d3c25c3df80ae979259373ff2b182f49d4ce7e1bbc8b", + "0x800000000000000000000000000000015f700cfff1a624e5e497161bcc8a198f", + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x3fa8124359f96680b83d1c3eb2c070e5c545c9858d03ecfb744bf8d717717efc", + "0x01" + }, + { + "GOST2001-CryptoPro-C", 256, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x9b9f605f5a858107ab1ec85e6b41c8aacf846e86789051d37998f7b9022d759b", + "0x9b9f605f5a858107ab1ec85e6b41c8aacf846e86789051d37998f7b9022d7598", + "0x000000000000000000000000000000000000000000000000000000000000805a", + "0x9b9f605f5a858107ab1ec85e6b41c8aa582ca3511eddfb74f02f3a6598980bb9", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x41ece55743711a8c3cbf3783cd08c0ee4d4dc440d4641a8f366e550dfdb3bb67", + "0x01" + }, + { + "GOST2012-test", 511, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x4531acd1fe0023c7550d267b6b2fee80922b14b2ffb90f04d4eb7c09b5d2d15d" + "f1d852741af4704a0458047e80e4546d35b8336fac224dd81664bbf528be6373", + "0x0000000000000000000000000000000000000000000000000000000000000007", + "0x1cff0806a31116da29d8cfa54e57eb748bc5f377e49400fdd788b649eca1ac4" + "361834013b2ad7322480a89ca58e0cf74bc9e540c2add6897fad0a3084f302adc", + "0x4531acd1fe0023c7550d267b6b2fee80922b14b2ffb90f04d4eb7c09b5d2d15d" + "a82f2d7ecb1dbac719905c5eecc423f1d86e25edbe23c595d644aaf187e6e6df", + + "0x24d19cc64572ee30f396bf6ebbfd7a6c5213b3b3d7057cc825f91093a68cd762" + "fd60611262cd838dc6b60aa7eee804e28bc849977fac33b4b530f1b120248a9a", + "0x2bb312a43bd2ce6e0d020613c857acddcfbf061e91e5f2c3f32447c259f39b2" + "c83ab156d77f1496bf7eb3351e1ee4e43dc1a18b91b24640b6dbb92cb1add371e", + "0x01" + }, + { + "GOST2012-tc26-A", 512, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc7", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc4", + "0xe8c2505dedfc86ddc1bd0b2b6667f1da34b82574761cb0e879bd081cfd0b6265" + "ee3cb090f30d27614cb4574010da90dd862ef9d4ebee4761503190785a71c760", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "27e69532f48d89116ff22b8d4e0560609b4b38abfad2b85dcacdb1411f10b275", + "0x0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000003", + "0x7503cfe87a836ae3a61b8816e25450e6ce5e1c93acf1abc1778064fdcbefa921" + "df1626be4fd036e93d75e6a50e3a41e98028fe5fc235f5b889a589cb5215f2a4", + "0x01" + }, + { + "GOST2012-tc26-B", 512, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0x8000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000006f", + "0x8000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000000000000000000000000006c", + "0x687d1b459dc841457e3e06cf6f5e2517b97c7d614af138bcbf85dc806c4b289f" + "3e965d2db1416d217f8b276fad1ab69c50f78bee1fa3106efb8ccbc7c5140116", + "0x8000000000000000000000000000000000000000000000000000000000000001" + "49a1ec142565a545acfdb77bd9d40cfa8b996712101bea0ec6346c54374f25bd", + "0x0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000002", + "0x1a8f7eda389b094c2c071e3647a8940f3c123b697578c213be6dd9e6c8ec7335" + "dcb228fd1edf4a39152cbcaaf8c0398828041055f94ceeec7e21340780fe41bd", + "0x01" + }, + + { + "secp256k1", 256, 0, + MPI_EC_WEIERSTRASS, ECC_DIALECT_STANDARD, + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000007", + "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", + "0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", + "0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", + "0x01" + }, + + { NULL, 0, 0, 0, 0, NULL, 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_EDWARDS: + case MPI_EC_MONTGOMERY: + break; + 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->a->sign) + mpi_add (curve->a, curve->p, curve->a); + } + if (!curve->b) + { + curve->b = scanval (domain_parms[idx].b); + if (curve->b->sign) + mpi_add (curve->b, curve->p, curve->b); + } + if (!curve->n) + curve->n = scanval (domain_parms[idx].n); + if (!curve->h) + curve->h = scanval (domain_parms[idx].h); + 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, N, and H 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, gcry_mpi_t *h) +{ + 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); + } + if (h) + { + _gcry_mpi_release (*h); + *h = scanval (domain_parms[idx].h); + } + 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, "-pabgnh", + &E.p, &E.a, &E.b, &mpi_g, &E.n, &E.h, + 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].h); + if (!mpi_cmp (tmp, E.h)) + { + 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); + _gcry_mpi_release (E.h); + 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_t h = 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; + errc = mpi_from_keyparam (&h, keyparam, "h"); + 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; + } + if (!h) + { + h = E->h; + E->h = 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; + } + if (h) + { + ec->h = h; + h = 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); + mpi_free (h); + _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[7]; + 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] = E.h; + pkey[6] = 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)(h%m)))", + pkey[0], pkey[1], pkey[2], pkey[3], pkey[4], pkey[5])) + 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, "h") && ec->h) + return mpi_is_const (ec->h) && !copy? ec->h : mpi_copy (ec->h); + 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->Q->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_EDWARDS) + { + 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 (!strcmp (name, "h")) + { + mpi_free (ec->h); + ec->h = 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/hobble-libgcrypt b/hobble-libgcrypt new file mode 100755 index 0000000..cc53cc1 --- /dev/null +++ b/hobble-libgcrypt @@ -0,0 +1,11 @@ +#!/bin/sh + +# Quit out if anything fails. +set -e -x + +# Clean out patent-or-otherwise-encumbered code. +# EC: ????????? ??/??/2015 + +rm -f cipher/ecc-curves.c +rm -f tests/curves.c +rm -f tests/t-mpi-point.c diff --git a/libgcrypt-1.6.1-mpicoder-gccopt.patch b/libgcrypt-1.6.1-mpicoder-gccopt.patch new file mode 100644 index 0000000..12555d3 --- /dev/null +++ b/libgcrypt-1.6.1-mpicoder-gccopt.patch @@ -0,0 +1,104 @@ +diff -up libgcrypt-1.6.1/mpi/mpicoder.c.gccopt libgcrypt-1.6.1/mpi/mpicoder.c +--- libgcrypt-1.6.1/mpi/mpicoder.c.gccopt 2014-02-28 15:37:53.983139821 +0100 ++++ libgcrypt-1.6.1/mpi/mpicoder.c 2014-02-28 15:47:35.312576387 +0100 +@@ -627,16 +627,16 @@ _gcry_mpi_print (enum gcry_mpi_format fo + extra = 1; + } + +- if (buffer && n > len) +- { +- /* The provided buffer is too short. */ +- xfree (tmp); +- return GPG_ERR_TOO_SHORT; +- } + if (buffer) + { + unsigned char *s = buffer; + ++ if (n > len) ++ { ++ /* The provided buffer is too short. */ ++ xfree (tmp); ++ return GPG_ERR_TOO_SHORT; ++ } + if (extra == 1) + *s++ = 0; + else if (extra) +@@ -654,13 +654,12 @@ _gcry_mpi_print (enum gcry_mpi_format fo + /* Note: We ignore the sign for this format. */ + /* FIXME: for performance reasons we should put this into + mpi_aprint because we can then use the buffer directly. */ +- +- if (buffer && n > len) +- return GPG_ERR_TOO_SHORT; + if (buffer) + { + unsigned char *tmp; + ++ if (n > len) ++ return GPG_ERR_TOO_SHORT; + tmp = _gcry_mpi_get_buffer (a, 0, &n, NULL); + if (!tmp) + return gpg_err_code_from_syserror (); +@@ -678,14 +677,14 @@ _gcry_mpi_print (enum gcry_mpi_format fo + if (negative) + return GPG_ERR_INV_ARG; + +- if (buffer && n+2 > len) +- return GPG_ERR_TOO_SHORT; +- + if (buffer) + { + unsigned char *tmp; + unsigned char *s = buffer; + ++ if (n+2 > len) ++ return GPG_ERR_TOO_SHORT; ++ + s[0] = nbits >> 8; + s[1] = nbits; + +@@ -724,16 +723,16 @@ _gcry_mpi_print (enum gcry_mpi_format fo + extra=1; + } + +- if (buffer && n+4 > len) +- { +- xfree(tmp); +- return GPG_ERR_TOO_SHORT; +- } +- + if (buffer) + { + unsigned char *s = buffer; + ++ if (n+4 > len) ++ { ++ xfree(tmp); ++ return GPG_ERR_TOO_SHORT; ++ } ++ + *s++ = n >> 24; + *s++ = n >> 16; + *s++ = n >> 8; +@@ -761,15 +760,15 @@ _gcry_mpi_print (enum gcry_mpi_format fo + if (!n || (*tmp & 0x80)) + extra = 2; + +- if (buffer && 2*n + extra + negative + 1 > len) +- { +- xfree(tmp); +- return GPG_ERR_TOO_SHORT; +- } + if (buffer) + { + unsigned char *s = buffer; + ++ if (2*n + extra + negative + 1 > len) ++ { ++ xfree(tmp); ++ return GPG_ERR_TOO_SHORT; ++ } + if (negative) + *s++ = '-'; + if (extra) diff --git a/libgcrypt-1.7.3-ecc-test-fix.patch b/libgcrypt-1.7.3-ecc-test-fix.patch new file mode 100644 index 0000000..8ce7aa9 --- /dev/null +++ b/libgcrypt-1.7.3-ecc-test-fix.patch @@ -0,0 +1,122 @@ +diff -up libgcrypt-1.7.3/tests/benchmark.c.eccfix libgcrypt-1.7.3/tests/benchmark.c +--- libgcrypt-1.7.3/tests/benchmark.c.eccfix 2016-07-14 11:19:17.000000000 +0200 ++++ libgcrypt-1.7.3/tests/benchmark.c 2016-11-22 16:21:00.109004197 +0100 +@@ -1412,7 +1412,7 @@ ecc_bench (int iterations, int print_hea + { + #if USE_ECC + gpg_error_t err; +- const char *p_sizes[] = { "192", "224", "256", "384", "521", "Ed25519", ++ const char *p_sizes[] = { "224", "256", "384", "521", "Ed25519", + "gost256", "gost512" }; + int testno; + +diff -up libgcrypt-1.7.3/tests/dsa-rfc6979.c.eccfix libgcrypt-1.7.3/tests/dsa-rfc6979.c +--- libgcrypt-1.7.3/tests/dsa-rfc6979.c.eccfix 2016-02-18 09:38:03.000000000 +0100 ++++ libgcrypt-1.7.3/tests/dsa-rfc6979.c 2016-11-22 16:22:11.804674008 +0100 +@@ -210,16 +210,6 @@ check_dsa_rfc6979 (void) + " ))" + }, + { +- "ECDSA, 192 bits (prime field)", +- "(private-key" +- " (ecdsa" +- " (curve \"NIST P-192\")" +- " (q #04AC2C77F529F91689FEA0EA5EFEC7F210D8EEA0B9E047ED56" +- " 3BC723E57670BD4887EBC732C523063D0A7C957BC97C1C43#)" +- " (d #6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4#)" +- " ))" +- }, +- { + "ECDSA, 224 bits (prime field)", + "(private-key" + " (ecdsa" +@@ -443,89 +433,6 @@ check_dsa_rfc6979 (void) + "C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1" + }, + { +- "ECDSA, 192 bits (prime field)", +- "With SHA-1, message = \"sample\"", +- "sha1", "sample", +- "37D7CA00D2C7B0E5E412AC03BD44BA837FDD5B28CD3B0021", +- "98C6BD12B23EAF5E2A2045132086BE3EB8EBD62ABF6698FF", +- "57A22B07DEA9530F8DE9471B1DC6624472E8E2844BC25B64" +- }, +- { +- "ECDSA, 192 bits (prime field)", +- "With SHA-224, message = \"sample\"", +- "sha224", "sample", +- "4381526B3FC1E7128F202E194505592F01D5FF4C5AF015D8", +- "A1F00DAD97AEEC91C95585F36200C65F3C01812AA60378F5", +- "E07EC1304C7C6C9DEBBE980B9692668F81D4DE7922A0F97A" +- }, +- { +- "ECDSA, 192 bits (prime field)", +- "With SHA-256, message = \"sample\"", +- "sha256", "sample", +- "32B1B6D7D42A05CB449065727A84804FB1A3E34D8F261496", +- "4B0B8CE98A92866A2820E20AA6B75B56382E0F9BFD5ECB55", +- "CCDB006926EA9565CBADC840829D8C384E06DE1F1E381B85" +- }, +- { +- "ECDSA, 192 bits (prime field)", +- "With SHA-384, message = \"sample\"", +- "sha384", "sample", +- "4730005C4FCB01834C063A7B6760096DBE284B8252EF4311", +- "DA63BF0B9ABCF948FBB1E9167F136145F7A20426DCC287D5", +- "C3AA2C960972BD7A2003A57E1C4C77F0578F8AE95E31EC5E" +- }, +- { +- "ECDSA, 192 bits (prime field)", +- "With SHA-512, message = \"sample\"", +- "sha512", "sample", +- "A2AC7AB055E4F20692D49209544C203A7D1F2C0BFBC75DB1", +- "4D60C5AB1996BD848343B31C00850205E2EA6922DAC2E4B8", +- "3F6E837448F027A1BF4B34E796E32A811CBB4050908D8F67" +- }, +- { +- "ECDSA, 192 bits (prime field)", +- "With SHA-1, message = \"test\"", +- "sha1", "test", +- "D9CF9C3D3297D3260773A1DA7418DB5537AB8DD93DE7FA25", +- "0F2141A0EBBC44D2E1AF90A50EBCFCE5E197B3B7D4DE036D", +- "EB18BC9E1F3D7387500CB99CF5F7C157070A8961E38700B7" +- }, +- { +- "ECDSA, 192 bits (prime field)", +- "With SHA-224, message = \"test\"", +- "sha224", "test", +- "F5DC805F76EF851800700CCE82E7B98D8911B7D510059FBE", +- "6945A1C1D1B2206B8145548F633BB61CEF04891BAF26ED34", +- "B7FB7FDFC339C0B9BD61A9F5A8EAF9BE58FC5CBA2CB15293" +- }, +- { +- "ECDSA, 192 bits (prime field)", +- "With SHA-256, message = \"test\"", +- "sha256", "test", +- "5C4CE89CF56D9E7C77C8585339B006B97B5F0680B4306C6C", +- "3A718BD8B4926C3B52EE6BBE67EF79B18CB6EB62B1AD97AE", +- "5662E6848A4A19B1F1AE2F72ACD4B8BBE50F1EAC65D9124F" +- }, +- { +- "ECDSA, 192 bits (prime field)", +- "With SHA-384, message = \"test\"", +- "sha384", "test", +- "5AFEFB5D3393261B828DB6C91FBC68C230727B030C975693", +- "B234B60B4DB75A733E19280A7A6034BD6B1EE88AF5332367", +- "7994090B2D59BB782BE57E74A44C9A1C700413F8ABEFE77A" +- }, +- { +- "ECDSA, 192 bits (prime field)", +- "With SHA-512, message = \"test\"", +- "sha512", "test", +- "0758753A5254759C7CFBAD2E2D9B0792EEE44136C9480527", +- "FE4F4AE86A58B6507946715934FE2D8FF9D95B6B098FE739", +- "74CF5605C98FBA0E1EF34D4B5A1577A7DCF59457CAE52290" +- }, +- +- +- +- { + "ECDSA, 224 bits (prime field)", + "With SHA-1, message = \"sample\"", + "sha1", "sample", diff --git a/libgcrypt-1.7.3-fips-cavs.patch b/libgcrypt-1.7.3-fips-cavs.patch new file mode 100644 index 0000000..42d028e --- /dev/null +++ b/libgcrypt-1.7.3-fips-cavs.patch @@ -0,0 +1,1311 @@ +diff -up libgcrypt-1.7.3/tests/cavs_driver.pl.cavs libgcrypt-1.7.3/tests/cavs_driver.pl +--- libgcrypt-1.7.3/tests/cavs_driver.pl.cavs 2013-03-15 20:25:38.000000000 +0100 ++++ libgcrypt-1.7.3/tests/cavs_driver.pl 2016-11-22 17:29:06.067553077 +0100 +@@ -1,9 +1,11 @@ + #!/usr/bin/env perl + # +-# $Id: cavs_driver.pl 1497 2009-01-22 14:01:29Z smueller $ ++# $Id: cavs_driver.pl 2124 2010-12-20 07:56:30Z smueller $ + # + # CAVS test driver (based on the OpenSSL driver) + # Written by: Stephan Müller ++# Werner Koch (libgcrypt interface) ++# Tomas Mraz (addition of DSA2) + # Copyright (c) atsec information security corporation + # + # Permission is hereby granted, free of charge, to any person obtaining a copy +@@ -85,13 +87,16 @@ + # T[CBC|CFB??|ECB|OFB]varkey + # T[CBC|CFB??|ECB|OFB]invperm + # T[CBC|CFB??|ECB|OFB]vartext ++# WARNING: TDES in CFB and OFB mode problems see below + # + # ANSI X9.31 RNG + # ANSI931_AES128MCT + # ANSI931_AES128VST + # +-# DSA ++# DSA2 + # PQGGen ++# PQGVer ++# KeyPair + # SigGen + # SigVer + # +@@ -101,6 +106,36 @@ + # RC4PltBD + # RC4REGT + # ++# ++# TDES MCT for CFB and OFB: ++# ------------------------- ++# The inner loop cannot be handled by this script. If you want to have tests ++# for these cipher types, implement your own inner loop and add it to ++# crypto_mct. ++# ++# the value $next_source in crypto_mct is NOT set by the standard implementation ++# of this script. It would need to be set as follows for these two (code take ++# from fipsdrv.c from libgcrypt - the value input at the end will contain the ++# the value for $next_source: ++# ++# ... inner loop ... ++# ... ++# get_current_iv (hd, last_iv, blocklen); ++# ... encrypt / decrypt (input is the data to be en/decrypted and output is the ++# result of operation) ... ++# if (encrypt_mode && (cipher_mode == GCRY_CIPHER_MODE_CFB)) ++# memcpy (input, last_iv, blocklen); ++# else if (cipher_mode == GCRY_CIPHER_MODE_OFB) ++# memcpy (input, last_iv, blocklen); ++# else if (!encrypt_mode && cipher_mode == GCRY_CIPHER_MODE_CFB) ++# { ++# /* Reconstruct the output vector. */ ++# int i; ++# for (i=0; i < blocklen; i++) ++# input[i] ^= output[i]; ++# } ++# ... inner loop ends ... ++# ==> now, the value of input is to be put into $next_source + + use strict; + use warnings; +@@ -226,6 +261,8 @@ my $hmac; + # Generate the P, Q, G, Seed, counter, h (value used to generate g) values + # for DSA + # $1: modulus size ++# $2: q size ++# $3: seed (might be empty string) + # return: string with the calculated values in hex format, where each value + # is separated from the previous with a \n in the following order: + # P\n +@@ -236,6 +273,19 @@ my $hmac; + # h + my $dsa_pqggen; + ++# Generate the G value from P and Q ++# for DSA ++# $1: modulus size ++# $2: q size ++# $3: P in hex form ++# $4: Q in hex form ++# return: string with the calculated values in hex format, where each value ++# is separated from the previous with a \n in the following order: ++# P\n ++# Q\n ++# G\n ++my $dsa_ggen; ++ + # + # Generate an DSA public key from the provided parameters: + # $1: Name of file to create +@@ -255,16 +305,30 @@ my $dsa_verify; + + # generate a new DSA key with the following properties: + # PEM format +-# $1 keyfile name +-# return: file created, hash with keys of P, Q, G in hex format ++# $1: modulus size ++# $2: q size ++# $3 keyfile name ++# return: file created with key, string with values of P, Q, G in hex format + my $gen_dsakey; + ++# generate a new DSA private key XY parameters in domain: ++# PEM format ++# $1: P in hex form ++# $2: Q in hex form ++# $3: G in hex form ++# return: string with values of X, Y in hex format ++my $gen_dsakey_domain; ++ + # Sign a message with DSA + # $1: data to be signed in hex form + # $2: Key file in PEM format with the private key + # return: hash of digest information in hex format with Y, R, S as keys + my $dsa_sign; + ++my $rsa_keygen; ++ ++my $rsa_keygen_kat; ++ + ################################################################ + ##### OpenSSL interface functions + ################################################################ +@@ -404,6 +468,35 @@ sub libgcrypt_rsa_derive($$$$$$$$) { + } + + ++sub libgcrypt_rsa_keygen($) { ++ my $n = shift; ++ my $sexp; ++ ++ $n = sprintf ("%u", $n); ++ $sexp = "(genkey(rsa(nbits " . sprintf ("%u:%s", length($n), $n) . ")))\n"; ++ ++ return pipe_through_program($sexp, "fipsdrv rsa-keygen"); ++} ++ ++ ++sub libgcrypt_rsa_keygen_kat($$$$) { ++ my $n = shift; ++ my $e = shift; ++ my $p = shift; ++ my $q = shift; ++ my $sexp; ++ ++ $n = sprintf ("%u", $n); ++ $sexp = "(genkey(rsa(nbits " . sprintf ("%u:%s", length($n), $n) . ")" ++ . "(test-parms" ++ . "(e #$e#)" ++ . "(p #$p#)" ++ . "(q #$q#))))\n"; ++ ++ return pipe_through_program($sexp, "fipsdrv rsa-keygen-kat"); ++} ++ ++ + sub libgcrypt_rsa_sign($$$) { + my $data = shift; + my $hashalgo = shift; +@@ -500,17 +593,32 @@ sub libgcrypt_hmac($$$$) { + return pipe_through_program($msg, $program); + } + +-sub libgcrypt_dsa_pqggen($) { ++sub libgcrypt_dsa_pqggen($$$) { ++ my $mod = shift; ++ my $qsize = shift; ++ my $seed = shift; ++ ++ my $program = "fipsdrv --keysize $mod --qsize $qsize dsa-pqg-gen"; ++ return pipe_through_program($seed, $program); ++} ++ ++sub libgcrypt_dsa_ggen($$$$) { + my $mod = shift; ++ my $qsize = shift; ++ my $p = shift; ++ my $q = shift; ++ my $domain = "(domain (p #$p#)(q #$q#))"; + +- my $program = "fipsdrv --keysize $mod dsa-pqg-gen"; ++ my $program = "fipsdrv --keysize $mod --qsize $qsize --key \'$domain\' dsa-g-gen"; + return pipe_through_program("", $program); + } + +-sub libgcrypt_gen_dsakey($) { ++sub libgcrypt_gen_dsakey($$$) { ++ my $mod = shift; ++ my $qsize = shift; + my $file = shift; + +- my $program = "fipsdrv --keysize 1024 --key $file dsa-gen"; ++ my $program = "fipsdrv --keysize $mod --qsize $qsize --key $file dsa-gen"; + my $tmp; + my %ret; + +@@ -519,10 +627,21 @@ sub libgcrypt_gen_dsakey($) { + $tmp = pipe_through_program("", $program); + die "dsa key gen failed: file $file not created" if (! -f $file); + +- @ret{'P', 'Q', 'G', 'Seed', 'c', 'H'} = split(/\n/, $tmp); ++ @ret{'P', 'Q', 'G'} = split(/\n/, $tmp); + return %ret; + } + ++sub libgcrypt_gen_dsakey_domain($$$) { ++ my $p = shift; ++ my $q = shift; ++ my $g = shift; ++ my $domain = "(domain (p #$p#)(q #$q#)(g #$g#))"; ++ ++ my $program = "fipsdrv --key '$domain' dsa-gen-key"; ++ ++ return pipe_through_program("", $program); ++} ++ + sub libgcrypt_dsa_genpubkey($$$$$) { + my $filename = shift; + my $p = shift; +@@ -1139,7 +1258,7 @@ sub hmac_kat($$$$) { + $out .= "Tlen = $tlen\n"; + $out .= "Key = $key\n"; + $out .= "Msg = $msg\n"; +- $out .= "Mac = " . &$hmac($key, $tlen, $msg, $hashtype{$tlen}) . "\n"; ++ $out .= "Mac = " . lc(&$hmac($key, $tlen, $msg, $hashtype{$tlen})) . "\n"; + + return $out; + } +@@ -1205,7 +1324,7 @@ sub crypto_mct($$$$$$$$) { + } + my ($CO, $CI); + my $cipher_imp = &$state_cipher($cipher, $enc, $bufsize, $key1, $iv); +- $cipher_imp = &$state_cipher_des($cipher, $enc, $bufsize, $key1, $iv) if($cipher =~ /des/); ++ $cipher_imp = &$state_cipher_des($cipher, $enc, $bufsize, $key1, $iv) if($cipher =~ /des/ && defined($state_cipher_des)); + my $pid = open2($CO, $CI, $cipher_imp); + + my $calc_data = $iv; # CT[j] +@@ -1213,8 +1332,8 @@ sub crypto_mct($$$$$$$$) { + my $old_old_calc_data; # CT[j-2] + my $next_source; + +- # TDES inner loop implements logic within driver +- if ($cipher =~ /des/) { ++ # TDES inner loop implements logic within driver of libgcrypt ++ if ($cipher =~ /des/ && $opt{'I'} && $opt{'I'} eq 'libgcrypt' ) { + # Need to provide a dummy IV in case of ECB mode. + my $iv_arg = (defined($iv) && $iv ne "") + ? bin2hex($iv) +@@ -1238,6 +1357,10 @@ sub crypto_mct($$$$$$$$) { + $line = <$CO>; + } else { + for (my $j = 0; $j < $iloop; ++$j) { ++ if ($cipher =~ /des-ede3-ofb/ || ++ (!$enc && $cipher =~ /des-ede3-cfb/)) { ++ die "Implementation lacks support for TDES OFB and TDES CFB in encryption mode - the problem is that we would need to extract the IV of the last round of encryption which would be the input for the next round - see comments in this script for implementation requirements"; ++ } + $old_old_calc_data = $old_calc_data; + $old_calc_data = $calc_data; + +@@ -1429,7 +1552,7 @@ sub rsa_sigver($$$$$) { + # $7 xq2 + # $8 Xq + # return: string formatted as expected by CAVS +-sub rsa_keygen($$$$$$$$) { ++sub rsa_keygen_x931($$$$$$$$) { + my $modulus = shift; + my $e = shift; + my $xp1 = shift; +@@ -1503,21 +1626,23 @@ sub rngx931($$$$) { + return $out; + } + +-# DSA PQGGen test ++# DSA PQGen test + # $1 modulus size +-# $2 number of rounds to perform the test ++# $2 q size ++# $3 number of rounds to perform the test + # return: string formatted as expected by CAVS +-sub dsa_pqggen_driver($$) { ++sub dsa_pqgen_driver($$$) { + my $mod = shift; ++ my $qsize = shift; + my $rounds = shift; + + my $out = ""; + for(my $i=0; $i<$rounds; $i++) { +- my $ret = &$dsa_pqggen($mod); ++ my $ret = &$dsa_pqggen($mod, $qsize, ""); + my ($P, $Q, $G, $Seed, $c, $H) = split(/\n/, $ret); +- die "Return value does not contain all expected values of P, Q, G, Seed, c, H for dsa_pqggen" +- if (!defined($P) || !defined($Q) || !defined($G) || +- !defined($Seed) || !defined($c) || !defined($H)); ++ die "Return value does not contain all expected values of P, Q, Seed, c for dsa_pqggen" ++ if (!defined($P) || !defined($Q) || ++ !defined($Seed) || !defined($c)); + + # now change the counter to decimal as CAVS wants decimal + # counter value although all other is HEX +@@ -1525,15 +1650,166 @@ sub dsa_pqggen_driver($$) { + + $out .= "P = $P\n"; + $out .= "Q = $Q\n"; +- $out .= "G = $G\n"; +- $out .= "Seed = $Seed\n"; +- $out .= "c = $c\n"; +- $out .= "H = $H\n\n"; ++ $out .= "domain_parameter_seed = $Seed\n"; ++ $out .= "counter = $c\n\n"; + } + + return $out; + } + ++# DSA GGen test ++# $1 modulus size ++# $2 q size ++# $3 p in hex form ++# $4 q in hex form ++# return: string formatted as expected by CAVS ++sub dsa_ggen_driver($$$$) { ++ my $mod = shift; ++ my $qsize = shift; ++ my $p = shift; ++ my $q = shift; ++ ++ my $out = ""; ++ my $ret = &$dsa_ggen($mod, $qsize, $p, $q); ++ my ($P, $Q, $G) = split(/\n/, $ret); ++ die "Return value does not contain all expected values of P, Q, G for dsa_ggen" ++ if (!defined($P) || !defined($Q) || !defined($G)); ++ ++ $out .= "G = $G\n\n"; ++ ++ return $out; ++} ++ ++sub hexcomp($$) { ++ my $a = lc shift; ++ my $b = lc shift; ++ ++ if (length $a < length $b) { ++ my $c = $a; ++ $a = $b; ++ $b = $a; ++ } ++ ++ while (length $b < length $a) { ++ $b = "00$b"; ++ } ++ ++ return $a eq $b; ++} ++ ++# DSA PQVer test ++# $1 modulus size ++# $2 q size ++# $3 p in hex form ++# $4 q in hex form ++# $5 seed in hex form ++# $6 c decimal counter ++# return: string formatted as expected by CAVS ++sub dsa_pqver_driver($$$$$$) { ++ my $mod = shift; ++ my $qsize = shift; ++ my $p = shift; ++ my $q = shift; ++ my $seed = shift; ++ my $c = shift; ++ ++ my $out = ""; ++ my $ret = &$dsa_pqggen($mod, $qsize, $seed); ++ my ($P, $Q, $G, $seed2, $c2, $h2) = split(/\n/, $ret); ++ die "Return value does not contain all expected values of P, Q, G, seed, c for dsa_pqggen" ++ if (!defined($P) || !defined($Q) || !defined($G) || ++ !defined($seed2) || !defined($c2)); ++ ++ $c2 = hex($c2); ++ ++ $out .= "Seed = $seed\n"; ++ $out .= "c = $c\n"; ++ ++ if (hexcomp($P, $p) && hexcomp($Q, $q) && hexcomp($seed, $seed2) && $c == $c2) { ++ $out .= "Result = P\n\n"; ++ } ++ else { ++ $out .= "Result = F\n\n"; ++ } ++ return $out; ++} ++ ++# DSA PQGVer test ++# $1 modulus size ++# $2 q size ++# $3 p in hex form ++# $4 q in hex form ++# $5 g in hex form ++# $6 seed in hex form ++# $7 c decimal counter ++# $8 h in hex form ++# return: string formatted as expected by CAVS ++sub dsa_pqgver_driver($$$$$$$$) { ++ my $mod = shift; ++ my $qsize = shift; ++ my $p = shift; ++ my $q = shift; ++ my $g = shift; ++ my $seed = shift; ++ my $c = shift; ++ my $h = shift; ++ ++ my $out = ""; ++ my $ret = &$dsa_pqggen($mod, $qsize, $seed); ++ my ($P, $Q, $G, $seed2, $c2, $h2) = split(/\n/, $ret); ++ die "Return value does not contain all expected values of P, Q, G, seed, c, H for dsa_pqggen" ++ if (!defined($P) || !defined($Q) || !defined($G) || ++ !defined($seed2) || !defined($c2) || !defined($h2)); ++ ++ ++ ++ $out .= "Seed = $seed\n"; ++ $out .= "c = $c\n"; ++ $out .= "H = $h\n"; ++ ++ $c2 = hex($c2); ++ ++ if (hexcomp($P, $p) && hexcomp($Q, $q) && hexcomp($G, $g) && hexcomp($seed, $seed2) && ++ $c == $c2 && hex($h) == hex($h2)) { ++ $out .= "Result = P\n\n"; ++ } ++ else { ++ $out .= "Result = F\n\n"; ++ } ++ ++ return $out; ++} ++ ++# DSA Keypair test ++# $1 modulus size ++# $2 q size ++# $3 number of rounds to perform the test ++# return: string formatted as expected by CAVS ++sub dsa_keypair_driver($$$) { ++ my $mod = shift; ++ my $qsize = shift; ++ my $rounds = shift; ++ ++ my $out = ""; ++ my $tmpkeyfile = "dsa_siggen.tmp.$$"; ++ my %pqg = &$gen_dsakey($mod, $qsize, $tmpkeyfile); ++ $out .= "P = " . $pqg{'P'} . "\n"; ++ $out .= "Q = " . $pqg{'Q'} . "\n"; ++ $out .= "G = " . $pqg{'G'} . "\n\n"; ++ unlink($tmpkeyfile); ++ ++ for(my $i=0; $i<$rounds; $i++) { ++ my $ret = &$gen_dsakey_domain($pqg{'P'}, $pqg{'Q'}, $pqg{'G'}); ++ my ($X, $Y) = split(/\n/, $ret); ++ die "Return value does not contain all expected values of X, Y for gen_dsakey_domain" ++ if (!defined($X) || !defined($Y)); ++ ++ $out .= "X = $X\n"; ++ $out .= "Y = $Y\n\n"; ++ } ++ ++ return $out; ++} + + # DSA SigGen test + # $1: Message to be signed in hex form +@@ -1598,6 +1874,53 @@ sub dsa_sigver($$$$$$$$) { + return $out; + } + ++# RSA Keygen RPP test ++# $1 modulus size ++# $2 number of rounds to perform the test ++# return: string formatted as expected by CAVS ++sub rsa_keygen_driver($$) { ++ my $mod = shift; ++ my $rounds = shift; ++ ++ my $out = ""; ++ ++ for(my $i=0; $i<$rounds; $i++) { ++ my $ret = &$rsa_keygen($mod); ++ my ($e, $p, $q, $n, $d) = split(/\n/, $ret); ++ die "Return value does not contain all expected values of e, p, q, n, d for rsa_keygen" ++ if (!defined($e) || !defined($p) || !defined($q) || !defined($n) || !defined($d)); ++ ++ $out .= "e = $e\n"; ++ $out .= "p = $p\n"; ++ $out .= "q = $q\n"; ++ $out .= "n = $n\n"; ++ $out .= "d = $d\n\n"; ++ } ++ ++ return $out; ++} ++ ++# RSA RPP Keygen KAT test ++# $1 modulus size ++# $2 p in hex form ++# $3 q in hex form ++# return: string formatted as expected by CAVS ++sub rsa_keygen_kat_driver($$$) { ++ my $mod = shift; ++ my $p = shift; ++ my $q = shift; ++ ++ my $out = ""; ++ my $ret = &$rsa_keygen_kat($mod, $p, $q); ++ my ($Result) = split(/\n/, $ret); ++ die "Return value does not contain all expected values of Result for rsa_keygen_kat" ++ if (!defined($Result)); ++ ++ $out .= "Result = $Result\n\n"; ++ return $out; ++} ++ ++ + ############################################################## + # Parser of input file and generator of result file + # +@@ -1658,12 +1981,18 @@ sub parse($$) { + my $klen = ""; + my $tlen = ""; + my $modulus = ""; ++ my $qsize = ""; + my $capital_n = 0; ++ my $num = 0; + my $capital_p = ""; + my $capital_q = ""; + my $capital_g = ""; + my $capital_y = ""; + my $capital_r = ""; ++ my $capital_h = ""; ++ my $c = ""; ++ my $prandom = ""; ++ my $qrandom = ""; + my $xp1 = ""; + my $xp2 = ""; + my $Xp = ""; +@@ -1700,7 +2029,7 @@ sub parse($$) { + + ##### Extract cipher + # XXX there may be more - to be added +- if ($tmpline =~ /^#.*(CBC|ECB|OFB|CFB|SHA-|SigGen|SigVer|RC4VS|ANSI X9\.31|Hash sizes tested|PQGGen|KeyGen RSA)/) { ++ if ($tmpline =~ /^#.*(CBC|ECB|OFB|CFB|SHA-|SigGen|SigVer|RC4VS|ANSI X9\.31|Hash sizes tested|PQGGen|KeyGen RSA|KeyGen - Random Probably Prime|KeyPair|PQGVer)/) { + if ($tmpline =~ /CBC/) { $mode="cbc"; } + elsif ($tmpline =~ /ECB/) { $mode="ecb"; } + elsif ($tmpline =~ /OFB/) { $mode="ofb"; } +@@ -1749,7 +2078,23 @@ sub parse($$) { + + if ($tt == 0) { + ##### Identify the test type +- if ($tmpline =~ /KeyGen RSA \(X9\.31\)/) { ++ if ($tmpline =~ /KeyGen - Random Probably Prime Known Answer Test/) { ++ $tt = 19; ++ die "Interface function rsa_keygen_kat for RSA key generation KAT not defined for tested library" ++ if (!defined($rsa_keygen_kat)); ++ } elsif ($tmpline =~ /KeyGen - Random Probably Prime Test/) { ++ $tt = 18; ++ die "Interface function rsa_keygen for RSA key generation not defined for tested library" ++ if (!defined($rsa_keygen)); ++ } elsif ($tmpline =~ /PQGVer/) { ++ $tt = 16; ++ die "Interface function for DSA PQGVer testing not defined for tested library" ++ if (!defined($dsa_pqggen)); ++ } elsif ($tmpline =~ /KeyPair/) { ++ $tt = 14; ++ die "Interface function dsa_keygen for DSA key generation not defined for tested library" ++ if (!defined($gen_dsakey_domain)); ++ } elsif ($tmpline =~ /KeyGen RSA \(X9\.31\)/) { + $tt = 13; + die "Interface function rsa_derive for RSA key generation not defined for tested library" + if (!defined($rsa_derive)); +@@ -1760,11 +2105,11 @@ sub parse($$) { + } elsif ($tmpline =~ /SigGen/ && $opt{'D'}) { + $tt = 11; + die "Interface function dsa_sign or gen_dsakey for DSA sign not defined for tested library" +- if (!defined($dsa_sign) || !defined($gen_rsakey)); ++ if (!defined($dsa_sign) || !defined($gen_dsakey)); + } elsif ($tmpline =~ /PQGGen/) { + $tt = 10; + die "Interface function for DSA PQGGen testing not defined for tested library" +- if (!defined($dsa_pqggen)); ++ if (!defined($dsa_pqggen) || !defined($dsa_ggen)); + } elsif ($tmpline =~ /Hash sizes tested/) { + $tt = 9; + die "Interface function hmac for HMAC testing not defined for tested library" +@@ -1792,7 +2137,7 @@ sub parse($$) { + } elsif ($tmpline =~ /Monte|MCT|Carlo/) { + $tt = 2; + die "Interface function state_cipher for Stateful Cipher operation defined for tested library" +- if (!defined($state_cipher) || !defined($state_cipher_des)); ++ if (!defined($state_cipher) && !defined($state_cipher_des)); + } elsif ($cipher =~ /^sha/) { + $tt = 3; + die "Interface function hash for Hashing not defined for tested library" +@@ -1875,18 +2220,44 @@ sub parse($$) { + die "Msg/Seed seen twice - input file crap" if ($pt ne ""); + $pt=$2; + } +- elsif ($line =~ /^\[mod\s*=\s*(.*)\]$/) { # found in RSA requests ++ elsif ($line =~ /^\[A.2.1\s.*\]$/) { # found in DSA2 PQGGen request ++ $out .= $line . "\n"; # print it ++ if ($tt == 10) { ++ # now generate G from PQ ++ $tt = 15; ++ } ++ } ++ elsif ($line =~ /^\[A.2.2\s.*\]$/) { # found in DSA2 PQGVer request ++ $out .= $line . "\n"; # print it ++ if ($tt == 16) { ++ # now verify PQG ++ $tt = 17; ++ } ++ } ++ elsif ($line =~ /^\[mod\s*=\s*L=([0-9]*),\s*N=([0-9]*).*\]$/) { # found in DSA2 requests + $modulus = $1; ++ $qsize = $2; + $out .= $line . "\n\n"; # print it ++ # clear eventual PQG ++ $capital_p = ""; ++ $capital_q = ""; ++ $capital_g = ""; + # generate the private key with given bit length now + # as we have the required key length in bit + if ($tt == 11) { + $dsa_keyfile = "dsa_siggen.tmp.$$"; +- my %pqg = &$gen_dsakey($dsa_keyfile); ++ my %pqg = &$gen_dsakey($modulus, $qsize, $dsa_keyfile); + $out .= "P = " . $pqg{'P'} . "\n"; + $out .= "Q = " . $pqg{'Q'} . "\n"; +- $out .= "G = " . $pqg{'G'} . "\n"; +- } elsif ( $tt == 5 ) { ++ $out .= "G = " . $pqg{'G'} . "\n\n"; ++ } ++ } ++ elsif ($line =~ /^\[mod\s*=\s*(.*)\]$/) { # found in RSA requests ++ $modulus = $1; ++ $out .= $line . "\n\n"; # print it ++ # generate the private key with given bit length now ++ # as we have the required key length in bit ++ if ( $tt == 5 ) { + # XXX maybe a secure temp file name is better here + # but since it is not run on a security sensitive + # system, I hope that this is fine +@@ -1907,6 +2278,9 @@ sub parse($$) { + } + elsif ($line =~ /^e\s*=\s*(.*)/) { # found in RSA requests + $e=$1; ++ if ($tt == 19) { ++ $out .= $line . "\n"; # print it ++ } + } + elsif ($line =~ /^S\s*=\s*(.*)/) { # found in RSA requests + die "S seen twice - input file crap" if ($signature ne ""); +@@ -1932,11 +2306,16 @@ sub parse($$) { + if ($tlen ne ""); + $tlen=$1; + } +- elsif ($line =~ /^N\s*=\s*(.*)/) { #DSA PQGGen ++ elsif ($line =~ /^N\s*=\s*(.*)/) { #DSA KeyPair + die "N seen twice - check input file" + if ($capital_n); + $capital_n = $1; + } ++ elsif ($line =~ /^Num\s*=\s*(.*)/) { #DSA PQGGen ++ die "Num seen twice - check input file" ++ if ($num); ++ $num = $1; ++ } + elsif ($line =~ /^P\s*=\s*(.*)/) { #DSA SigVer + die "P seen twice - check input file" + if ($capital_p); +@@ -1965,6 +2344,16 @@ sub parse($$) { + if ($capital_r); + $capital_r = $1; + } ++ elsif ($line =~ /^H\s*=\s*(.*)/) { #DSA PQGVer ++ die "H seen twice - check input file" ++ if ($capital_h); ++ $capital_h = $1; ++ } ++ elsif ($line =~ /^c\s*=\s*(.*)/) { #DSA PQGVer ++ die "c seen twice - check input file" ++ if ($c); ++ $c = $1; ++ } + elsif ($line =~ /^xp1\s*=\s*(.*)/) { #RSA key gen + die "xp1 seen twice - check input file" + if ($xp1); +@@ -1995,6 +2384,22 @@ sub parse($$) { + if ($Xq); + $Xq = $1; + } ++ elsif ($line =~ /^prandom\s*=\s*(.*)/) { #RSA key gen KAT ++ die "prandom seen twice - check input file" ++ if ($prandom); ++ $prandom = $1; ++ $out .= $line . "\n"; # print it ++ } ++ elsif ($line =~ /^qrandom\s*=\s*(.*)/) { #RSA key gen KAT ++ die "qrandom seen twice - check input file" ++ if ($qrandom); ++ $qrandom = $1; ++ $out .= $line . "\n"; # print it ++ } ++ elsif ($tt == 19 && $line =~ /^ / && $qrandom eq "") { #RSA key gen KAT ++ $qrandom = "00"; ++ $out .= $line . "\n"; # print it ++ } + else { + $out .= $line . "\n"; + } +@@ -2074,11 +2479,10 @@ sub parse($$) { + } + } + elsif ($tt == 10) { +- if ($modulus ne "" && $capital_n > 0) { +- $out .= dsa_pqggen_driver($modulus, $capital_n); +- #$mod is not resetted +- $capital_n = 0; +- } ++ if ($modulus ne "" && $qsize ne "" && $num > 0) { ++ $out .= dsa_pqgen_driver($modulus, $qsize, $num); ++ $num = 0; ++ } + } + elsif ($tt == 11) { + if ($pt ne "" && $dsa_keyfile ne "") { +@@ -2124,7 +2528,7 @@ sub parse($$) { + $xq1 ne "" && + $xq2 ne "" && + $Xq ne "") { +- $out .= rsa_keygen($modulus, ++ $out .= rsa_keygen_x931($modulus, + $e, + $xp1, + $xp2, +@@ -2141,6 +2545,96 @@ sub parse($$) { + $Xq = ""; + } + } ++ elsif ($tt == 14) { ++ if ($modulus ne "" && ++ $qsize ne "" && ++ $capital_n > 0) { ++ $out .= dsa_keypair_driver($modulus, ++ $qsize, ++ $capital_n); ++ $capital_n = 0; ++ } ++ } ++ elsif ($tt == 15) { ++ if ($modulus ne "" && ++ $qsize ne "" && ++ $capital_p ne "" && ++ $capital_q ne "") { ++ $out .= dsa_ggen_driver($modulus, ++ $qsize, ++ $capital_p, ++ $capital_q); ++ $capital_p = ""; ++ $capital_q = ""; ++ $num--; ++ } ++ } ++ elsif ($tt == 16) { ++ if ($modulus ne "" && ++ $qsize ne "" && ++ $capital_p ne "" && ++ $capital_q ne "" && ++ $pt ne "" && ++ $c ne "") { ++ $out .= dsa_pqver_driver($modulus, ++ $qsize, ++ $capital_p, ++ $capital_q, ++ $pt, ++ $c); ++ $capital_p = ""; ++ $capital_q = ""; ++ $pt = ""; ++ $c = ""; ++ } ++ } ++ elsif ($tt == 17) { ++ if ($modulus ne "" && ++ $qsize ne "" && ++ $capital_p ne "" && ++ $capital_q ne "" && ++ $capital_g ne "" && ++ $pt ne "" && ++ $c ne "" && ++ $capital_h ne "") { ++ $out .= dsa_pqgver_driver($modulus, ++ $qsize, ++ $capital_p, ++ $capital_q, ++ $capital_g, ++ $pt, ++ $c, ++ $capital_h); ++ $capital_p = ""; ++ $capital_q = ""; ++ $capital_g = ""; ++ $pt = ""; ++ $c = ""; ++ $capital_h = ""; ++ } ++ } ++ elsif ($tt == 18) { ++ if ($modulus ne "" && ++ $capital_n > 0) { ++ $out .= rsa_keygen_driver($modulus, ++ $capital_n); ++ $capital_n = 0; ++ } ++ } ++ elsif ($tt == 19) { ++ if ($modulus ne "" && ++ $e ne "" && ++ $prandom ne "" && ++ $qrandom ne "") { ++ $out .= rsa_keygen_kat_driver($modulus, ++ $e, ++ $prandom, ++ $qrandom); ++ $prandom = ""; ++ $qrandom = ""; ++ $e = ""; ++ } ++ } + elsif ($tt > 0) { + die "Test case $tt not defined"; + } +@@ -2199,10 +2693,14 @@ sub main() { + $state_rng = \&libgcrypt_state_rng; + $hmac = \&libgcrypt_hmac; + $dsa_pqggen = \&libgcrypt_dsa_pqggen; ++ $dsa_ggen = \&libgcrypt_dsa_ggen; + $gen_dsakey = \&libgcrypt_gen_dsakey; ++ $gen_dsakey_domain = \&libgcrypt_gen_dsakey_domain; + $dsa_sign = \&libgcrypt_dsa_sign; + $dsa_verify = \&libgcrypt_dsa_verify; + $dsa_genpubkey = \&libgcrypt_dsa_genpubkey; ++ $rsa_keygen = \&libgcrypt_rsa_keygen; ++ $rsa_keygen_kat = \&libgcrypt_rsa_keygen_kat; + } else { + die "Invalid interface option given"; + } +diff -up libgcrypt-1.7.3/tests/cavs_tests.sh.cavs libgcrypt-1.7.3/tests/cavs_tests.sh +--- libgcrypt-1.7.3/tests/cavs_tests.sh.cavs 2013-03-15 20:25:38.000000000 +0100 ++++ libgcrypt-1.7.3/tests/cavs_tests.sh 2016-11-22 17:29:06.067553077 +0100 +@@ -55,7 +55,7 @@ function run_one_test () { + [ -d "$respdir" ] || mkdir "$respdir" + [ -f "$rspfile" ] && rm "$rspfile" + +- if echo "$reqfile" | grep '/DSA/req/' >/dev/null 2>/dev/null; then ++ if echo "$reqfile" | grep '/DSA.\?/req/' >/dev/null 2>/dev/null; then + dflag="-D" + fi + +diff -up libgcrypt-1.7.3/tests/fipsdrv.c.cavs libgcrypt-1.7.3/tests/fipsdrv.c +--- libgcrypt-1.7.3/tests/fipsdrv.c.cavs 2016-07-14 11:19:17.000000000 +0200 ++++ libgcrypt-1.7.3/tests/fipsdrv.c 2016-11-22 17:33:15.468330859 +0100 +@@ -892,6 +892,9 @@ print_mpi_line (gcry_mpi_t a, int no_lz) + die ("gcry_mpi_aprint failed: %s\n", gpg_strerror (err)); + + p = buf; ++ while (*p) ++ *p++ = tolower(*p); ++ p = buf; + if (no_lz && p[0] == '0' && p[1] == '0' && p[2]) + p += 2; + +@@ -1765,14 +1768,14 @@ run_rsa_verify (const void *data, size_t + /* Generate a DSA key of size KEYSIZE and return the complete + S-expression. */ + static gcry_sexp_t +-dsa_gen (int keysize) ++dsa_gen (int keysize, int qsize) + { + gpg_error_t err; + gcry_sexp_t keyspec, key; + + err = gcry_sexp_build (&keyspec, NULL, +- "(genkey (dsa (nbits %d)(use-fips186-2)))", +- keysize); ++ "(genkey (dsa (nbits %d)(qbits %d)(use-fips186)))", ++ keysize, qsize); + if (err) + die ("gcry_sexp_build failed for DSA key generation: %s\n", + gpg_strerror (err)); +@@ -1790,7 +1793,7 @@ dsa_gen (int keysize) + /* Generate a DSA key of size KEYSIZE and return the complete + S-expression. */ + static gcry_sexp_t +-dsa_gen_with_seed (int keysize, const void *seed, size_t seedlen) ++dsa_gen_with_seed (int keysize, int qsize, const void *seed, size_t seedlen) + { + gpg_error_t err; + gcry_sexp_t keyspec, key; +@@ -1799,10 +1802,11 @@ dsa_gen_with_seed (int keysize, const vo + "(genkey" + " (dsa" + " (nbits %d)" +- " (use-fips186-2)" ++ " (qbits %d)" ++ " (use-fips186)" + " (derive-parms" + " (seed %b))))", +- keysize, (int)seedlen, seed); ++ keysize, qsize, (int)seedlen, seed); + if (err) + die ("gcry_sexp_build failed for DSA key generation: %s\n", + gpg_strerror (err)); +@@ -1810,6 +1814,37 @@ dsa_gen_with_seed (int keysize, const vo + err = gcry_pk_genkey (&key, keyspec); + if (err) + die ("gcry_pk_genkey failed for DSA: %s\n", gpg_strerror (err)); ++ ++ gcry_sexp_release (keyspec); ++ ++ return key; ++} ++ ++/* Generate a DSA key with specified domain parameters and return the complete ++ S-expression. */ ++static gcry_sexp_t ++dsa_gen_key (const char *domain) ++{ ++ gpg_error_t err; ++ gcry_sexp_t keyspec, key, domspec; ++ ++ err = gcry_sexp_new (&domspec, domain, strlen(domain), 0); ++ if (err) ++ die ("gcry_sexp_build failed for domain spec: %s\n", ++ gpg_strerror (err)); ++ ++ err = gcry_sexp_build (&keyspec, NULL, ++ "(genkey" ++ " (dsa" ++ " (use-fips186)" ++ " %S))", ++ domspec); ++ if (err) ++ die ("gcry_sexp_build failed for DSA key generation: %s\n", ++ gpg_strerror (err)); ++ err = gcry_pk_genkey (&key, keyspec); ++ if (err) ++ die ("gcry_pk_genkey failed for DSA: %s\n", gpg_strerror (err)); + + gcry_sexp_release (keyspec); + +@@ -1849,7 +1884,7 @@ ecdsa_gen_key (const char *curve) + with one parameter per line in hex format using this order: p, q, + g, seed, counter, h. */ + static void +-print_dsa_domain_parameters (gcry_sexp_t key) ++print_dsa_domain_parameters (gcry_sexp_t key, int print_misc) + { + gcry_sexp_t l1, l2; + gcry_mpi_t mpi; +@@ -1885,6 +1920,9 @@ print_dsa_domain_parameters (gcry_sexp_t + } + gcry_sexp_release (l1); + ++ if (!print_misc) ++ return; ++ + /* Extract the seed values. */ + l1 = gcry_sexp_find_token (key, "misc-key-info", 0); + if (!l1) +@@ -1976,38 +2014,106 @@ print_ecdsa_dq (gcry_sexp_t key) + } + + +-/* Generate DSA domain parameters for a modulus size of KEYSIZE. The ++/* Print just the XY private key parameters. KEY ++ is the complete key as returned by dsa_gen. We print to stdout ++ with one parameter per line in hex format using this order: x, y. */ ++static void ++print_dsa_xy (gcry_sexp_t key) ++{ ++ gcry_sexp_t l1, l2; ++ gcry_mpi_t mpi; ++ int idx; ++ ++ l1 = gcry_sexp_find_token (key, "private-key", 0); ++ if (!l1) ++ die ("private key not found in genkey result\n"); ++ ++ l2 = gcry_sexp_find_token (l1, "dsa", 0); ++ if (!l2) ++ die ("returned private key not formed as expected\n"); ++ gcry_sexp_release (l1); ++ l1 = l2; ++ ++ /* Extract the parameters from the S-expression and print them to stdout. */ ++ for (idx=0; "xy"[idx]; idx++) ++ { ++ l2 = gcry_sexp_find_token (l1, "xy"+idx, 1); ++ if (!l2) ++ die ("no %c parameter in returned public key\n", "xy"[idx]); ++ mpi = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); ++ if (!mpi) ++ die ("no value for %c parameter in returned private key\n","xy"[idx]); ++ gcry_sexp_release (l2); ++ if (standalone_mode) ++ printf ("%c = ", "XY"[idx]); ++ print_mpi_line (mpi, 1); ++ gcry_mpi_release (mpi); ++ } ++ ++ gcry_sexp_release (l1); ++} ++ ++ ++/* Generate DSA pq domain parameters for a modulus size of KEYSIZE. The + result is printed to stdout with one parameter per line in hex +- format and in this order: p, q, g, seed, counter, h. If SEED is ++ format and in this order: p, q, seed, counter. If SEED is + not NULL this seed value will be used for the generation. */ + static void +-run_dsa_pqg_gen (int keysize, const void *seed, size_t seedlen) ++run_dsa_pqg_gen (int keysize, int qsize, const void *seed, size_t seedlen) + { + gcry_sexp_t key; + + if (seed) +- key = dsa_gen_with_seed (keysize, seed, seedlen); ++ key = dsa_gen_with_seed (keysize, qsize, seed, seedlen); + else +- key = dsa_gen (keysize); +- print_dsa_domain_parameters (key); ++ key = dsa_gen (keysize, qsize); ++ print_dsa_domain_parameters (key, 1); ++ gcry_sexp_release (key); ++} ++ ++ ++/* Generate DSA domain parameters for a modulus size of KEYSIZE. The ++ result is printed to stdout with one parameter per line in hex ++ format and in this order: p, q, g, seed, counter, h. If SEED is ++ not NULL this seed value will be used for the generation. */ ++static void ++run_dsa_g_gen (int keysize, int qsize, const char *domain) ++{ ++ gcry_sexp_t key; ++ ++ key = dsa_gen_key (domain); ++ print_dsa_domain_parameters (key, 0); ++ gcry_sexp_release (key); ++} ++ ++/* Generate a DSA key with specified domain parameters ++ and print the XY values. */ ++static void ++run_dsa_gen_key (const char *domain) ++{ ++ gcry_sexp_t key; ++ ++ key = dsa_gen_key (domain); ++ print_dsa_xy (key); ++ + gcry_sexp_release (key); + } + + + /* Generate a DSA key of size of KEYSIZE and write the private key to + FILENAME. Also write the parameters to stdout in the same way as +- run_dsa_pqg_gen. */ ++ run_dsa_g_gen. */ + static void +-run_dsa_gen (int keysize, const char *filename) ++run_dsa_gen (int keysize, int qsize, const char *filename) + { + gcry_sexp_t key, private_key; + FILE *fp; + +- key = dsa_gen (keysize); ++ key = dsa_gen (keysize, qsize); + private_key = gcry_sexp_find_token (key, "private-key", 0); + if (!private_key) + die ("private key not found in genkey result\n"); +- print_dsa_domain_parameters (key); ++ print_dsa_domain_parameters (key, 1); + + fp = fopen (filename, "wb"); + if (!fp) +@@ -2020,6 +2126,53 @@ run_dsa_gen (int keysize, const char *fi + } + + ++static int ++dsa_hash_from_key(gcry_sexp_t s_key) ++{ ++ gcry_sexp_t l1, l2; ++ gcry_mpi_t q; ++ unsigned int qbits; ++ ++ l1 = gcry_sexp_find_token (s_key, "public-key", 0); ++ if (!l1) ++ { ++ l1 = gcry_sexp_find_token (s_key, "private-key", 0); ++ if (!l1) ++ die ("neither private nor public key found in the loaded key\n"); ++ } ++ ++ l2 = gcry_sexp_find_token (l1, "dsa", 0); ++ if (!l2) ++ die ("public key not formed as expected - no dsa\n"); ++ gcry_sexp_release (l1); ++ l1 = l2; ++ ++ l2 = gcry_sexp_find_token (l1, "q", 0); ++ if (!l2) ++ die ("public key not formed as expected - no q\n"); ++ gcry_sexp_release (l1); ++ l1 = l2; ++ ++ q = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); ++ if (!q) ++ die ("public key not formed as expected - no mpi in q\n"); ++ qbits = gcry_mpi_get_nbits(q); ++ gcry_sexp_release(l1); ++ gcry_mpi_release(q); ++ switch(qbits) ++ { ++ case 160: ++ return GCRY_MD_SHA1; ++ case 224: ++ return GCRY_MD_SHA224; ++ case 256: ++ return GCRY_MD_SHA256; ++ default: ++ die("bad number bits (%d) of q in key\n", qbits); ++ } ++ return GCRY_MD_NONE; ++} ++ + + /* Sign DATA of length DATALEN using the key taken from the S-expression + encoded KEYFILE. */ +@@ -2029,11 +2182,16 @@ run_dsa_sign (const void *data, size_t d + { + gpg_error_t err; + gcry_sexp_t s_data, s_key, s_sig, s_tmp, s_tmp2; +- char hash[20]; ++ char hash[128]; + gcry_mpi_t tmpmpi; ++ int algo; ++ ++ s_key = read_sexp_from_file (keyfile); ++ algo = dsa_hash_from_key(s_key); + +- gcry_md_hash_buffer (GCRY_MD_SHA1, hash, data, datalen); +- err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash, 20, NULL); ++ gcry_md_hash_buffer (algo, hash, data, datalen); ++ err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash, ++ gcry_md_get_algo_dlen(algo), NULL); + if (!err) + { + err = gcry_sexp_build (&s_data, NULL, +@@ -2044,8 +2202,6 @@ run_dsa_sign (const void *data, size_t d + die ("gcry_sexp_build failed for DSA data input: %s\n", + gpg_strerror (err)); + +- s_key = read_sexp_from_file (keyfile); +- + err = gcry_pk_sign (&s_sig, s_data, s_key); + if (err) + { +@@ -2121,13 +2277,18 @@ run_dsa_verify (const void *data, size_t + { + gpg_error_t err; + gcry_sexp_t s_data, s_key, s_sig; +- char hash[20]; ++ char hash[128]; + gcry_mpi_t tmpmpi; ++ int algo; + +- gcry_md_hash_buffer (GCRY_MD_SHA1, hash, data, datalen); ++ s_key = read_sexp_from_file (keyfile); ++ algo = dsa_hash_from_key(s_key); ++ ++ gcry_md_hash_buffer (algo, hash, data, datalen); + /* Note that we can't simply use %b with HASH to build the + S-expression, because that might yield a negative value. */ +- err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash, 20, NULL); ++ err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash, ++ gcry_md_get_algo_dlen(algo), NULL); + if (!err) + { + err = gcry_sexp_build (&s_data, NULL, +@@ -2138,7 +2299,6 @@ run_dsa_verify (const void *data, size_t + die ("gcry_sexp_build failed for DSA data input: %s\n", + gpg_strerror (err)); + +- s_key = read_sexp_from_file (keyfile); + s_sig = read_sexp_from_file (sigfile); + + err = gcry_pk_verify (s_sig, s_data, s_key); +@@ -2304,7 +2464,7 @@ usage (int show_help) + "MODE:\n" + " encrypt, decrypt, digest, random, hmac-sha,\n" + " rsa-{derive,gen,sign,verify},\n" +- " dsa-{pqg-gen,gen,sign,verify}, ecdsa-{gen-key,sign,verify}\n" ++ " dsa-{pq-gen,g-gen,gen,sign,verify}, ecdsa-{gen-key,sign,verify}\n" + "OPTIONS:\n" + " --verbose Print additional information\n" + " --binary Input and output is in binary form\n" +@@ -2315,6 +2475,7 @@ usage (int show_help) + " --algo NAME Use algorithm NAME\n" + " --curve NAME Select ECC curve spec NAME\n" + " --keysize N Use a keysize of N bits\n" ++ " --qize N Use a DSA q parameter size of N bits\n" + " --signature NAME Take signature from file NAME\n" + " --chunk N Read in chunks of N bytes (implies --binary)\n" + " --pkcs1 Use PKCS#1 encoding\n" +@@ -2344,6 +2505,7 @@ main (int argc, char **argv) + const char *dt_string = NULL; + const char *algo_string = NULL; + const char *keysize_string = NULL; ++ const char *qsize_string = NULL; + const char *signature_string = NULL; + FILE *input; + void *data; +@@ -2437,6 +2599,14 @@ main (int argc, char **argv) + keysize_string = *argv; + argc--; argv++; + } ++ else if (!strcmp (*argv, "--qsize")) ++ { ++ argc--; argv++; ++ if (!argc) ++ usage (0); ++ qsize_string = *argv; ++ argc--; argv++; ++ } + else if (!strcmp (*argv, "--signature")) + { + argc--; argv++; +@@ -2792,23 +2962,49 @@ main (int argc, char **argv) + } + else if (!strcmp (mode_string, "dsa-pqg-gen")) + { +- int keysize; ++ int keysize, qsize; ++ ++ keysize = keysize_string? atoi (keysize_string) : 0; ++ if (keysize < 1024 || keysize > 3072) ++ die ("invalid keysize specified; needs to be 1024 .. 3072\n"); ++ qsize = qsize_string? atoi (qsize_string) : 0; ++ if (qsize < 160 || qsize > 256) ++ die ("invalid qsize specified; needs to be 160 .. 256\n"); ++ run_dsa_pqg_gen (keysize, qsize, datalen? data:NULL, datalen); ++ } ++ else if (!strcmp (mode_string, "dsa-g-gen")) ++ { ++ int keysize, qsize; + + keysize = keysize_string? atoi (keysize_string) : 0; + if (keysize < 1024 || keysize > 3072) + die ("invalid keysize specified; needs to be 1024 .. 3072\n"); +- run_dsa_pqg_gen (keysize, datalen? data:NULL, datalen); ++ qsize = qsize_string? atoi (qsize_string) : 0; ++ if (qsize < 160 || qsize > 256) ++ die ("invalid qsize specified; needs to be 160 .. 256\n"); ++ if (!key_string) ++ die ("option --key containing pq domain parameters is required in this mode\n"); ++ run_dsa_g_gen (keysize, qsize, key_string); ++ } ++ else if (!strcmp (mode_string, "dsa-gen-key")) ++ { ++ if (!key_string) ++ die ("option --key containing pqg domain parameters is required in this mode\n"); ++ run_dsa_gen_key (key_string); + } + else if (!strcmp (mode_string, "dsa-gen")) + { +- int keysize; ++ int keysize, qsize; + + keysize = keysize_string? atoi (keysize_string) : 0; + if (keysize < 1024 || keysize > 3072) + die ("invalid keysize specified; needs to be 1024 .. 3072\n"); ++ qsize = qsize_string? atoi (qsize_string) : 0; ++ if (qsize < 160 || qsize > 256) ++ die ("invalid qsize specified; needs to be 160 .. 256\n"); + if (!key_string) + die ("option --key is required in this mode\n"); +- run_dsa_gen (keysize, key_string); ++ run_dsa_gen (keysize, qsize, key_string); + } + else if (!strcmp (mode_string, "dsa-sign")) + { diff --git a/libgcrypt-1.7.3-fips-reqs.patch b/libgcrypt-1.7.3-fips-reqs.patch new file mode 100644 index 0000000..ef7f765 --- /dev/null +++ b/libgcrypt-1.7.3-fips-reqs.patch @@ -0,0 +1,35 @@ +diff -up libgcrypt-1.7.3/src/visibility.c.fips-reqs libgcrypt-1.7.3/src/visibility.c +--- libgcrypt-1.7.3/src/visibility.c.fips-reqs 2016-03-23 12:59:34.000000000 +0100 ++++ libgcrypt-1.7.3/src/visibility.c 2016-11-22 16:29:36.992042480 +0100 +@@ -1288,6 +1288,8 @@ gcry_kdf_derive (const void *passphrase, + unsigned long iterations, + size_t keysize, void *keybuffer) + { ++ if (!fips_is_operational ()) ++ return gpg_error (fips_not_operational ()); + return gpg_error (_gcry_kdf_derive (passphrase, passphraselen, algo, hashalgo, + salt, saltlen, iterations, + keysize, keybuffer)); +@@ -1343,6 +1345,13 @@ void + gcry_mpi_randomize (gcry_mpi_t w, + unsigned int nbits, enum gcry_random_level level) + { ++ if (!fips_is_operational ()) ++ { ++ (void)fips_not_operational (); ++ fips_signal_fatal_error ("called in non-operational state"); ++ fips_noreturn (); ++ } ++ + _gcry_mpi_randomize (w, nbits, level); + } + +@@ -1368,6 +1377,8 @@ gcry_prime_generate (gcry_mpi_t *prime, + gcry_random_level_t random_level, + unsigned int flags) + { ++ if (!fips_is_operational ()) ++ return gpg_error (fips_not_operational ()); + return gpg_error (_gcry_prime_generate (prime, prime_bits, factor_bits, + factors, cb_func, cb_arg, + random_level, flags)); diff --git a/libgcrypt-1.8.3-cmac-selftest.patch b/libgcrypt-1.8.3-cmac-selftest.patch new file mode 100644 index 0000000..d480092 --- /dev/null +++ b/libgcrypt-1.8.3-cmac-selftest.patch @@ -0,0 +1,322 @@ +diff -up libgcrypt-1.8.3/cipher/cipher-cmac.c.cmac-selftest libgcrypt-1.8.3/cipher/cipher-cmac.c +--- libgcrypt-1.8.3/cipher/cipher-cmac.c.cmac-selftest 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.3/cipher/cipher-cmac.c 2019-05-31 17:33:35.594407152 +0200 +@@ -251,3 +251,246 @@ _gcry_cipher_cmac_set_subkeys (gcry_ciph + + return GPG_ERR_NO_ERROR; + } ++ ++/* CMAC selftests. ++ * Copyright (C) 2008 Free Software Foundation, Inc. ++ * Copyright (C) 2019 Red Hat, Inc. ++ */ ++ ++ ++ ++/* Check one MAC with MAC ALGO using the regular MAC ++ * API. (DATA,DATALEN) is the data to be MACed, (KEY,KEYLEN) the key ++ * and (EXPECT,EXPECTLEN) the expected result. If TRUNC is set, the ++ * EXPECTLEN may be less than the digest length. Returns NULL on ++ * success or a string describing the failure. */ ++static const char * ++check_one (int algo, ++ const void *data, size_t datalen, ++ const void *key, size_t keylen, ++ const void *expect, size_t expectlen) ++{ ++ gcry_mac_hd_t hd; ++ unsigned char mac[512]; /* hardcoded to avoid allocation */ ++ size_t macoutlen = expectlen; ++ ++/* printf ("MAC algo %d\n", algo); */ ++ if (_gcry_mac_get_algo_maclen (algo) != expectlen || ++ expectlen > sizeof (mac)) ++ return "invalid tests data"; ++ if (_gcry_mac_open (&hd, algo, 0, NULL)) ++ return "gcry_mac_open failed"; ++ if (_gcry_mac_setkey (hd, key, keylen)) ++ { ++ _gcry_mac_close (hd); ++ return "gcry_md_setkey failed"; ++ } ++ if (_gcry_mac_write (hd, data, datalen)) ++ { ++ _gcry_mac_close (hd); ++ return "gcry_mac_write failed"; ++ } ++ if (_gcry_mac_read (hd, mac, &macoutlen)) ++ { ++ _gcry_mac_close (hd); ++ return "gcry_mac_read failed"; ++ } ++ _gcry_mac_close (hd); ++ if (macoutlen != expectlen || memcmp (mac, expect, expectlen)) ++ { ++/* int i; */ ++ ++/* fputs (" {", stdout); */ ++/* for (i=0; i < expectlen-1; i++) */ ++/* { */ ++/* if (i && !(i % 8)) */ ++/* fputs ("\n ", stdout); */ ++/* printf (" 0x%02x,", mac[i]); */ ++/* } */ ++/* printf (" 0x%02x } },\n", mac[i]); */ ++ ++ return "does not match"; ++ } ++ return NULL; ++} ++ ++ ++static gpg_err_code_t ++selftests_cmac_tdes (int extended, selftest_report_func_t report) ++{ ++ const char *what; ++ const char *errtxt; ++ ++ what = "Basic TDES"; ++ errtxt = check_one (GCRY_MAC_CMAC_3DES, ++ "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" ++ "\xae\x2d\x8a\x57", 20, ++ "\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58" ++ "\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5", 24, ++ "\x74\x3d\xdb\xe0\xce\x2d\xc2\xed", 8); ++ if (errtxt) ++ goto failed; ++ ++ if (extended) ++ { ++ what = "Extended TDES #1"; ++ errtxt = check_one (GCRY_MAC_CMAC_3DES, ++ "", 0, ++ "\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58" ++ "\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5", 24, ++ "\xb7\xa6\x88\xe1\x22\xff\xaf\x95", 8); ++ if (errtxt) ++ goto failed; ++ ++ what = "Extended TDES #2"; ++ errtxt = check_one (GCRY_MAC_CMAC_3DES, ++ "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96", 8, ++ "\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58" ++ "\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5", 24, ++ "\x8e\x8f\x29\x31\x36\x28\x37\x97", 8); ++ if (errtxt) ++ goto failed; ++ ++ what = "Extended TDES #3"; ++ errtxt = check_one (GCRY_MAC_CMAC_3DES, ++ "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" ++ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51", 32, ++ "\x8a\xa8\x3b\xf8\xcb\xda\x10\x62\x0b\xc1\xbf\x19\xfb\xb6\xcd\x58" ++ "\xbc\x31\x3d\x4a\x37\x1c\xa8\xb5", 24, ++ "\x33\xe6\xb1\x09\x24\x00\xea\xe5", 8); ++ if (errtxt) ++ goto failed; ++ } ++ ++ return 0; /* Succeeded. */ ++ ++ failed: ++ if (report) ++ report ("cmac", GCRY_MAC_CMAC_3DES, what, errtxt); ++ return GPG_ERR_SELFTEST_FAILED; ++} ++ ++ ++ ++static gpg_err_code_t ++selftests_cmac_aes (int extended, selftest_report_func_t report) ++{ ++ const char *what; ++ const char *errtxt; ++ ++ what = "Basic AES128"; ++ errtxt = check_one (GCRY_MAC_CMAC_AES, ++ "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" ++ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" ++ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11", 40, ++ "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c", 16, ++ "\xdf\xa6\x67\x47\xde\x9a\xe6\x30\x30\xca\x32\x61\x14\x97\xc8\x27", 16); ++ if (errtxt) ++ goto failed; ++ ++ what = "Basic AES192"; ++ errtxt = check_one (GCRY_MAC_CMAC_AES, ++ "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" ++ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" ++ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11", 40, ++ "\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5" ++ "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b", 24, ++ "\x8a\x1d\xe5\xbe\x2e\xb3\x1a\xad\x08\x9a\x82\xe6\xee\x90\x8b\x0e", 16); ++ if (errtxt) ++ goto failed; ++ ++ what = "Basic AES256"; ++ errtxt = check_one (GCRY_MAC_CMAC_AES, ++ "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" ++ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" ++ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11", 40, ++ "\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81" ++ "\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4", 32, ++ "\xaa\xf3\xd8\xf1\xde\x56\x40\xc2\x32\xf5\xb1\x69\xb9\xc9\x11\xe6", 16); ++ if (errtxt) ++ goto failed; ++ if (extended) ++ { ++ what = "Extended AES #1"; ++ errtxt = check_one (GCRY_MAC_CMAC_AES, ++ "", 0, ++ "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c", 16, ++ "\xbb\x1d\x69\x29\xe9\x59\x37\x28\x7f\xa3\x7d\x12\x9b\x75\x67\x46", 16); ++ if (errtxt) ++ goto failed; ++ ++ what = "Extended AES #2"; ++ errtxt = check_one (GCRY_MAC_CMAC_AES, ++ "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a", 16, ++ "\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5" ++ "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b", 24, ++ "\x9e\x99\xa7\xbf\x31\xe7\x10\x90\x06\x62\xf6\x5e\x61\x7c\x51\x84", 16); ++ if (errtxt) ++ goto failed; ++ ++ what = "Extended AES #3"; ++ errtxt = check_one (GCRY_MAC_CMAC_AES, ++ "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" ++ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" ++ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" ++ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10", 64, ++ "\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81" ++ "\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4", 32, ++ "\xe1\x99\x21\x90\x54\x9f\x6e\xd5\x69\x6a\x2c\x05\x6c\x31\x54\x10", 16 ); ++ if (errtxt) ++ goto failed; ++ } ++ ++ return 0; /* Succeeded. */ ++ ++ failed: ++ if (report) ++ report ("cmac", GCRY_MAC_CMAC_AES, what, errtxt); ++ return GPG_ERR_SELFTEST_FAILED; ++} ++ ++ ++/* Run a full self-test for ALGO and return 0 on success. */ ++static gpg_err_code_t ++run_cmac_selftests (int algo, int extended, selftest_report_func_t report) ++{ ++ gpg_err_code_t ec; ++ ++ switch (algo) ++ { ++ case GCRY_MAC_CMAC_3DES: ++ ec = selftests_cmac_tdes (extended, report); ++ break; ++ case GCRY_MAC_CMAC_AES: ++ ec = selftests_cmac_aes (extended, report); ++ break; ++ ++ default: ++ ec = GPG_ERR_MAC_ALGO; ++ break; ++ } ++ return ec; ++} ++ ++ ++ ++ ++/* Run the selftests for CMAC with CMAC algorithm ALGO with optional ++ reporting function REPORT. */ ++gpg_error_t ++_gcry_cmac_selftest (int algo, int extended, selftest_report_func_t report) ++{ ++ gcry_err_code_t ec = 0; ++ ++ if (!_gcry_mac_algo_info( algo, GCRYCTL_TEST_ALGO, NULL, NULL )) ++ { ++ ec = run_cmac_selftests (algo, extended, report); ++ } ++ else ++ { ++ ec = GPG_ERR_MAC_ALGO; ++ if (report) ++ report ("mac", algo, "module", "algorithm not available"); ++ } ++ return gpg_error (ec); ++} +diff -up libgcrypt-1.8.3/src/cipher-proto.h.cmac-selftest libgcrypt-1.8.3/src/cipher-proto.h +--- libgcrypt-1.8.3/src/cipher-proto.h.cmac-selftest 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.3/src/cipher-proto.h 2019-05-31 17:29:34.574588234 +0200 +@@ -256,6 +256,8 @@ gcry_error_t _gcry_pk_selftest (int algo + selftest_report_func_t report); + gcry_error_t _gcry_hmac_selftest (int algo, int extended, + selftest_report_func_t report); ++gcry_error_t _gcry_cmac_selftest (int algo, int extended, ++ selftest_report_func_t report); + + gcry_error_t _gcry_random_selftest (selftest_report_func_t report); + +diff -up libgcrypt-1.8.3/src/fips.c.cmac-selftest libgcrypt-1.8.3/src/fips.c +--- libgcrypt-1.8.3/src/fips.c.cmac-selftest 2018-11-01 15:40:36.051865535 +0100 ++++ libgcrypt-1.8.3/src/fips.c 2019-05-31 17:31:20.157756640 +0200 +@@ -521,29 +521,32 @@ run_digest_selftests (int extended) + + /* Run self-tests for all HMAC algorithms. Return 0 on success. */ + static int +-run_hmac_selftests (int extended) ++run_mac_selftests (int extended) + { +- static int algos[] = ++ static int algos[][2] = + { +- GCRY_MD_SHA1, +- GCRY_MD_SHA224, +- GCRY_MD_SHA256, +- GCRY_MD_SHA384, +- GCRY_MD_SHA512, +- GCRY_MD_SHA3_224, +- GCRY_MD_SHA3_256, +- GCRY_MD_SHA3_384, +- GCRY_MD_SHA3_512, +- 0 ++ { GCRY_MD_SHA1, 0 }, ++ { GCRY_MD_SHA224, 0 }, ++ { GCRY_MD_SHA256, 0 }, ++ { GCRY_MD_SHA384, 0 }, ++ { GCRY_MD_SHA512, 0 }, ++ { GCRY_MD_SHA3_224, 0 }, ++ { GCRY_MD_SHA3_256, 0 }, ++ { GCRY_MD_SHA3_384, 0 }, ++ { GCRY_MD_SHA3_512, 0 }, ++ { GCRY_MAC_CMAC_3DES, 1 }, ++ { GCRY_MAC_CMAC_AES, 1 }, ++ { 0, 0 } + }; + int idx; + gpg_error_t err; + int anyerr = 0; + +- for (idx=0; algos[idx]; idx++) ++ for (idx=0; algos[idx][0]; idx++) + { +- err = _gcry_hmac_selftest (algos[idx], extended, reporter); +- reporter ("hmac", algos[idx], NULL, ++ err = algos[idx][1] ? _gcry_cmac_selftest (algos[idx][0], extended, reporter) : ++ _gcry_hmac_selftest (algos[idx][0], extended, reporter); ++ reporter (algos[idx][1] ? "cmac" : "hmac", algos[idx][0], NULL, + err? gpg_strerror (err):NULL); + if (err) + anyerr = 1; +@@ -747,7 +750,7 @@ _gcry_fips_run_selftests (int extended) + if (run_digest_selftests (extended)) + goto leave; + +- if (run_hmac_selftests (extended)) ++ if (run_mac_selftests (extended)) + goto leave; + + /* Run random tests before the pubkey tests because the latter diff --git a/libgcrypt-1.8.3-fips-ctor.patch b/libgcrypt-1.8.3-fips-ctor.patch new file mode 100644 index 0000000..66abd59 --- /dev/null +++ b/libgcrypt-1.8.3-fips-ctor.patch @@ -0,0 +1,60 @@ +diff -up libgcrypt-1.8.3/src/global.c.fips-ctor libgcrypt-1.8.3/src/global.c +--- libgcrypt-1.8.3/src/global.c.fips-ctor 2017-11-23 19:25:58.000000000 +0100 ++++ libgcrypt-1.8.3/src/global.c 2020-04-17 16:29:59.258218015 +0200 +@@ -141,6 +141,34 @@ global_init (void) + } + + ++#ifndef FIPS_MODULE_PATH ++#define FIPS_MODULE_PATH "/etc/system-fips" ++#endif ++ ++void __attribute__ ((constructor)) _gcry_global_constructor (void) ++{ ++ int rv; ++ ++ rv = access (FIPS_MODULE_PATH, F_OK); ++ if (rv < 0 && errno != ENOENT) ++ rv = 0; ++ ++ if (!rv) ++ { ++ int no_secmem_save; ++ ++ /* it should be always 0 at this point but let's keep on the safe side */ ++ no_secmem_save = no_secure_memory; ++ no_secure_memory = 1; ++ /* force selftests */ ++ global_init(); ++ _gcry_fips_run_selftests (0); ++ if (!fips_mode()) ++ _gcry_random_close_fds (); ++ no_secure_memory = no_secmem_save; ++ } ++} ++ + /* This function is called by the macro fips_is_operational and makes + sure that the minimal initialization has been done. This is far + from a perfect solution and hides problems with an improper +@@ -671,8 +699,7 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, + + case GCRYCTL_FIPS_MODE_P: + if (fips_mode () +- && !_gcry_is_fips_mode_inactive () +- && !no_secure_memory) ++ && !_gcry_is_fips_mode_inactive ()) + rc = GPG_ERR_GENERAL; /* Used as TRUE value */ + break; + +@@ -749,9 +776,9 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, + break; + + case GCRYCTL_SET_ENFORCED_FIPS_FLAG: +- if (!any_init_done) ++ if (fips_mode ()) + { +- /* Not yet initialized at all. Set the enforced fips mode flag */ ++ /* We are in FIPS mode, we can set the enforced fips mode flag. */ + _gcry_set_preferred_rng_type (0); + _gcry_set_enforced_fips_mode (); + } diff --git a/libgcrypt-1.8.3-fips-enttest.patch b/libgcrypt-1.8.3-fips-enttest.patch new file mode 100644 index 0000000..b6b09ba --- /dev/null +++ b/libgcrypt-1.8.3-fips-enttest.patch @@ -0,0 +1,113 @@ +diff -up libgcrypt-1.8.3/random/random-drbg.c.fips-enttest libgcrypt-1.8.3/random/random-drbg.c +--- libgcrypt-1.8.3/random/random-drbg.c.fips-enttest 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.3/random/random-drbg.c 2019-06-24 10:04:23.219547141 +0200 +@@ -317,6 +317,7 @@ struct drbg_state_s + unsigned char *ctr_null; /* CTR mode zero buffer */ + int seeded:1; /* DRBG fully seeded? */ + int pr:1; /* Prediction resistance enabled? */ ++ int ent_primed:1; /* Previous entropy data primed? */ + /* Taken from libgcrypt ANSI X9.31 DRNG: We need to keep track of the + * process which did the initialization so that we can detect a fork. + * The volatile modifier is required so that the compiler does not +@@ -324,6 +325,7 @@ struct drbg_state_s + pid_t seed_init_pid; + const struct drbg_state_ops_s *d_ops; + const struct drbg_core_s *core; ++ unsigned char ent_hash[64]; /* Hash of previous entropy data */ + struct drbg_test_data_s *test_data; + }; + +@@ -610,11 +612,13 @@ drbg_get_entropy (drbg_state_t drbg, uns + size_t len) + { + int rc = 0; ++ unsigned char newhash[64]; + + /* Perform testing as defined in 11.3.2 */ + if (drbg->test_data && drbg->test_data->fail_seed_source) + return -1; + ++redo: + read_cb_buffer = buffer; + read_cb_size = len; + read_cb_len = 0; +@@ -634,6 +638,27 @@ drbg_get_entropy (drbg_state_t drbg, uns + #else + rc = -1; + #endif ++ ++ /* to avoid storing the actual entropy obtained for indefinite ++ time, we just store the SHA-512 hash of the entropy gathered ++ */ ++ _gcry_md_hash_buffer (GCRY_MD_SHA512, newhash, buffer, len); ++ ++ if (!drbg->ent_primed) ++ { ++ memcpy (drbg->ent_hash, newhash, sizeof (drbg->ent_hash)); ++ drbg->ent_primed = 1; ++ goto redo; ++ } ++ ++ if (memcmp (newhash, drbg->ent_hash, sizeof (drbg->ent_hash)) == 0) ++ { ++ fips_signal_error ("Entropy source failed the continuous test"); ++ return -1; /* continuous entropy test failed */ ++ } ++ ++ memcpy (drbg->ent_hash, newhash, sizeof (drbg->ent_hash)); ++ + return rc; + } + +@@ -1341,26 +1366,38 @@ drbg_seed (drbg_state_t drbg, drbg_strin + } + else + { ++ int nonce = 0; + /* Gather entropy equal to the security strength of the DRBG. + * With a derivation function, a nonce is required in addition + * to the entropy. A nonce must be at least 1/2 of the security + * strength of the DRBG in size. Thus, entropy * nonce is 3/2 + * of the strength. The consideration of a nonce is only +- * applicable during initial seeding. */ ++ * applicable during initial seeding. ++ * To avoid pulling different length of data from entropy ++ * source, we use 2 * strength for initial seeding. */ + entropylen = drbg_sec_strength (drbg->core->flags); + if (!entropylen) + return GPG_ERR_GENERAL; + if (0 == reseed) +- /* make sure we round up strength/2 in +- * case it is not divisible by 2 */ +- entropylen = ((entropylen + 1) / 2) * 3; ++ { ++ nonce = 1; ++ } + dbg (("DRBG: (re)seeding with %lu bytes of entropy\n", entropylen)); +- entropy = xcalloc_secure (1, entropylen); ++ entropy = xcalloc_secure (nonce + 1, entropylen); + if (!entropy) + return GPG_ERR_ENOMEM; + ret = drbg_get_entropy (drbg, entropy, entropylen); + if (ret) + goto out; ++ if (nonce) ++ { ++ ret = drbg_get_entropy (drbg, entropy + entropylen, entropylen); ++ if (ret) ++ goto out; ++ /* make sure we round up strength/2 in ++ * case it is not divisible by 2 */ ++ entropylen = 2 * entropylen; ++ } + drbg_string_fill (&data1, entropy, entropylen); + } + +@@ -1597,6 +1634,7 @@ drbg_instantiate (drbg_state_t drbg, + drbg->core = &drbg_cores[coreref]; + drbg->pr = pr; + drbg->seeded = 0; ++ drbg->ent_primed = 0; + if (drbg->core->flags & DRBG_HMAC) + drbg->d_ops = &drbg_hmac_ops; + else if (drbg->core->flags & DRBG_HASH_MASK) diff --git a/libgcrypt-1.8.3-md-fips-enforce.patch b/libgcrypt-1.8.3-md-fips-enforce.patch new file mode 100644 index 0000000..eed7fa5 --- /dev/null +++ b/libgcrypt-1.8.3-md-fips-enforce.patch @@ -0,0 +1,18 @@ +diff -up libgcrypt-1.8.3/cipher/md.c.fips-enforce libgcrypt-1.8.3/cipher/md.c +--- libgcrypt-1.8.3/cipher/md.c.fips-enforce 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.3/cipher/md.c 2020-04-17 15:07:31.364945130 +0200 +@@ -409,13 +409,10 @@ md_enable (gcry_md_hd_t hd, int algorith + } + + +- if (!err && algorithm == GCRY_MD_MD5 && fips_mode ()) ++ if (!err && !spec->flags.fips && 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. But better throw an error. */ + err = GPG_ERR_DIGEST_ALGO; + } + } diff --git a/libgcrypt-1.8.4-fips-keygen.patch b/libgcrypt-1.8.4-fips-keygen.patch new file mode 100644 index 0000000..9d3a647 --- /dev/null +++ b/libgcrypt-1.8.4-fips-keygen.patch @@ -0,0 +1,65 @@ +diff -up libgcrypt-1.8.4/cipher/dsa.c.fips-keygen libgcrypt-1.8.4/cipher/dsa.c +--- libgcrypt-1.8.4/cipher/dsa.c.fips-keygen 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.4/cipher/dsa.c 2019-02-12 14:29:25.629513989 +0100 +@@ -457,11 +457,22 @@ generate_fips186 (DSA_secret_key *sk, un + &prime_q, &prime_p, + r_counter, + r_seed, r_seedlen); +- else +- ec = _gcry_generate_fips186_3_prime (nbits, qbits, NULL, 0, ++ else if (!domain->p || !domain->q) ++ ec = _gcry_generate_fips186_3_prime (nbits, qbits, ++ initial_seed.seed, ++ initial_seed.seedlen, + &prime_q, &prime_p, + r_counter, + r_seed, r_seedlen, NULL); ++ else ++ { ++ /* Domain parameters p and q are given; use them. */ ++ prime_p = mpi_copy (domain->p); ++ prime_q = mpi_copy (domain->q); ++ gcry_assert (mpi_get_nbits (prime_p) == nbits); ++ gcry_assert (mpi_get_nbits (prime_q) == qbits); ++ ec = 0; ++ } + sexp_release (initial_seed.sexp); + if (ec) + goto leave; +@@ -855,13 +866,12 @@ dsa_generate (const gcry_sexp_t genparms + sexp_release (l1); + sexp_release (domainsexp); + +- /* Check that all domain parameters are available. */ +- if (!domain.p || !domain.q || !domain.g) ++ /* Check that p and q domain parameters are available. */ ++ if (!domain.p || !domain.q || (!domain.g && !(flags & PUBKEY_FLAG_USE_FIPS186))) + { + _gcry_mpi_release (domain.p); + _gcry_mpi_release (domain.q); + _gcry_mpi_release (domain.g); +- sexp_release (deriveparms); + return GPG_ERR_MISSING_VALUE; + } + +diff -up libgcrypt-1.8.4/cipher/rsa.c.fips-keygen libgcrypt-1.8.4/cipher/rsa.c +--- libgcrypt-1.8.4/cipher/rsa.c.fips-keygen 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.4/cipher/rsa.c 2019-02-12 14:29:25.630513971 +0100 +@@ -389,7 +389,7 @@ generate_fips (RSA_secret_key *sk, unsig + + if (nbits < 1024 || (nbits & 0x1FF)) + return GPG_ERR_INV_VALUE; +- if (_gcry_enforced_fips_mode() && nbits != 2048 && nbits != 3072) ++ if (fips_mode() && nbits < 2048) + return GPG_ERR_INV_VALUE; + + /* The random quality depends on the transient_key flag. */ +@@ -696,7 +696,7 @@ generate_x931 (RSA_secret_key *sk, unsig + + *swapped = 0; + +- if (e_value == 1) /* Alias for a secure value. */ ++ if (e_value == 1 || e_value == 0) /* Alias for a secure value. */ + e_value = 65537; + + /* Point 1 of section 4.1: k = 1024 + 256s with S >= 0 */ diff --git a/libgcrypt-1.8.4-tests-fipsmode.patch b/libgcrypt-1.8.4-tests-fipsmode.patch new file mode 100644 index 0000000..1442a0b --- /dev/null +++ b/libgcrypt-1.8.4-tests-fipsmode.patch @@ -0,0 +1,184 @@ +diff -up libgcrypt-1.8.4/tests/basic.c.tests-fipsmode libgcrypt-1.8.4/tests/basic.c +--- libgcrypt-1.8.4/tests/basic.c.tests-fipsmode 2018-04-17 17:29:40.000000000 +0200 ++++ libgcrypt-1.8.4/tests/basic.c 2019-02-12 13:30:48.935791024 +0100 +@@ -6964,7 +6964,7 @@ check_ciphers (void) + check_one_cipher (algos[i], GCRY_CIPHER_MODE_CTR, 0); + if (gcry_cipher_get_algo_blklen (algos[i]) == GCRY_CCM_BLOCK_LEN) + check_one_cipher (algos[i], GCRY_CIPHER_MODE_CCM, 0); +- if (gcry_cipher_get_algo_blklen (algos[i]) == GCRY_GCM_BLOCK_LEN) ++ if (!in_fips_mode && gcry_cipher_get_algo_blklen (algos[i]) == GCRY_GCM_BLOCK_LEN) + check_one_cipher (algos[i], GCRY_CIPHER_MODE_GCM, 0); + if (gcry_cipher_get_algo_blklen (algos[i]) == GCRY_OCB_BLOCK_LEN) + check_one_cipher (algos[i], GCRY_CIPHER_MODE_OCB, 0); +@@ -7010,11 +7010,17 @@ check_cipher_modes(void) + check_cfb_cipher (); + check_ofb_cipher (); + check_ccm_cipher (); +- check_gcm_cipher (); +- check_poly1305_cipher (); +- check_ocb_cipher (); ++ if (!in_fips_mode) ++ { ++ check_gcm_cipher (); ++ check_poly1305_cipher (); ++ check_ocb_cipher (); ++ } + check_xts_cipher (); +- check_gost28147_cipher (); ++ if (!in_fips_mode) ++ { ++ check_gost28147_cipher (); ++ } + check_stream_cipher (); + check_stream_cipher_large_block (); + +@@ -10001,7 +10007,7 @@ check_mac (void) + show_mac_not_available (algos[i].algo); + continue; + } +- if (gcry_mac_test_algo (algos[i].algo) && in_fips_mode) ++ if ((algos[i].algo == GCRY_MAC_GMAC_AES || gcry_mac_test_algo (algos[i].algo)) && in_fips_mode) + { + if (verbose) + fprintf (stderr, " algorithm %d not available in fips mode\n", +@@ -11095,8 +11101,6 @@ main (int argc, char **argv) + /* If we are in fips mode do some more tests. */ + gcry_md_hd_t md; + +- /* First trigger a self-test. */ +- xgcry_control (GCRYCTL_FORCE_FIPS_MODE, 0); + if (!gcry_control (GCRYCTL_OPERATIONAL_P, 0)) + fail ("not in operational state after self-test\n"); + +@@ -11121,15 +11125,6 @@ main (int argc, char **argv) + gcry_md_close (md); + if (gcry_control (GCRYCTL_OPERATIONAL_P, 0)) + fail ("expected error state but still in operational state\n"); +- else +- { +- /* Now run a self-test and to get back into +- operational state. */ +- xgcry_control (GCRYCTL_FORCE_FIPS_MODE, 0); +- if (!gcry_control (GCRYCTL_OPERATIONAL_P, 0)) +- fail ("did not reach operational after error " +- "and self-test\n"); +- } + } + } + +diff -up libgcrypt-1.8.4/tests/benchmark.c.tests-fipsmode libgcrypt-1.8.4/tests/benchmark.c +--- libgcrypt-1.8.4/tests/benchmark.c.tests-fipsmode 2019-02-12 11:31:44.859603883 +0100 ++++ libgcrypt-1.8.4/tests/benchmark.c 2019-02-12 14:10:40.271999352 +0100 +@@ -872,8 +872,10 @@ cipher_bench ( const char *algoname ) + || (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM)) + continue; + +- if (modes[modeidx].req_blocksize > 0 +- && blklen != modes[modeidx].req_blocksize) ++ if ((modes[modeidx].req_blocksize > 0 ++ && blklen != modes[modeidx].req_blocksize) ++ || (in_fips_mode ++ && modes[modeidx].mode == GCRY_CIPHER_MODE_GCM)) + { + printf (" %7s %7s", "-", "-" ); + continue; +diff -up libgcrypt-1.8.4/tests/bench-slope.c.tests-fipsmode libgcrypt-1.8.4/tests/bench-slope.c +--- libgcrypt-1.8.4/tests/bench-slope.c.tests-fipsmode 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.4/tests/bench-slope.c 2019-02-12 14:14:33.618763325 +0100 +@@ -1338,7 +1338,7 @@ cipher_bench_one (int algo, struct bench + return; + + /* GCM has restrictions for block-size */ +- if (mode.mode == GCRY_CIPHER_MODE_GCM && blklen != GCRY_GCM_BLOCK_LEN) ++ if (mode.mode == GCRY_CIPHER_MODE_GCM && (gcry_fips_mode_active () || blklen != GCRY_GCM_BLOCK_LEN)) + return; + + /* XTS has restrictions for block-size */ +diff -up libgcrypt-1.8.4/tests/pubkey.c.tests-fipsmode libgcrypt-1.8.4/tests/pubkey.c +--- libgcrypt-1.8.4/tests/pubkey.c.tests-fipsmode 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.4/tests/pubkey.c 2019-02-12 13:52:25.658746415 +0100 +@@ -504,15 +504,30 @@ get_dsa_key_with_domain_new (gcry_sexp_t + rc = gcry_sexp_new + (&key_spec, + "(genkey (dsa (transient-key)(domain" +- "(p #d3aed1876054db831d0c1348fbb1ada72507e5fbf9a62cbd47a63aeb7859d6921" +- "4adeb9146a6ec3f43520f0fd8e3125dd8bbc5d87405d1ac5f82073cd762a3f8d7" +- "74322657c9da88a7d2f0e1a9ceb84a39cb40876179e6a76e400498de4bb9379b0" +- "5f5feb7b91eb8fea97ee17a955a0a8a37587a272c4719d6feb6b54ba4ab69#)" +- "(q #9c916d121de9a03f71fb21bc2e1c0d116f065a4f#)" +- "(g #8157c5f68ca40b3ded11c353327ab9b8af3e186dd2e8dade98761a0996dda99ab" +- "0250d3409063ad99efae48b10c6ab2bba3ea9a67b12b911a372a2bba260176fad" +- "b4b93247d9712aad13aa70216c55da9858f7a298deb670a403eb1e7c91b847f1e" +- "ccfbd14bd806fd42cf45dbb69cd6d6b43add2a78f7d16928eaa04458dea44#)" ++ " (p #a85378d8fd3f8d72ec7418080da21317e43ec4b62ba8c862" ++ " 3b7e4d04441dd1a0658662596493ca8e9e8fbb7e34aaddb6" ++ " 2e5d67b6d09a6e61b769e7c352aa2b10e20ca0636963b552" ++ " 3e86470decbbeda027e797e7b67635d4d49c30700e74af8a" ++ " 0ff156a801af57a26e7078f1d82f74908ecb6d07e70b3503" ++ " eed94fa32cf17a7fc3d6cf40dc7b00830e6a2566dc073e34" ++ " 3312517c6aa5152b4bfecd2e551fee346318a153423c996b" ++ " 0d5dcb9102aedd38798616f1f1e0d6c403525b1f9b3d4dc7" ++ " 66de2dfc4a56d7b8ba5963d60f3e16318870ad436952e557" ++ " 65374eab85e8ec17d6b9a4547b9b5f2752f3105be809b23a" ++ " 2c8d7469db02e24d592394a7dba069e9#)" ++ " (q #d277044e50f5a4e3f510a50a0b84fdffbca047ed27602056" ++ " 7441a0a5#)" ++ " (g #13d754e21fd241655da891c522a65a72a89bdc64ec9b54a8" ++ " 21ed4a898b490e0c4fcb72192a4a20f541f3f2925399f0ba" ++ " ecf929aafbf79dfe4332393b32cd2e2fcf272f32a627434a" ++ " 0df242b75b414df372121e53a553f222f836b000f016485b" ++ " 6bd0898451801dcd8de64cd5365696ffc532d528c506620a" ++ " 942a0305046d8f1876341f1e570bc3974ba6b9a438e97023" ++ " 02a2e6e67bfd06d32bc679962271d7b40cd72f386e64e0d7" ++ " ef86ca8ca5d14228dc2a4f16e3189886b5990674f4200f3a" ++ " 4cf65a3f0ddba1fa672dff2f5e143d10e4e97ae84f6da095" ++ " 35d5b9df259181a79b63b069e949972b02ba36b3586aab7e" ++ " 45f322f82e4e85ca3ab85591b3c2a966#)" + ")))", 0, 1); + if (rc) + die ("error creating S-expression: %s\n", gcry_strerror (rc)); +@@ -595,7 +610,7 @@ get_dsa_key_fips186_with_seed_new (gcry_ + " (use-fips186)" + " (transient-key)" + " (derive-parms" +- " (seed #0cb1990c1fd3626055d7a0096f8fa99807399871#))))", ++ " (seed #8b4c4d671fff82e8ed932260206d0571e3a1c2cee8cd94cb73fe58f9b67488fa#))))", + 0, 1); + if (rc) + die ("error creating S-expression: %s\n", gcry_strerror (rc)); +diff -up libgcrypt-1.8.4/tests/t-cv25519.c.tests-fipsmode libgcrypt-1.8.4/tests/t-cv25519.c +--- libgcrypt-1.8.4/tests/t-cv25519.c.tests-fipsmode 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.4/tests/t-cv25519.c 2019-02-12 14:02:35.935705390 +0100 +@@ -560,6 +560,9 @@ main (int argc, char **argv) + xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0); + xgcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); + xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); ++ /* Curve25519 isn't supported in fips mode */ ++ if (gcry_fips_mode_active()) ++ return 77; + + start_timer (); + check_cv25519 (); +diff -up libgcrypt-1.8.4/tests/t-secmem.c.tests-fipsmode libgcrypt-1.8.4/tests/t-secmem.c +--- libgcrypt-1.8.4/tests/t-secmem.c.tests-fipsmode 2017-11-23 19:19:54.000000000 +0100 ++++ libgcrypt-1.8.4/tests/t-secmem.c 2019-02-12 11:51:02.462190538 +0100 +@@ -174,7 +174,8 @@ main (int argc, char **argv) + xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0); + xgcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); + xgcry_control (GCRYCTL_INIT_SECMEM, pool_size, 0); +- gcry_set_outofcore_handler (outofcore_handler, NULL); ++ if (!gcry_fips_mode_active ()) ++ gcry_set_outofcore_handler (outofcore_handler, NULL); + xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); + + /* Libgcrypt prints a warning when the first overflow is allocated; +@@ -184,7 +185,8 @@ main (int argc, char **argv) + + + test_secmem (); +- test_secmem_overflow (); ++ if (!gcry_fips_mode_active ()) ++ test_secmem_overflow (); + /* FIXME: We need to improve the tests, for example by registering + * our own log handler and comparing the output of + * PRIV_CTL_DUMP_SECMEM_STATS to expected pattern. */ diff --git a/libgcrypt-1.8.4-use-poll.patch b/libgcrypt-1.8.4-use-poll.patch new file mode 100644 index 0000000..b96c6ce --- /dev/null +++ b/libgcrypt-1.8.4-use-poll.patch @@ -0,0 +1,77 @@ +diff -up libgcrypt-1.8.4/random/rndlinux.c.use-poll libgcrypt-1.8.4/random/rndlinux.c +--- libgcrypt-1.8.4/random/rndlinux.c.use-poll 2018-10-26 13:50:20.000000000 +0200 ++++ libgcrypt-1.8.4/random/rndlinux.c 2018-11-20 15:51:56.760669058 +0100 +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + #if defined(__linux__) && defined(HAVE_SYSCALL) + # include + #endif +@@ -241,9 +242,8 @@ _gcry_rndlinux_gather_random (void (*add + return with something we will actually use 100ms. */ + while (length) + { +- fd_set rfds; +- struct timeval tv; + int rc; ++ struct pollfd pfd; + + /* If we have a modern Linux kernel, we first try to use the new + * getrandom syscall. That call guarantees that the kernel's +@@ -300,36 +300,25 @@ _gcry_rndlinux_gather_random (void (*add + any_need_entropy = 1; + } + +- /* If the system has no limit on the number of file descriptors +- and we encounter an fd which is larger than the fd_set size, +- we don't use the select at all. The select code is only used +- to emit progress messages. A better solution would be to +- fall back to poll() if available. */ +-#ifdef FD_SETSIZE +- if (fd < FD_SETSIZE) +-#endif ++ pfd.fd = fd; ++ pfd.events = POLLIN; ++ ++ _gcry_pre_syscall (); ++ rc = poll(&pfd, 1, delay); ++ _gcry_post_syscall (); ++ if (!rc) + { +- FD_ZERO(&rfds); +- FD_SET(fd, &rfds); +- tv.tv_sec = delay; +- tv.tv_usec = delay? 0 : 100000; +- _gcry_pre_syscall (); +- rc = select (fd+1, &rfds, NULL, NULL, &tv); +- _gcry_post_syscall (); +- if (!rc) +- { +- any_need_entropy = 1; +- delay = 3; /* Use 3 seconds henceforth. */ +- continue; +- } +- else if( rc == -1 ) +- { +- log_error ("select() error: %s\n", strerror(errno)); +- if (!delay) +- delay = 1; /* Use 1 second if we encounter an error before +- we have ever blocked. */ +- continue; +- } ++ any_need_entropy = 1; ++ delay = 3000; /* Use 3 seconds henceforth. */ ++ continue; ++ } ++ else if( rc == -1 ) ++ { ++ log_error ("poll() error: %s\n", strerror(errno)); ++ if (!delay) ++ delay = 1000; /* Use 1 second if we encounter an error before ++ we have ever blocked. */ ++ continue; + } + + do diff --git a/libgcrypt-1.8.5-aes-perf.patch b/libgcrypt-1.8.5-aes-perf.patch new file mode 100644 index 0000000..268ce70 --- /dev/null +++ b/libgcrypt-1.8.5-aes-perf.patch @@ -0,0 +1,8156 @@ +diff -up libgcrypt-1.8.5/cipher/arcfour.c.aes-perf libgcrypt-1.8.5/cipher/arcfour.c +--- libgcrypt-1.8.5/cipher/arcfour.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/arcfour.c 2020-04-22 18:29:41.662862382 +0200 +@@ -184,10 +184,12 @@ do_arcfour_setkey (void *context, const + } + + static gcry_err_code_t +-arcfour_setkey ( void *context, const byte *key, unsigned int keylen ) ++arcfour_setkey ( void *context, const byte *key, unsigned int keylen, ++ gcry_cipher_hd_t hd ) + { + ARCFOUR_context *ctx = (ARCFOUR_context *) context; + gcry_err_code_t rc = do_arcfour_setkey (ctx, key, keylen ); ++ (void)hd; + return rc; + } + +@@ -207,11 +209,11 @@ selftest(void) + static const byte ciphertext_1[] = + { 0xF1, 0x38, 0x29, 0xC9, 0xDE }; + +- arcfour_setkey( &ctx, key_1, sizeof(key_1)); ++ arcfour_setkey( &ctx, key_1, sizeof(key_1), NULL); + encrypt_stream( &ctx, scratch, plaintext_1, sizeof(plaintext_1)); + if ( memcmp (scratch, ciphertext_1, sizeof (ciphertext_1))) + return "Arcfour encryption test 1 failed."; +- arcfour_setkey( &ctx, key_1, sizeof(key_1)); ++ arcfour_setkey( &ctx, key_1, sizeof(key_1), NULL); + encrypt_stream(&ctx, scratch, scratch, sizeof(plaintext_1)); /* decrypt */ + if ( memcmp (scratch, plaintext_1, sizeof (plaintext_1))) + return "Arcfour decryption test 1 failed."; +diff -up libgcrypt-1.8.5/cipher/blowfish.c.aes-perf libgcrypt-1.8.5/cipher/blowfish.c +--- libgcrypt-1.8.5/cipher/blowfish.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/blowfish.c 2020-04-22 18:29:41.663862363 +0200 +@@ -37,6 +37,7 @@ + #include "g10lib.h" + #include "cipher.h" + #include "bufhelp.h" ++#include "cipher-internal.h" + #include "cipher-selftest.h" + + #define BLOWFISH_BLOCKSIZE 8 +@@ -67,7 +68,8 @@ typedef struct { + u32 p[BLOWFISH_ROUNDS+2]; + } BLOWFISH_context; + +-static gcry_err_code_t bf_setkey (void *c, const byte *key, unsigned keylen); ++static gcry_err_code_t bf_setkey (void *c, const byte *key, unsigned keylen, ++ gcry_cipher_hd_t hd); + static unsigned int encrypt_block (void *bc, byte *outbuf, const byte *inbuf); + static unsigned int decrypt_block (void *bc, byte *outbuf, const byte *inbuf); + +@@ -703,7 +705,7 @@ _gcry_blowfish_ctr_enc(void *context, un + /* 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); ++ cipher_block_xor(outbuf, tmpbuf, inbuf, BLOWFISH_BLOCKSIZE); + outbuf += BLOWFISH_BLOCKSIZE; + inbuf += BLOWFISH_BLOCKSIZE; + /* Increment the counter. */ +@@ -771,7 +773,7 @@ _gcry_blowfish_cbc_dec(void *context, un + the intermediate result to SAVEBUF. */ + do_decrypt_block (ctx, savebuf, inbuf); + +- buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, BLOWFISH_BLOCKSIZE); ++ cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, BLOWFISH_BLOCKSIZE); + inbuf += BLOWFISH_BLOCKSIZE; + outbuf += BLOWFISH_BLOCKSIZE; + } +@@ -828,7 +830,7 @@ _gcry_blowfish_cfb_dec(void *context, un + for ( ;nblocks; nblocks-- ) + { + do_encrypt_block(ctx, iv, iv); +- buf_xor_n_copy(outbuf, iv, inbuf, BLOWFISH_BLOCKSIZE); ++ cipher_block_xor_n_copy(outbuf, iv, inbuf, BLOWFISH_BLOCKSIZE); + outbuf += BLOWFISH_BLOCKSIZE; + inbuf += BLOWFISH_BLOCKSIZE; + } +@@ -897,7 +899,7 @@ selftest(void) + const char *r; + + bf_setkey( (void *) &c, +- (const unsigned char*)"abcdefghijklmnopqrstuvwxyz", 26 ); ++ (const unsigned char*)"abcdefghijklmnopqrstuvwxyz", 26, NULL ); + encrypt_block( (void *) &c, buffer, plain ); + if( memcmp( buffer, "\x32\x4E\xD0\xFE\xF4\x13\xA2\x03", 8 ) ) + return "Blowfish selftest failed (1)."; +@@ -905,7 +907,7 @@ selftest(void) + if( memcmp( buffer, plain, 8 ) ) + return "Blowfish selftest failed (2)."; + +- bf_setkey( (void *) &c, key3, 8 ); ++ bf_setkey( (void *) &c, key3, 8, NULL ); + encrypt_block( (void *) &c, buffer, plain3 ); + if( memcmp( buffer, cipher3, 8 ) ) + return "Blowfish selftest failed (3)."; +@@ -1095,10 +1097,12 @@ do_bf_setkey (BLOWFISH_context *c, const + + + static gcry_err_code_t +-bf_setkey (void *context, const byte *key, unsigned keylen) ++bf_setkey (void *context, const byte *key, unsigned keylen, ++ gcry_cipher_hd_t hd) + { + BLOWFISH_context *c = (BLOWFISH_context *) context; + gcry_err_code_t rc = do_bf_setkey (c, key, keylen); ++ (void)hd; + return rc; + } + +diff -up libgcrypt-1.8.5/cipher/bufhelp.h.aes-perf libgcrypt-1.8.5/cipher/bufhelp.h +--- libgcrypt-1.8.5/cipher/bufhelp.h.aes-perf 2018-04-17 17:35:28.000000000 +0200 ++++ libgcrypt-1.8.5/cipher/bufhelp.h 2020-04-22 18:29:41.663862363 +0200 +@@ -450,7 +450,21 @@ static inline void buf_put_le64(void *_b + out->a = le_bswap64(val); + } + +- + #endif /*BUFHELP_UNALIGNED_ACCESS*/ + ++ ++/* Host-endian get/put macros */ ++#ifdef WORDS_BIGENDIAN ++# define buf_get_he32 buf_get_be32 ++# define buf_put_he32 buf_put_be32 ++# define buf_get_he64 buf_get_be64 ++# define buf_put_he64 buf_put_be64 ++#else ++# define buf_get_he32 buf_get_le32 ++# define buf_put_he32 buf_put_le32 ++# define buf_get_he64 buf_get_le64 ++# define buf_put_he64 buf_put_le64 ++#endif ++ ++ + #endif /*GCRYPT_BUFHELP_H*/ +diff -up libgcrypt-1.8.5/cipher/camellia-glue.c.aes-perf libgcrypt-1.8.5/cipher/camellia-glue.c +--- libgcrypt-1.8.5/cipher/camellia-glue.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/camellia-glue.c 2020-04-22 18:29:41.664862344 +0200 +@@ -204,7 +204,8 @@ extern void _gcry_camellia_aesni_avx2_oc + static const char *selftest(void); + + static gcry_err_code_t +-camellia_setkey(void *c, const byte *key, unsigned keylen) ++camellia_setkey(void *c, const byte *key, unsigned keylen, ++ gcry_cipher_hd_t hd) + { + CAMELLIA_context *ctx=c; + static int initialized=0; +@@ -213,6 +214,8 @@ camellia_setkey(void *c, const byte *key + unsigned int hwf = _gcry_get_hw_features (); + #endif + ++ (void)hd; ++ + if(keylen!=16 && keylen!=24 && keylen!=32) + return GPG_ERR_INV_KEYLEN; + +@@ -427,7 +430,7 @@ _gcry_camellia_ctr_enc(void *context, un + /* 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); ++ cipher_block_xor(outbuf, tmpbuf, inbuf, CAMELLIA_BLOCK_SIZE); + outbuf += CAMELLIA_BLOCK_SIZE; + inbuf += CAMELLIA_BLOCK_SIZE; + /* Increment the counter. */ +@@ -520,7 +523,8 @@ _gcry_camellia_cbc_dec(void *context, un + 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); ++ cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, ++ CAMELLIA_BLOCK_SIZE); + inbuf += CAMELLIA_BLOCK_SIZE; + outbuf += CAMELLIA_BLOCK_SIZE; + } +@@ -602,7 +606,7 @@ _gcry_camellia_cfb_dec(void *context, un + for ( ;nblocks; nblocks-- ) + { + Camellia_EncryptBlock(ctx->keybitlength, iv, ctx->keytable, iv); +- buf_xor_n_copy(outbuf, iv, inbuf, CAMELLIA_BLOCK_SIZE); ++ cipher_block_xor_n_copy(outbuf, iv, inbuf, CAMELLIA_BLOCK_SIZE); + outbuf += CAMELLIA_BLOCK_SIZE; + inbuf += CAMELLIA_BLOCK_SIZE; + } +@@ -991,7 +995,7 @@ selftest(void) + 0x20,0xef,0x7c,0x91,0x9e,0x3a,0x75,0x09 + }; + +- camellia_setkey(&ctx,key_128,sizeof(key_128)); ++ camellia_setkey(&ctx,key_128,sizeof(key_128),NULL); + camellia_encrypt(&ctx,scratch,plaintext); + if(memcmp(scratch,ciphertext_128,sizeof(ciphertext_128))!=0) + return "CAMELLIA-128 test encryption failed."; +@@ -999,7 +1003,7 @@ selftest(void) + if(memcmp(scratch,plaintext,sizeof(plaintext))!=0) + return "CAMELLIA-128 test decryption failed."; + +- camellia_setkey(&ctx,key_192,sizeof(key_192)); ++ camellia_setkey(&ctx,key_192,sizeof(key_192),NULL); + camellia_encrypt(&ctx,scratch,plaintext); + if(memcmp(scratch,ciphertext_192,sizeof(ciphertext_192))!=0) + return "CAMELLIA-192 test encryption failed."; +@@ -1007,7 +1011,7 @@ selftest(void) + if(memcmp(scratch,plaintext,sizeof(plaintext))!=0) + return "CAMELLIA-192 test decryption failed."; + +- camellia_setkey(&ctx,key_256,sizeof(key_256)); ++ camellia_setkey(&ctx,key_256,sizeof(key_256),NULL); + camellia_encrypt(&ctx,scratch,plaintext); + if(memcmp(scratch,ciphertext_256,sizeof(ciphertext_256))!=0) + return "CAMELLIA-256 test encryption failed."; +diff -up libgcrypt-1.8.5/cipher/cast5.c.aes-perf libgcrypt-1.8.5/cipher/cast5.c +--- libgcrypt-1.8.5/cipher/cast5.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/cast5.c 2020-04-22 18:29:41.665862325 +0200 +@@ -44,6 +44,7 @@ + #include "cipher.h" + #include "bithelp.h" + #include "bufhelp.h" ++#include "cipher-internal.h" + #include "cipher-selftest.h" + + /* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */ +@@ -72,7 +73,8 @@ typedef struct { + #endif + } CAST5_context; + +-static gcry_err_code_t cast_setkey (void *c, const byte *key, unsigned keylen); ++static gcry_err_code_t cast_setkey (void *c, const byte *key, unsigned keylen, ++ gcry_cipher_hd_t hd); + static unsigned int encrypt_block (void *c, byte *outbuf, const byte *inbuf); + static unsigned int decrypt_block (void *c, byte *outbuf, const byte *inbuf); + +@@ -671,7 +673,7 @@ _gcry_cast5_ctr_enc(void *context, unsig + /* 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); ++ cipher_block_xor(outbuf, tmpbuf, inbuf, CAST5_BLOCKSIZE); + outbuf += CAST5_BLOCKSIZE; + inbuf += CAST5_BLOCKSIZE; + /* Increment the counter. */ +@@ -739,7 +741,7 @@ _gcry_cast5_cbc_dec(void *context, unsig + the intermediate result to SAVEBUF. */ + do_decrypt_block (ctx, savebuf, inbuf); + +- buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, CAST5_BLOCKSIZE); ++ cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, CAST5_BLOCKSIZE); + inbuf += CAST5_BLOCKSIZE; + outbuf += CAST5_BLOCKSIZE; + } +@@ -795,7 +797,7 @@ _gcry_cast5_cfb_dec(void *context, unsig + for ( ;nblocks; nblocks-- ) + { + do_encrypt_block(ctx, iv, iv); +- buf_xor_n_copy(outbuf, iv, inbuf, CAST5_BLOCKSIZE); ++ cipher_block_xor_n_copy(outbuf, iv, inbuf, CAST5_BLOCKSIZE); + outbuf += CAST5_BLOCKSIZE; + inbuf += CAST5_BLOCKSIZE; + } +@@ -863,7 +865,7 @@ selftest(void) + byte buffer[8]; + const char *r; + +- cast_setkey( &c, key, 16 ); ++ cast_setkey( &c, key, 16, NULL ); + encrypt_block( &c, buffer, plain ); + if( memcmp( buffer, cipher, 8 ) ) + return "1"; +@@ -884,10 +886,10 @@ selftest(void) + 0x80,0xAC,0x05,0xB8,0xE8,0x3D,0x69,0x6E }; + + for(i=0; i < 1000000; i++ ) { +- cast_setkey( &c, b0, 16 ); ++ cast_setkey( &c, b0, 16, NULL ); + encrypt_block( &c, a0, a0 ); + encrypt_block( &c, a0+8, a0+8 ); +- cast_setkey( &c, a0, 16 ); ++ cast_setkey( &c, a0, 16, NULL ); + encrypt_block( &c, b0, b0 ); + encrypt_block( &c, b0+8, b0+8 ); + } +@@ -1029,10 +1031,12 @@ do_cast_setkey( CAST5_context *c, const + } + + static gcry_err_code_t +-cast_setkey (void *context, const byte *key, unsigned keylen ) ++cast_setkey (void *context, const byte *key, unsigned keylen, ++ gcry_cipher_hd_t hd ) + { + CAST5_context *c = (CAST5_context *) context; + gcry_err_code_t rc = do_cast_setkey (c, key, keylen); ++ (void)hd; + return rc; + } + +diff -up libgcrypt-1.8.5/cipher/chacha20.c.aes-perf libgcrypt-1.8.5/cipher/chacha20.c +--- libgcrypt-1.8.5/cipher/chacha20.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/chacha20.c 2020-04-22 18:29:41.665862325 +0200 +@@ -419,10 +419,12 @@ chacha20_do_setkey (CHACHA20_context_t * + + + static gcry_err_code_t +-chacha20_setkey (void *context, const byte * key, unsigned int keylen) ++chacha20_setkey (void *context, const byte *key, unsigned int keylen, ++ gcry_cipher_hd_t hd) + { + CHACHA20_context_t *ctx = (CHACHA20_context_t *) context; + gcry_err_code_t rc = chacha20_do_setkey (ctx, key, keylen); ++ (void)hd; + _gcry_burn_stack (4 + sizeof (void *) + 4 * sizeof (void *)); + return rc; + } +@@ -569,7 +571,7 @@ selftest (void) + /* 16-byte alignment required for amd64 implementation. */ + ctx = (CHACHA20_context_t *)((uintptr_t)(ctxbuf + 15) & ~(uintptr_t)15); + +- chacha20_setkey (ctx, key_1, sizeof key_1); ++ chacha20_setkey (ctx, key_1, sizeof key_1, NULL); + chacha20_setiv (ctx, nonce_1, sizeof nonce_1); + scratch[sizeof (scratch) - 1] = 0; + chacha20_encrypt_stream (ctx, scratch, plaintext_1, sizeof plaintext_1); +@@ -577,7 +579,7 @@ selftest (void) + return "ChaCha20 encryption test 1 failed."; + if (scratch[sizeof (scratch) - 1]) + return "ChaCha20 wrote too much."; +- chacha20_setkey (ctx, key_1, sizeof (key_1)); ++ chacha20_setkey (ctx, key_1, sizeof (key_1), NULL); + chacha20_setiv (ctx, nonce_1, sizeof nonce_1); + chacha20_encrypt_stream (ctx, scratch, scratch, sizeof plaintext_1); + if (memcmp (scratch, plaintext_1, sizeof plaintext_1)) +@@ -585,12 +587,12 @@ selftest (void) + + for (i = 0; i < sizeof buf; i++) + buf[i] = i; +- chacha20_setkey (ctx, key_1, sizeof key_1); ++ chacha20_setkey (ctx, key_1, sizeof key_1, NULL); + chacha20_setiv (ctx, nonce_1, sizeof nonce_1); + /*encrypt */ + chacha20_encrypt_stream (ctx, buf, buf, sizeof buf); + /*decrypt */ +- chacha20_setkey (ctx, key_1, sizeof key_1); ++ chacha20_setkey (ctx, key_1, sizeof key_1, NULL); + chacha20_setiv (ctx, nonce_1, sizeof nonce_1); + chacha20_encrypt_stream (ctx, buf, buf, 1); + chacha20_encrypt_stream (ctx, buf + 1, buf + 1, (sizeof buf) - 1 - 1); +@@ -600,13 +602,13 @@ selftest (void) + if (buf[i] != (byte) i) + return "ChaCha20 encryption test 2 failed."; + +- chacha20_setkey (ctx, key_1, sizeof key_1); ++ chacha20_setkey (ctx, key_1, sizeof key_1, NULL); + chacha20_setiv (ctx, nonce_1, sizeof nonce_1); + /* encrypt */ + for (i = 0; i < sizeof buf; i++) + chacha20_encrypt_stream (ctx, &buf[i], &buf[i], 1); + /* decrypt */ +- chacha20_setkey (ctx, key_1, sizeof key_1); ++ chacha20_setkey (ctx, key_1, sizeof key_1, NULL); + chacha20_setiv (ctx, nonce_1, sizeof nonce_1); + chacha20_encrypt_stream (ctx, buf, buf, sizeof buf); + for (i = 0; i < sizeof buf; i++) +diff -up libgcrypt-1.8.5/cipher/cipher-aeswrap.c.aes-perf libgcrypt-1.8.5/cipher/cipher-aeswrap.c +--- libgcrypt-1.8.5/cipher/cipher-aeswrap.c.aes-perf 2018-04-17 17:49:00.000000000 +0200 ++++ libgcrypt-1.8.5/cipher/cipher-aeswrap.c 2020-04-22 18:29:41.665862325 +0200 +@@ -99,7 +99,7 @@ _gcry_cipher_aeswrap_encrypt (gcry_ciphe + break; + } + /* A := MSB_64(B) ^ t */ +- buf_xor(a, b, t, 8); ++ cipher_block_xor(a, b, t, 8); + /* R[i] := LSB_64(B) */ + memcpy (r+i*8, b+8, 8); + } +@@ -170,7 +170,7 @@ _gcry_cipher_aeswrap_decrypt (gcry_ciphe + for (i = n; i >= 1; i--) + { + /* B := AES_k^1( (A ^ t)| R[i] ) */ +- buf_xor(b, a, t, 8); ++ cipher_block_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; +diff -up libgcrypt-1.8.5/cipher/cipher.c.aes-perf libgcrypt-1.8.5/cipher/cipher.c +--- libgcrypt-1.8.5/cipher/cipher.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/cipher.c 2020-04-22 18:29:41.666862306 +0200 +@@ -92,6 +92,8 @@ static gcry_cipher_spec_t *cipher_list[] + + + ++static void _gcry_cipher_setup_mode_ops(gcry_cipher_hd_t c, int mode); ++ + + static int + map_algo (int algo) +@@ -532,6 +534,7 @@ _gcry_cipher_open_internal (gcry_cipher_ + h->bulk.ctr_enc = _gcry_aes_ctr_enc; + h->bulk.ocb_crypt = _gcry_aes_ocb_crypt; + h->bulk.ocb_auth = _gcry_aes_ocb_auth; ++ h->bulk.xts_crypt = _gcry_aes_xts_crypt; + break; + #endif /*USE_AES*/ + #ifdef USE_BLOWFISH +@@ -592,6 +595,9 @@ _gcry_cipher_open_internal (gcry_cipher_ + break; + } + ++ /* Setup mode routines. */ ++ _gcry_cipher_setup_mode_ops(h, mode); ++ + /* Setup defaults depending on the mode. */ + switch (mode) + { +@@ -609,8 +615,7 @@ _gcry_cipher_open_internal (gcry_cipher_ + default: + break; + } +- +- } ++ } + } + + /* Done. */ +@@ -675,7 +680,7 @@ cipher_setkey (gcry_cipher_hd_t c, byte + } + } + +- rc = c->spec->setkey (&c->context.c, key, keylen); ++ rc = c->spec->setkey (&c->context.c, key, keylen, c); + if (!rc) + { + /* Duplicate initial context. */ +@@ -701,7 +706,7 @@ cipher_setkey (gcry_cipher_hd_t c, byte + case GCRY_CIPHER_MODE_XTS: + /* Setup tweak cipher with second part of XTS key. */ + rc = c->spec->setkey (c->u_mode.xts.tweak_context, key + keylen, +- keylen); ++ keylen, c); + if (!rc) + { + /* Duplicate initial tweak context. */ +@@ -872,85 +877,78 @@ do_ecb_decrypt (gcry_cipher_hd_t c, + } + + +-/**************** +- * 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) ++do_stream_encrypt (gcry_cipher_hd_t c, ++ unsigned char *outbuf, size_t outbuflen, ++ const unsigned char *inbuf, size_t inbuflen) ++{ ++ (void)outbuflen; ++ c->spec->stencrypt (&c->context.c, outbuf, (void *)inbuf, inbuflen); ++ return 0; ++} ++ ++static gcry_err_code_t ++do_stream_decrypt (gcry_cipher_hd_t c, ++ unsigned char *outbuf, size_t outbuflen, ++ const unsigned char *inbuf, size_t inbuflen) ++{ ++ (void)outbuflen; ++ c->spec->stdecrypt (&c->context.c, outbuf, (void *)inbuf, inbuflen); ++ return 0; ++} ++ ++ ++static gcry_err_code_t ++do_encrypt_none_unknown (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen, ++ const byte *inbuf, size_t inbuflen) + { + gcry_err_code_t rc; + +- if (c->mode != GCRY_CIPHER_MODE_NONE && !c->marks.key) +- { +- log_error ("cipher_encrypt: key not set\n"); +- return GPG_ERR_MISSING_KEY; +- } ++ (void)outbuflen; + + switch (c->mode) + { +- 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; +- +- case GCRY_CIPHER_MODE_CFB: +- rc = _gcry_cipher_cfb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); ++ case GCRY_CIPHER_MODE_CMAC: ++ rc = GPG_ERR_INV_CIPHER_MODE; + break; + +- case GCRY_CIPHER_MODE_CFB8: +- rc = _gcry_cipher_cfb8_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); ++ 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, inbuflen); ++ rc = 0; ++ } + break; + +- case GCRY_CIPHER_MODE_OFB: +- rc = _gcry_cipher_ofb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); ++ default: ++ log_fatal ("cipher_encrypt: invalid mode %d\n", c->mode ); ++ rc = GPG_ERR_INV_CIPHER_MODE; + break; ++ } + +- case GCRY_CIPHER_MODE_CTR: +- rc = _gcry_cipher_ctr_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); +- break; ++ return rc; ++} + +- case GCRY_CIPHER_MODE_AESWRAP: +- rc = _gcry_cipher_aeswrap_encrypt (c, outbuf, outbuflen, +- inbuf, inbuflen); +- break; ++static gcry_err_code_t ++do_decrypt_none_unknown (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen, ++ const byte *inbuf, size_t inbuflen) ++{ ++ gcry_err_code_t rc; + +- case GCRY_CIPHER_MODE_CCM: +- rc = _gcry_cipher_ccm_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); +- break; ++ (void)outbuflen; + ++ switch (c->mode) ++ { + case GCRY_CIPHER_MODE_CMAC: + rc = GPG_ERR_INV_CIPHER_MODE; + break; + +- case GCRY_CIPHER_MODE_GCM: +- rc = _gcry_cipher_gcm_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); +- break; +- +- case GCRY_CIPHER_MODE_POLY1305: +- rc = _gcry_cipher_poly1305_encrypt (c, outbuf, outbuflen, +- inbuf, inbuflen); +- break; +- +- case GCRY_CIPHER_MODE_OCB: +- rc = _gcry_cipher_ocb_encrypt (c, outbuf, outbuflen, inbuf, inbuflen); +- break; +- +- case GCRY_CIPHER_MODE_XTS: +- rc = _gcry_cipher_xts_crypt (c, outbuf, outbuflen, inbuf, inbuflen, 1); +- break; +- +- case GCRY_CIPHER_MODE_STREAM: +- c->spec->stencrypt (&c->context.c, +- outbuf, (byte*)/*arggg*/inbuf, inbuflen); +- rc = 0; +- break; +- + case GCRY_CIPHER_MODE_NONE: + if (fips_mode () || !_gcry_get_debug_flag (0)) + { +@@ -966,7 +964,7 @@ cipher_encrypt (gcry_cipher_hd_t c, byte + break; + + default: +- log_fatal ("cipher_encrypt: invalid mode %d\n", c->mode ); ++ log_fatal ("cipher_decrypt: invalid mode %d\n", c->mode ); + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } +@@ -991,7 +989,13 @@ _gcry_cipher_encrypt (gcry_cipher_hd_t h + inlen = outsize; + } + +- rc = cipher_encrypt (h, out, outsize, in, inlen); ++ if (h->mode != GCRY_CIPHER_MODE_NONE && !h->marks.key) ++ { ++ log_error ("cipher_decrypt: key not set\n"); ++ return GPG_ERR_MISSING_KEY; ++ } ++ ++ rc = h->mode_ops.encrypt (h, out, outsize, in, inlen); + + /* Failsafe: Make sure that the plaintext will never make it into + OUT if the encryption returned an error. */ +@@ -1002,110 +1006,10 @@ _gcry_cipher_encrypt (gcry_cipher_hd_t h + } + + +- + /**************** +- * 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 constraints apply to INBUFLEN. ++ * Decrypt IN and write it to OUT. If IN is NULL, in-place encryption has ++ * been requested. + */ +-static gcry_err_code_t +-cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, size_t outbuflen, +- const byte *inbuf, size_t inbuflen) +-{ +- gcry_err_code_t rc; +- +- if (c->mode != GCRY_CIPHER_MODE_NONE && !c->marks.key) +- { +- log_error ("cipher_decrypt: key not set\n"); +- return GPG_ERR_MISSING_KEY; +- } +- +- 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; +- +- case GCRY_CIPHER_MODE_CFB: +- rc = _gcry_cipher_cfb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); +- break; +- +- case GCRY_CIPHER_MODE_CFB8: +- rc = _gcry_cipher_cfb8_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); +- break; +- +- 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_POLY1305: +- rc = _gcry_cipher_poly1305_decrypt (c, outbuf, outbuflen, +- inbuf, inbuflen); +- break; +- +- case GCRY_CIPHER_MODE_OCB: +- rc = _gcry_cipher_ocb_decrypt (c, outbuf, outbuflen, inbuf, inbuflen); +- break; +- +- case GCRY_CIPHER_MODE_XTS: +- rc = _gcry_cipher_xts_crypt (c, outbuf, outbuflen, inbuf, inbuflen, 0); +- 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 +- { +- 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; +- } +- +- 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) +@@ -1116,9 +1020,14 @@ _gcry_cipher_decrypt (gcry_cipher_hd_t h + inlen = outsize; + } + +- return cipher_decrypt (h, out, outsize, in, inlen); +-} ++ if (h->mode != GCRY_CIPHER_MODE_NONE && !h->marks.key) ++ { ++ log_error ("cipher_decrypt: key not set\n"); ++ return GPG_ERR_MISSING_KEY; ++ } + ++ return h->mode_ops.decrypt (h, out, outsize, in, inlen); ++} + + + /**************** +@@ -1149,33 +1058,10 @@ _gcry_cipher_setkey (gcry_cipher_hd_t hd + gcry_err_code_t + _gcry_cipher_setiv (gcry_cipher_hd_t hd, const void *iv, size_t ivlen) + { +- gcry_err_code_t rc = 0; +- +- switch (hd->mode) +- { +- case GCRY_CIPHER_MODE_CCM: +- rc = _gcry_cipher_ccm_set_nonce (hd, iv, ivlen); +- break; +- +- case GCRY_CIPHER_MODE_GCM: +- rc = _gcry_cipher_gcm_setiv (hd, iv, ivlen); +- break; +- +- case GCRY_CIPHER_MODE_POLY1305: +- rc = _gcry_cipher_poly1305_setiv (hd, iv, ivlen); +- break; +- +- case GCRY_CIPHER_MODE_OCB: +- rc = _gcry_cipher_ocb_set_nonce (hd, iv, ivlen); +- break; +- +- default: +- rc = cipher_setiv (hd, iv, ivlen); +- break; +- } +- return rc; ++ return hd->mode_ops.setiv (hd, iv, ivlen); + } + ++ + /* 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. */ +@@ -1209,38 +1095,40 @@ _gcry_cipher_getctr (gcry_cipher_hd_t hd + return 0; + } + ++ + gcry_err_code_t + _gcry_cipher_authenticate (gcry_cipher_hd_t hd, const void *abuf, + size_t abuflen) + { + gcry_err_code_t rc; + +- switch (hd->mode) ++ if (hd->mode_ops.authenticate) + { +- 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; ++ rc = hd->mode_ops.authenticate (hd, abuf, abuflen); ++ } ++ else ++ { ++ log_error ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode); ++ rc = GPG_ERR_INV_CIPHER_MODE; ++ } + +- case GCRY_CIPHER_MODE_GCM: +- rc = _gcry_cipher_gcm_authenticate (hd, abuf, abuflen); +- break; ++ return rc; ++} + +- case GCRY_CIPHER_MODE_POLY1305: +- rc = _gcry_cipher_poly1305_authenticate (hd, abuf, abuflen); +- break; + +- case GCRY_CIPHER_MODE_OCB: +- rc = _gcry_cipher_ocb_authenticate (hd, abuf, abuflen); +- break; ++gcry_err_code_t ++_gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen) ++{ ++ gcry_err_code_t rc; + +- default: +- log_error ("gcry_cipher_authenticate: invalid mode %d\n", hd->mode); ++ if (hd->mode_ops.get_tag) ++ { ++ rc = hd->mode_ops.get_tag (hd, outtag, taglen); ++ } ++ else ++ { ++ log_error ("gcry_cipher_gettag: invalid mode %d\n", hd->mode); + rc = GPG_ERR_INV_CIPHER_MODE; +- break; + } + + return rc; +@@ -1248,76 +1136,166 @@ _gcry_cipher_authenticate (gcry_cipher_h + + + gcry_err_code_t +-_gcry_cipher_gettag (gcry_cipher_hd_t hd, void *outtag, size_t taglen) ++_gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen) + { + gcry_err_code_t rc; + +- switch (hd->mode) ++ if (hd->mode_ops.check_tag) + { +- case GCRY_CIPHER_MODE_CCM: +- rc = _gcry_cipher_ccm_get_tag (hd, outtag, taglen); ++ rc = hd->mode_ops.check_tag (hd, intag, taglen); ++ } ++ else ++ { ++ log_error ("gcry_cipher_checktag: invalid mode %d\n", hd->mode); ++ rc = GPG_ERR_INV_CIPHER_MODE; ++ } ++ ++ return rc; ++} ++ ++ ++ ++static void ++_gcry_cipher_setup_mode_ops(gcry_cipher_hd_t c, int mode) ++{ ++ /* Setup encryption and decryption routines. */ ++ switch (mode) ++ { ++ case GCRY_CIPHER_MODE_STREAM: ++ c->mode_ops.encrypt = do_stream_encrypt; ++ c->mode_ops.decrypt = do_stream_decrypt; + break; + +- case GCRY_CIPHER_MODE_CMAC: +- rc = _gcry_cipher_cmac_get_tag (hd, outtag, taglen); ++ case GCRY_CIPHER_MODE_ECB: ++ c->mode_ops.encrypt = do_ecb_encrypt; ++ c->mode_ops.decrypt = do_ecb_decrypt; ++ break; ++ ++ case GCRY_CIPHER_MODE_CBC: ++ c->mode_ops.encrypt = _gcry_cipher_cbc_encrypt; ++ c->mode_ops.decrypt = _gcry_cipher_cbc_decrypt; ++ break; ++ ++ case GCRY_CIPHER_MODE_CFB: ++ c->mode_ops.encrypt = _gcry_cipher_cfb_encrypt; ++ c->mode_ops.decrypt = _gcry_cipher_cfb_decrypt; ++ break; ++ ++ case GCRY_CIPHER_MODE_CFB8: ++ c->mode_ops.encrypt = _gcry_cipher_cfb8_encrypt; ++ c->mode_ops.decrypt = _gcry_cipher_cfb8_decrypt; ++ break; ++ ++ case GCRY_CIPHER_MODE_OFB: ++ c->mode_ops.encrypt = _gcry_cipher_ofb_encrypt; ++ c->mode_ops.decrypt = _gcry_cipher_ofb_encrypt; ++ break; ++ ++ case GCRY_CIPHER_MODE_CTR: ++ c->mode_ops.encrypt = _gcry_cipher_ctr_encrypt; ++ c->mode_ops.decrypt = _gcry_cipher_ctr_encrypt; ++ break; ++ ++ case GCRY_CIPHER_MODE_AESWRAP: ++ c->mode_ops.encrypt = _gcry_cipher_aeswrap_encrypt; ++ c->mode_ops.decrypt = _gcry_cipher_aeswrap_decrypt; ++ break; ++ ++ case GCRY_CIPHER_MODE_CCM: ++ c->mode_ops.encrypt = _gcry_cipher_ccm_encrypt; ++ c->mode_ops.decrypt = _gcry_cipher_ccm_decrypt; + break; + + case GCRY_CIPHER_MODE_GCM: +- rc = _gcry_cipher_gcm_get_tag (hd, outtag, taglen); ++ c->mode_ops.encrypt = _gcry_cipher_gcm_encrypt; ++ c->mode_ops.decrypt = _gcry_cipher_gcm_decrypt; + break; + + case GCRY_CIPHER_MODE_POLY1305: +- rc = _gcry_cipher_poly1305_get_tag (hd, outtag, taglen); ++ c->mode_ops.encrypt = _gcry_cipher_poly1305_encrypt; ++ c->mode_ops.decrypt = _gcry_cipher_poly1305_decrypt; + break; + + case GCRY_CIPHER_MODE_OCB: +- rc = _gcry_cipher_ocb_get_tag (hd, outtag, taglen); ++ c->mode_ops.encrypt = _gcry_cipher_ocb_encrypt; ++ c->mode_ops.decrypt = _gcry_cipher_ocb_decrypt; ++ break; ++ ++ case GCRY_CIPHER_MODE_XTS: ++ c->mode_ops.encrypt = _gcry_cipher_xts_encrypt; ++ c->mode_ops.decrypt = _gcry_cipher_xts_decrypt; + break; + + default: +- log_error ("gcry_cipher_gettag: invalid mode %d\n", hd->mode); +- rc = GPG_ERR_INV_CIPHER_MODE; ++ c->mode_ops.encrypt = do_encrypt_none_unknown; ++ c->mode_ops.decrypt = do_decrypt_none_unknown; + break; + } + +- return rc; +-} ++ /* Setup IV setting routine. */ ++ switch (mode) ++ { ++ case GCRY_CIPHER_MODE_CCM: ++ c->mode_ops.setiv = _gcry_cipher_ccm_set_nonce; ++ break; ++ ++ case GCRY_CIPHER_MODE_GCM: ++ c->mode_ops.setiv = _gcry_cipher_gcm_setiv; ++ break; + ++ case GCRY_CIPHER_MODE_POLY1305: ++ c->mode_ops.setiv = _gcry_cipher_poly1305_setiv; ++ break; + +-gcry_err_code_t +-_gcry_cipher_checktag (gcry_cipher_hd_t hd, const void *intag, size_t taglen) +-{ +- gcry_err_code_t rc; ++ case GCRY_CIPHER_MODE_OCB: ++ c->mode_ops.setiv = _gcry_cipher_ocb_set_nonce; ++ break; + +- switch (hd->mode) ++ default: ++ c->mode_ops.setiv = cipher_setiv; ++ break; ++ } ++ ++ ++ /* Setup authentication routines for AEAD modes. */ ++ switch (mode) + { + case GCRY_CIPHER_MODE_CCM: +- rc = _gcry_cipher_ccm_check_tag (hd, intag, taglen); ++ c->mode_ops.authenticate = _gcry_cipher_ccm_authenticate; ++ c->mode_ops.get_tag = _gcry_cipher_ccm_get_tag; ++ c->mode_ops.check_tag = _gcry_cipher_ccm_check_tag; + break; + + case GCRY_CIPHER_MODE_CMAC: +- rc = _gcry_cipher_cmac_check_tag (hd, intag, taglen); ++ c->mode_ops.authenticate = _gcry_cipher_cmac_authenticate; ++ c->mode_ops.get_tag = _gcry_cipher_cmac_get_tag; ++ c->mode_ops.check_tag = _gcry_cipher_cmac_check_tag; + break; + + case GCRY_CIPHER_MODE_GCM: +- rc = _gcry_cipher_gcm_check_tag (hd, intag, taglen); ++ c->mode_ops.authenticate = _gcry_cipher_gcm_authenticate; ++ c->mode_ops.get_tag = _gcry_cipher_gcm_get_tag; ++ c->mode_ops.check_tag = _gcry_cipher_gcm_check_tag; + break; + + case GCRY_CIPHER_MODE_POLY1305: +- rc = _gcry_cipher_poly1305_check_tag (hd, intag, taglen); ++ c->mode_ops.authenticate = _gcry_cipher_poly1305_authenticate; ++ c->mode_ops.get_tag = _gcry_cipher_poly1305_get_tag; ++ c->mode_ops.check_tag = _gcry_cipher_poly1305_check_tag; + break; + + case GCRY_CIPHER_MODE_OCB: +- rc = _gcry_cipher_ocb_check_tag (hd, intag, taglen); ++ c->mode_ops.authenticate = _gcry_cipher_ocb_authenticate; ++ c->mode_ops.get_tag = _gcry_cipher_ocb_get_tag; ++ c->mode_ops.check_tag = _gcry_cipher_ocb_check_tag; + break; + + default: +- log_error ("gcry_cipher_checktag: invalid mode %d\n", hd->mode); +- rc = GPG_ERR_INV_CIPHER_MODE; ++ c->mode_ops.authenticate = NULL; ++ c->mode_ops.get_tag = NULL; ++ c->mode_ops.check_tag = NULL; + break; + } +- +- return rc; + } + + +diff -up libgcrypt-1.8.5/cipher/cipher-cbc.c.aes-perf libgcrypt-1.8.5/cipher/cipher-cbc.c +--- libgcrypt-1.8.5/cipher/cipher-cbc.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/cipher-cbc.c 2020-04-22 18:29:41.666862306 +0200 +@@ -79,7 +79,7 @@ _gcry_cipher_cbc_encrypt (gcry_cipher_hd + + for (n=0; n < nblocks; n++ ) + { +- buf_xor (outbuf, inbuf, ivp, blocksize); ++ cipher_block_xor (outbuf, inbuf, ivp, blocksize); + nburn = enc_fn ( &c->context.c, outbuf, outbuf ); + burn = nburn > burn ? nburn : burn; + ivp = outbuf; +@@ -116,7 +116,7 @@ _gcry_cipher_cbc_encrypt (gcry_cipher_hd + + nburn = enc_fn (&c->context.c, outbuf, outbuf); + burn = nburn > burn ? nburn : burn; +- buf_cpy (c->u_iv.iv, outbuf, blocksize); ++ cipher_block_cpy (c->u_iv.iv, outbuf, blocksize); + } + + if (burn > 0) +@@ -158,7 +158,7 @@ _gcry_cipher_cbc_decrypt (gcry_cipher_hd + nblocks--; + if ((inbuflen % blocksize) == 0) + nblocks--; +- buf_cpy (c->lastiv, c->u_iv.iv, blocksize); ++ cipher_block_cpy (c->lastiv, c->u_iv.iv, blocksize); + } + + if (c->bulk.cbc_dec) +@@ -176,7 +176,8 @@ _gcry_cipher_cbc_decrypt (gcry_cipher_hd + 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); ++ cipher_block_xor_n_copy_2 (outbuf, c->lastiv, c->u_iv.iv, inbuf, ++ blocksize); + inbuf += blocksize; + outbuf += blocksize; + } +@@ -191,7 +192,7 @@ _gcry_cipher_cbc_decrypt (gcry_cipher_hd + else + restbytes = inbuflen % blocksize; + +- buf_cpy (c->lastiv, c->u_iv.iv, blocksize ); /* Save Cn-2. */ ++ cipher_block_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 ); +@@ -203,7 +204,7 @@ _gcry_cipher_cbc_decrypt (gcry_cipher_hd + 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); ++ cipher_block_xor(outbuf, outbuf, c->lastiv, blocksize); + /* c->lastiv is now really lastlastiv, does this matter? */ + } + +diff -up libgcrypt-1.8.5/cipher/cipher-ccm.c.aes-perf libgcrypt-1.8.5/cipher/cipher-ccm.c +--- libgcrypt-1.8.5/cipher/cipher-ccm.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/cipher-ccm.c 2020-04-22 18:29:41.666862306 +0200 +@@ -67,7 +67,8 @@ do_cbc_mac (gcry_cipher_hd_t c, const un + if (unused > 0) + { + /* Process one block from macbuf. */ +- buf_xor(c->u_iv.iv, c->u_iv.iv, c->u_mode.ccm.macbuf, blocksize); ++ cipher_block_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; +@@ -86,7 +87,7 @@ do_cbc_mac (gcry_cipher_hd_t c, const un + { + while (inlen >= blocksize) + { +- buf_xor(c->u_iv.iv, c->u_iv.iv, inbuf, blocksize); ++ cipher_block_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 )); + +@@ -272,7 +273,7 @@ _gcry_cipher_ccm_tag (gcry_cipher_hd_t c + 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); ++ cipher_block_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); +diff -up libgcrypt-1.8.5/cipher/cipher-cfb.c.aes-perf libgcrypt-1.8.5/cipher/cipher-cfb.c +--- libgcrypt-1.8.5/cipher/cipher-cfb.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/cipher-cfb.c 2020-04-22 18:29:41.667862287 +0200 +@@ -91,7 +91,7 @@ _gcry_cipher_cfb_encrypt (gcry_cipher_hd + 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); ++ cipher_block_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize); + outbuf += blocksize; + inbuf += blocksize; + inbuflen -= blocksize; +@@ -101,11 +101,11 @@ _gcry_cipher_cfb_encrypt (gcry_cipher_hd + if ( inbuflen >= blocksize ) + { + /* Save the current IV and then encrypt the IV. */ +- buf_cpy( c->lastiv, c->u_iv.iv, blocksize ); ++ cipher_block_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); ++ cipher_block_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize); + outbuf += blocksize; + inbuf += blocksize; + inbuflen -= blocksize; +@@ -113,7 +113,7 @@ _gcry_cipher_cfb_encrypt (gcry_cipher_hd + if ( inbuflen ) + { + /* Save the current IV and then encrypt the IV. */ +- buf_cpy( c->lastiv, c->u_iv.iv, blocksize ); ++ cipher_block_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; +@@ -193,7 +193,7 @@ _gcry_cipher_cfb_decrypt (gcry_cipher_hd + 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); ++ cipher_block_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize); + outbuf += blocksize; + inbuf += blocksize; + inbuflen -= blocksize; +@@ -203,11 +203,11 @@ _gcry_cipher_cfb_decrypt (gcry_cipher_hd + if (inbuflen >= blocksize ) + { + /* Save the current IV and then encrypt the IV. */ +- buf_cpy ( c->lastiv, c->u_iv.iv, blocksize); ++ cipher_block_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); ++ cipher_block_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize); + outbuf += blocksize; + inbuf += blocksize; + inbuflen -= blocksize; +@@ -216,7 +216,7 @@ _gcry_cipher_cfb_decrypt (gcry_cipher_hd + if (inbuflen) + { + /* Save the current IV and then encrypt the IV. */ +- buf_cpy ( c->lastiv, c->u_iv.iv, blocksize ); ++ cipher_block_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; +diff -up libgcrypt-1.8.5/cipher/cipher-cmac.c.aes-perf libgcrypt-1.8.5/cipher/cipher-cmac.c +--- libgcrypt-1.8.5/cipher/cipher-cmac.c.aes-perf 2020-04-22 18:29:41.643862745 +0200 ++++ libgcrypt-1.8.5/cipher/cipher-cmac.c 2020-04-22 18:29:41.667862287 +0200 +@@ -63,7 +63,7 @@ cmac_write (gcry_cipher_hd_t c, const by + for (; inlen && c->unused < blocksize; inlen--) + c->lastiv[c->unused++] = *inbuf++; + +- buf_xor (c->u_iv.iv, c->u_iv.iv, c->lastiv, blocksize); ++ cipher_block_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; +@@ -83,7 +83,7 @@ cmac_write (gcry_cipher_hd_t c, const by + else + while (inlen > blocksize) + { +- buf_xor (c->u_iv.iv, c->u_iv.iv, inbuf, blocksize); ++ cipher_block_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; +@@ -174,9 +174,9 @@ cmac_final (gcry_cipher_hd_t c) + c->lastiv[count++] = 0; + } + +- buf_xor (c->lastiv, c->lastiv, subkey, blocksize); ++ cipher_block_xor (c->lastiv, c->lastiv, subkey, blocksize); + +- buf_xor (c->u_iv.iv, c->u_iv.iv, c->lastiv, blocksize); ++ cipher_block_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 *)); +diff -up libgcrypt-1.8.5/cipher/cipher-ctr.c.aes-perf libgcrypt-1.8.5/cipher/cipher-ctr.c +--- libgcrypt-1.8.5/cipher/cipher-ctr.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/cipher-ctr.c 2020-04-22 18:29:41.667862287 +0200 +@@ -81,24 +81,34 @@ _gcry_cipher_ctr_encrypt (gcry_cipher_hd + { + 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); ++ 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; ++ } ++ ++ if (inbuflen < blocksize) ++ break; ++ n = blocksize; ++ cipher_block_xor(outbuf, inbuf, tmp, blocksize); ++ ++ inbuflen -= n; ++ outbuf += n; ++ inbuf += n; ++ } ++ while (inbuflen); ++ ++ if (inbuflen) ++ { ++ n = inbuflen; ++ buf_xor(outbuf, inbuf, tmp, inbuflen); ++ } + + /* Save the unused bytes of the counter. */ + c->unused = blocksize - n; +diff -up libgcrypt-1.8.5/cipher/cipher-gcm.c.aes-perf libgcrypt-1.8.5/cipher/cipher-gcm.c +--- libgcrypt-1.8.5/cipher/cipher-gcm.c.aes-perf 2018-04-17 17:27:25.000000000 +0200 ++++ libgcrypt-1.8.5/cipher/cipher-gcm.c 2020-04-22 18:29:41.667862287 +0200 +@@ -150,7 +150,7 @@ do_ghash (unsigned char *result, const u + u32 A; + int i; + +- buf_xor (V, result, buf, 16); ++ cipher_block_xor (V, result, buf, 16); + V[0] = be_bswap64 (V[0]); + V[1] = be_bswap64 (V[1]); + +@@ -259,7 +259,7 @@ do_ghash (unsigned char *result, const u + u32 T[3]; + int i; + +- buf_xor (V, result, buf, 16); /* V is big-endian */ ++ cipher_block_xor (V, result, buf, 16); /* V is big-endian */ + + /* First round can be manually tweaked based on fact that 'tmp' is zero. */ + i = 15; +@@ -342,7 +342,7 @@ do_ghash (unsigned char *hsub, unsigned + #else + unsigned long T[4]; + +- buf_xor (V, result, buf, 16); ++ cipher_block_xor (V, result, buf, 16); + for (i = 0; i < 4; i++) + { + V[i] = (V[i] & 0x00ff00ff) << 8 | (V[i] & 0xff00ff00) >> 8; +@@ -358,7 +358,7 @@ do_ghash (unsigned char *hsub, unsigned + for (j = 0x80; j; j >>= 1) + { + if (hsub[i] & j) +- buf_xor (p, p, V, 16); ++ cipher_block_xor (p, p, V, 16); + if (bshift (V)) + V[0] ^= 0xe1000000; + } +@@ -598,7 +598,7 @@ gcm_ctr_encrypt (gcry_cipher_hd_t c, byt + } + + fix_ctr = 1; +- buf_cpy(ctr_copy, c->u_ctr.ctr, GCRY_GCM_BLOCK_LEN); ++ cipher_block_cpy(ctr_copy, c->u_ctr.ctr, GCRY_GCM_BLOCK_LEN); + } + } + +@@ -928,8 +928,8 @@ _gcry_cipher_gcm_tag (gcry_cipher_hd_t c + /* 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); ++ cipher_block_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)); +diff -up libgcrypt-1.8.5/cipher/cipher-gcm-intel-pclmul.c.aes-perf libgcrypt-1.8.5/cipher/cipher-gcm-intel-pclmul.c +--- libgcrypt-1.8.5/cipher/cipher-gcm-intel-pclmul.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/cipher-gcm-intel-pclmul.c 2020-04-22 18:29:41.668862268 +0200 +@@ -248,7 +248,8 @@ static inline void gfmul_pclmul_aggr4(vo + void + _gcry_ghash_setup_intel_pclmul (gcry_cipher_hd_t c) + { +- u64 tmp[2]; ++ 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 }; + #if defined(__x86_64__) && defined(__WIN64__) + char win64tmp[3 * 16]; + +@@ -262,15 +263,19 @@ _gcry_ghash_setup_intel_pclmul (gcry_cip + #endif + + /* 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); ++ asm volatile ("movdqu (%[key]), %%xmm0\n\t" ++ "pshufb %[be_mask], %%xmm0\n\t" ++ "movdqu %%xmm0, (%[key])\n\t" ++ : ++ : [key] "r" (c->u_mode.gcm.u_ghash_key.key), ++ [be_mask] "m" (*be_mask) ++ : "memory"); + + #ifdef __x86_64__ +- asm volatile ("movdqu %[h_1], %%xmm0\n\t" +- "movdqa %%xmm0, %%xmm1\n\t" ++ asm volatile ("movdqa %%xmm0, %%xmm1\n\t" ++ : + : +- : [h_1] "m" (*tmp)); ++ : "memory"); + + gfmul_pclmul (); /* H•H => H² */ + +@@ -324,8 +329,6 @@ _gcry_ghash_setup_intel_pclmul (gcry_cip + ::: "cc" ); + #endif + #endif +- +- wipememory (tmp, sizeof(tmp)); + } + + +diff -up libgcrypt-1.8.5/cipher/cipher-internal.h.aes-perf libgcrypt-1.8.5/cipher/cipher-internal.h +--- libgcrypt-1.8.5/cipher/cipher-internal.h.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/cipher-internal.h 2020-04-22 18:29:41.668862268 +0200 +@@ -121,6 +121,25 @@ struct gcry_cipher_handle + interface does not easily allow to retrieve this value. */ + int algo; + ++ /* A structure with function pointers for mode operations. */ ++ struct { ++ gcry_err_code_t (*encrypt)(gcry_cipher_hd_t c, ++ unsigned char *outbuf, size_t outbuflen, ++ const unsigned char *inbuf, size_t inbuflen); ++ gcry_err_code_t (*decrypt)(gcry_cipher_hd_t c, ++ unsigned char *outbuf, size_t outbuflen, ++ const unsigned char *inbuf, size_t inbuflen); ++ gcry_err_code_t (*setiv)(gcry_cipher_hd_t c, const unsigned char *iv, ++ size_t ivlen); ++ ++ gcry_err_code_t (*authenticate)(gcry_cipher_hd_t c, ++ const unsigned char *abuf, size_t abuflen); ++ gcry_err_code_t (*get_tag)(gcry_cipher_hd_t c, unsigned char *outtag, ++ size_t taglen); ++ gcry_err_code_t (*check_tag)(gcry_cipher_hd_t c, const unsigned char *intag, ++ size_t taglen); ++ } mode_ops; ++ + /* 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 +@@ -146,7 +165,7 @@ struct gcry_cipher_handle + const void *inbuf_arg, size_t nblocks, int encrypt); + size_t (*ocb_auth)(gcry_cipher_hd_t c, const void *abuf_arg, + size_t nblocks); +- void (*xts_crypt)(gcry_cipher_hd_t c, unsigned char *tweak, ++ void (*xts_crypt)(void *context, unsigned char *tweak, + void *outbuf_arg, const void *inbuf_arg, + size_t nblocks, int encrypt); + } bulk; +@@ -479,9 +498,12 @@ gcry_err_code_t _gcry_cipher_ocb_check_t + + + /*-- cipher-xts.c --*/ +-gcry_err_code_t _gcry_cipher_xts_crypt ++gcry_err_code_t _gcry_cipher_xts_encrypt + /* */ (gcry_cipher_hd_t c, unsigned char *outbuf, size_t outbuflen, +- const unsigned char *inbuf, size_t inbuflen, int encrypt); ++ const unsigned char *inbuf, size_t inbuflen); ++gcry_err_code_t _gcry_cipher_xts_decrypt ++/* */ (gcry_cipher_hd_t c, unsigned char *outbuf, size_t outbuflen, ++ const unsigned char *inbuf, size_t inbuflen); + + + /* Return the L-value for block N. Note: 'cipher_ocb.c' ensures that N +@@ -506,4 +528,145 @@ ocb_get_l (gcry_cipher_hd_t c, u64 n) + return c->u_mode.ocb.L[ntz]; + } + ++/* Optimized function for cipher block copying */ ++static inline void ++cipher_block_cpy(void *_dst, const void *_src, size_t blocksize) ++{ ++ byte *dst = _dst; ++ const byte *src = _src; ++ u64 s[2]; ++ ++ if (blocksize == 8) ++ { ++ buf_put_he64(dst + 0, buf_get_he64(src + 0)); ++ } ++ else /* blocksize == 16 */ ++ { ++ s[0] = buf_get_he64(src + 0); ++ s[1] = buf_get_he64(src + 8); ++ buf_put_he64(dst + 0, s[0]); ++ buf_put_he64(dst + 8, s[1]); ++ } ++} ++ ++ ++/* Optimized function for cipher block xoring */ ++static inline void ++cipher_block_xor(void *_dst, const void *_src1, const void *_src2, ++ size_t blocksize) ++{ ++ byte *dst = _dst; ++ const byte *src1 = _src1; ++ const byte *src2 = _src2; ++ u64 s1[2]; ++ u64 s2[2]; ++ ++ if (blocksize == 8) ++ { ++ buf_put_he64(dst + 0, buf_get_he64(src1 + 0) ^ buf_get_he64(src2 + 0)); ++ } ++ else /* blocksize == 16 */ ++ { ++ s1[0] = buf_get_he64(src1 + 0); ++ s1[1] = buf_get_he64(src1 + 8); ++ s2[0] = buf_get_he64(src2 + 0); ++ s2[1] = buf_get_he64(src2 + 8); ++ buf_put_he64(dst + 0, s1[0] ^ s2[0]); ++ buf_put_he64(dst + 8, s1[1] ^ s2[1]); ++ } ++} ++ ++ ++/* Optimized function for in-place cipher block xoring */ ++static inline void ++cipher_block_xor_1(void *_dst, const void *_src, size_t blocksize) ++{ ++ cipher_block_xor (_dst, _dst, _src, blocksize); ++} ++ ++ ++/* Optimized function for cipher block xoring with two destination cipher ++ blocks. Used mainly by CFB mode encryption. */ ++static inline void ++cipher_block_xor_2dst(void *_dst1, void *_dst2, const void *_src, ++ size_t blocksize) ++{ ++ byte *dst1 = _dst1; ++ byte *dst2 = _dst2; ++ const byte *src = _src; ++ u64 d2[2]; ++ u64 s[2]; ++ ++ if (blocksize == 8) ++ { ++ d2[0] = buf_get_he64(dst2 + 0) ^ buf_get_he64(src + 0); ++ buf_put_he64(dst2 + 0, d2[0]); ++ buf_put_he64(dst1 + 0, d2[0]); ++ } ++ else /* blocksize == 16 */ ++ { ++ s[0] = buf_get_he64(src + 0); ++ s[1] = buf_get_he64(src + 8); ++ d2[0] = buf_get_he64(dst2 + 0); ++ d2[1] = buf_get_he64(dst2 + 8); ++ d2[0] = d2[0] ^ s[0]; ++ d2[1] = d2[1] ^ s[1]; ++ buf_put_he64(dst2 + 0, d2[0]); ++ buf_put_he64(dst2 + 8, d2[1]); ++ buf_put_he64(dst1 + 0, d2[0]); ++ buf_put_he64(dst1 + 8, d2[1]); ++ } ++} ++ ++ ++/* Optimized function for combined cipher block xoring and copying. ++ Used by mainly CBC mode decryption. */ ++static inline void ++cipher_block_xor_n_copy_2(void *_dst_xor, const void *_src_xor, ++ void *_srcdst_cpy, const void *_src_cpy, ++ size_t blocksize) ++{ ++ byte *dst_xor = _dst_xor; ++ byte *srcdst_cpy = _srcdst_cpy; ++ const byte *src_xor = _src_xor; ++ const byte *src_cpy = _src_cpy; ++ u64 sc[2]; ++ u64 sx[2]; ++ u64 sdc[2]; ++ ++ if (blocksize == 8) ++ { ++ sc[0] = buf_get_he64(src_cpy + 0); ++ buf_put_he64(dst_xor + 0, ++ buf_get_he64(srcdst_cpy + 0) ^ buf_get_he64(src_xor + 0)); ++ buf_put_he64(srcdst_cpy + 0, sc[0]); ++ } ++ else /* blocksize == 16 */ ++ { ++ sc[0] = buf_get_he64(src_cpy + 0); ++ sc[1] = buf_get_he64(src_cpy + 8); ++ sx[0] = buf_get_he64(src_xor + 0); ++ sx[1] = buf_get_he64(src_xor + 8); ++ sdc[0] = buf_get_he64(srcdst_cpy + 0); ++ sdc[1] = buf_get_he64(srcdst_cpy + 8); ++ sx[0] ^= sdc[0]; ++ sx[1] ^= sdc[1]; ++ buf_put_he64(dst_xor + 0, sx[0]); ++ buf_put_he64(dst_xor + 8, sx[1]); ++ buf_put_he64(srcdst_cpy + 0, sc[0]); ++ buf_put_he64(srcdst_cpy + 8, sc[1]); ++ } ++} ++ ++ ++/* Optimized function for combined cipher block xoring and copying. ++ Used by mainly CFB mode decryption. */ ++static inline void ++cipher_block_xor_n_copy(void *_dst_xor, void *_srcdst_cpy, const void *_src, ++ size_t blocksize) ++{ ++ cipher_block_xor_n_copy_2(_dst_xor, _src, _srcdst_cpy, _src, blocksize); ++} ++ ++ + #endif /*G10_CIPHER_INTERNAL_H*/ +diff -up libgcrypt-1.8.5/cipher/cipher-ocb.c.aes-perf libgcrypt-1.8.5/cipher/cipher-ocb.c +--- libgcrypt-1.8.5/cipher/cipher-ocb.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/cipher-ocb.c 2020-04-22 18:29:41.668862268 +0200 +@@ -82,7 +82,7 @@ static void + double_block_cpy (unsigned char *d, const unsigned char *s) + { + if (d != s) +- buf_cpy (d, s, OCB_BLOCK_LEN); ++ cipher_block_cpy (d, s, OCB_BLOCK_LEN); + double_block (d); + } + +@@ -181,8 +181,8 @@ _gcry_cipher_ocb_set_nonce (gcry_cipher_ + nburn = c->spec->encrypt (&c->context.c, ktop, ktop); + burn = nburn > burn ? nburn : burn; + /* Stretch = Ktop || (Ktop[1..64] xor Ktop[9..72]) */ +- buf_cpy (stretch, ktop, OCB_BLOCK_LEN); +- buf_xor (stretch + OCB_BLOCK_LEN, ktop, ktop + 1, 8); ++ cipher_block_cpy (stretch, ktop, OCB_BLOCK_LEN); ++ cipher_block_xor (stretch + OCB_BLOCK_LEN, ktop, ktop + 1, 8); + /* Offset_0 = Stretch[1+bottom..128+bottom] + (We use the IV field to store the offset) */ + bit_copy (c->u_iv.iv, stretch, bottom, OCB_BLOCK_LEN); +@@ -267,18 +267,18 @@ _gcry_cipher_ocb_authenticate (gcry_ciph + } + else + { +- buf_cpy (l_tmp, ocb_get_l (c, c->u_mode.ocb.aad_nblocks), +- OCB_BLOCK_LEN); ++ cipher_block_cpy (l_tmp, ocb_get_l (c, c->u_mode.ocb.aad_nblocks), ++ OCB_BLOCK_LEN); + } + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ +- buf_xor_1 (c->u_mode.ocb.aad_offset, l_tmp, OCB_BLOCK_LEN); ++ cipher_block_xor_1 (c->u_mode.ocb.aad_offset, l_tmp, OCB_BLOCK_LEN); + /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) */ +- buf_xor (l_tmp, c->u_mode.ocb.aad_offset, +- c->u_mode.ocb.aad_leftover, OCB_BLOCK_LEN); ++ cipher_block_xor (l_tmp, c->u_mode.ocb.aad_offset, ++ c->u_mode.ocb.aad_leftover, OCB_BLOCK_LEN); + nburn = c->spec->encrypt (&c->context.c, l_tmp, l_tmp); + burn = nburn > burn ? nburn : burn; +- buf_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); ++ cipher_block_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); + + c->u_mode.ocb.aad_nleftover = 0; + } +@@ -309,12 +309,13 @@ _gcry_cipher_ocb_authenticate (gcry_ciph + ocb_get_L_big(c, c->u_mode.ocb.aad_nblocks, l_tmp); + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ +- buf_xor_1 (c->u_mode.ocb.aad_offset, l_tmp, OCB_BLOCK_LEN); ++ cipher_block_xor_1 (c->u_mode.ocb.aad_offset, l_tmp, OCB_BLOCK_LEN); + /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) */ +- buf_xor (l_tmp, c->u_mode.ocb.aad_offset, abuf, OCB_BLOCK_LEN); ++ cipher_block_xor (l_tmp, c->u_mode.ocb.aad_offset, abuf, ++ OCB_BLOCK_LEN); + nburn = c->spec->encrypt (&c->context.c, l_tmp, l_tmp); + burn = nburn > burn ? nburn : burn; +- buf_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); ++ cipher_block_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); + + abuf += OCB_BLOCK_LEN; + abuflen -= OCB_BLOCK_LEN; +@@ -349,14 +350,15 @@ _gcry_cipher_ocb_authenticate (gcry_ciph + gcry_assert(c->u_mode.ocb.aad_nblocks & table_size_mask); + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ +- buf_xor_1 (c->u_mode.ocb.aad_offset, +- ocb_get_l (c, c->u_mode.ocb.aad_nblocks), +- OCB_BLOCK_LEN); ++ cipher_block_xor_1 (c->u_mode.ocb.aad_offset, ++ ocb_get_l (c, c->u_mode.ocb.aad_nblocks), ++ OCB_BLOCK_LEN); + /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) */ +- buf_xor (l_tmp, c->u_mode.ocb.aad_offset, abuf, OCB_BLOCK_LEN); ++ cipher_block_xor (l_tmp, c->u_mode.ocb.aad_offset, abuf, ++ OCB_BLOCK_LEN); + nburn = c->spec->encrypt (&c->context.c, l_tmp, l_tmp); + burn = nburn > burn ? nburn : burn; +- buf_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); ++ cipher_block_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); + + abuf += OCB_BLOCK_LEN; + abuflen -= OCB_BLOCK_LEN; +@@ -397,18 +399,18 @@ ocb_aad_finalize (gcry_cipher_hd_t c) + if (c->u_mode.ocb.aad_nleftover) + { + /* Offset_* = Offset_m xor L_* */ +- buf_xor_1 (c->u_mode.ocb.aad_offset, +- c->u_mode.ocb.L_star, OCB_BLOCK_LEN); ++ cipher_block_xor_1 (c->u_mode.ocb.aad_offset, ++ c->u_mode.ocb.L_star, OCB_BLOCK_LEN); + /* CipherInput = (A_* || 1 || zeros(127-bitlen(A_*))) xor Offset_* */ + buf_cpy (l_tmp, c->u_mode.ocb.aad_leftover, c->u_mode.ocb.aad_nleftover); + memset (l_tmp + c->u_mode.ocb.aad_nleftover, 0, + OCB_BLOCK_LEN - c->u_mode.ocb.aad_nleftover); + l_tmp[c->u_mode.ocb.aad_nleftover] = 0x80; +- buf_xor_1 (l_tmp, c->u_mode.ocb.aad_offset, OCB_BLOCK_LEN); ++ cipher_block_xor_1 (l_tmp, c->u_mode.ocb.aad_offset, OCB_BLOCK_LEN); + /* Sum = Sum_m xor ENCIPHER(K, CipherInput) */ + nburn = c->spec->encrypt (&c->context.c, l_tmp, l_tmp); + burn = nburn > burn ? nburn : burn; +- buf_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); ++ cipher_block_xor_1 (c->u_mode.ocb.aad_sum, l_tmp, OCB_BLOCK_LEN); + + c->u_mode.ocb.aad_nleftover = 0; + } +@@ -431,7 +433,7 @@ ocb_checksum (unsigned char *chksum, con + while (nblks > 0) + { + /* Checksum_i = Checksum_{i-1} xor P_i */ +- buf_xor_1(chksum, plainbuf, OCB_BLOCK_LEN); ++ cipher_block_xor_1(chksum, plainbuf, OCB_BLOCK_LEN); + + plainbuf += OCB_BLOCK_LEN; + nblks--; +@@ -491,12 +493,12 @@ ocb_crypt (gcry_cipher_hd_t c, int encry + } + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ +- buf_xor_1 (c->u_iv.iv, l_tmp, OCB_BLOCK_LEN); ++ cipher_block_xor_1 (c->u_iv.iv, l_tmp, OCB_BLOCK_LEN); + /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */ +- buf_xor (outbuf, c->u_iv.iv, inbuf, OCB_BLOCK_LEN); ++ cipher_block_xor (outbuf, c->u_iv.iv, inbuf, OCB_BLOCK_LEN); + nburn = crypt_fn (&c->context.c, outbuf, outbuf); + burn = nburn > burn ? nburn : burn; +- buf_xor_1 (outbuf, c->u_iv.iv, OCB_BLOCK_LEN); ++ cipher_block_xor_1 (outbuf, c->u_iv.iv, OCB_BLOCK_LEN); + + if (!encrypt) + { +@@ -551,14 +553,14 @@ ocb_crypt (gcry_cipher_hd_t c, int encry + gcry_assert(c->u_mode.ocb.data_nblocks & table_size_mask); + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ +- buf_xor_1 (c->u_iv.iv, +- ocb_get_l (c, c->u_mode.ocb.data_nblocks), +- OCB_BLOCK_LEN); ++ cipher_block_xor_1 (c->u_iv.iv, ++ ocb_get_l (c, c->u_mode.ocb.data_nblocks), ++ OCB_BLOCK_LEN); + /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */ +- buf_xor (outbuf, c->u_iv.iv, inbuf, OCB_BLOCK_LEN); ++ cipher_block_xor (outbuf, c->u_iv.iv, inbuf, OCB_BLOCK_LEN); + nburn = crypt_fn (&c->context.c, outbuf, outbuf); + burn = nburn > burn ? nburn : burn; +- buf_xor_1 (outbuf, c->u_iv.iv, OCB_BLOCK_LEN); ++ cipher_block_xor_1 (outbuf, c->u_iv.iv, OCB_BLOCK_LEN); + + inbuf += OCB_BLOCK_LEN; + inbuflen -= OCB_BLOCK_LEN; +@@ -584,7 +586,7 @@ ocb_crypt (gcry_cipher_hd_t c, int encry + unsigned char pad[OCB_BLOCK_LEN]; + + /* Offset_* = Offset_m xor L_* */ +- buf_xor_1 (c->u_iv.iv, c->u_mode.ocb.L_star, OCB_BLOCK_LEN); ++ cipher_block_xor_1 (c->u_iv.iv, c->u_mode.ocb.L_star, OCB_BLOCK_LEN); + /* Pad = ENCIPHER(K, Offset_*) */ + nburn = c->spec->encrypt (&c->context.c, pad, c->u_iv.iv); + burn = nburn > burn ? nburn : burn; +@@ -596,7 +598,7 @@ ocb_crypt (gcry_cipher_hd_t c, int encry + buf_cpy (l_tmp, inbuf, inbuflen); + memset (l_tmp + inbuflen, 0, OCB_BLOCK_LEN - inbuflen); + l_tmp[inbuflen] = 0x80; +- buf_xor_1 (c->u_ctr.ctr, l_tmp, OCB_BLOCK_LEN); ++ cipher_block_xor_1 (c->u_ctr.ctr, l_tmp, OCB_BLOCK_LEN); + /* C_* = P_* xor Pad[1..bitlen(P_*)] */ + buf_xor (outbuf, inbuf, pad, inbuflen); + } +@@ -604,13 +606,13 @@ ocb_crypt (gcry_cipher_hd_t c, int encry + { + /* P_* = C_* xor Pad[1..bitlen(C_*)] */ + /* Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) */ +- buf_cpy (l_tmp, pad, OCB_BLOCK_LEN); ++ cipher_block_cpy (l_tmp, pad, OCB_BLOCK_LEN); + buf_cpy (l_tmp, inbuf, inbuflen); +- buf_xor_1 (l_tmp, pad, OCB_BLOCK_LEN); ++ cipher_block_xor_1 (l_tmp, pad, OCB_BLOCK_LEN); + l_tmp[inbuflen] = 0x80; + buf_cpy (outbuf, l_tmp, inbuflen); + +- buf_xor_1 (c->u_ctr.ctr, l_tmp, OCB_BLOCK_LEN); ++ cipher_block_xor_1 (c->u_ctr.ctr, l_tmp, OCB_BLOCK_LEN); + } + } + +@@ -618,8 +620,10 @@ ocb_crypt (gcry_cipher_hd_t c, int encry + if (c->marks.finalize) + { + /* Tag = ENCIPHER(K, Checksum xor Offset xor L_$) xor HASH(K,A) */ +- buf_xor (c->u_mode.ocb.tag, c->u_ctr.ctr, c->u_iv.iv, OCB_BLOCK_LEN); +- buf_xor_1 (c->u_mode.ocb.tag, c->u_mode.ocb.L_dollar, OCB_BLOCK_LEN); ++ cipher_block_xor (c->u_mode.ocb.tag, c->u_ctr.ctr, c->u_iv.iv, ++ OCB_BLOCK_LEN); ++ cipher_block_xor_1 (c->u_mode.ocb.tag, c->u_mode.ocb.L_dollar, ++ OCB_BLOCK_LEN); + nburn = c->spec->encrypt (&c->context.c, + c->u_mode.ocb.tag, c->u_mode.ocb.tag); + burn = nburn > burn ? nburn : burn; +@@ -672,7 +676,8 @@ compute_tag_if_needed (gcry_cipher_hd_t + if (!c->marks.tag) + { + ocb_aad_finalize (c); +- buf_xor_1 (c->u_mode.ocb.tag, c->u_mode.ocb.aad_sum, OCB_BLOCK_LEN); ++ cipher_block_xor_1 (c->u_mode.ocb.tag, c->u_mode.ocb.aad_sum, ++ OCB_BLOCK_LEN); + c->marks.tag = 1; + } + } +diff -up libgcrypt-1.8.5/cipher/cipher-ofb.c.aes-perf libgcrypt-1.8.5/cipher/cipher-ofb.c +--- libgcrypt-1.8.5/cipher/cipher-ofb.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/cipher-ofb.c 2020-04-22 18:29:41.668862268 +0200 +@@ -76,7 +76,7 @@ _gcry_cipher_ofb_encrypt (gcry_cipher_hd + /* 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); ++ cipher_block_xor(outbuf, c->u_iv.iv, inbuf, blocksize); + outbuf += blocksize; + inbuf += blocksize; + inbuflen -= blocksize; +diff -up libgcrypt-1.8.5/cipher/cipher-selftest.c.aes-perf libgcrypt-1.8.5/cipher/cipher-selftest.c +--- libgcrypt-1.8.5/cipher/cipher-selftest.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/cipher-selftest.c 2020-04-22 18:29:41.669862248 +0200 +@@ -105,7 +105,7 @@ _gcry_selftest_helper_cbc (const char *c + ciphertext = plaintext2 + nblocks * blocksize; + + /* Initialize ctx */ +- if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR) ++ if (setkey_func (ctx, key, sizeof(key), NULL) != GPG_ERR_NO_ERROR) + { + xfree(mem); + return "setkey failed"; +@@ -228,7 +228,7 @@ _gcry_selftest_helper_cfb (const char *c + ciphertext = plaintext2 + nblocks * blocksize; + + /* Initialize ctx */ +- if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR) ++ if (setkey_func (ctx, key, sizeof(key), NULL) != GPG_ERR_NO_ERROR) + { + xfree(mem); + return "setkey failed"; +@@ -351,7 +351,7 @@ _gcry_selftest_helper_ctr (const char *c + ciphertext2 = ciphertext + nblocks * blocksize; + + /* Initialize ctx */ +- if (setkey_func (ctx, key, sizeof(key)) != GPG_ERR_NO_ERROR) ++ if (setkey_func (ctx, key, sizeof(key), NULL) != GPG_ERR_NO_ERROR) + { + xfree(mem); + return "setkey failed"; +diff -up libgcrypt-1.8.5/cipher/cipher-xts.c.aes-perf libgcrypt-1.8.5/cipher/cipher-xts.c +--- libgcrypt-1.8.5/cipher/cipher-xts.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/cipher-xts.c 2020-04-22 18:29:41.669862248 +0200 +@@ -93,7 +93,8 @@ _gcry_cipher_xts_crypt (gcry_cipher_hd_t + /* Use a bulk method if available. */ + if (nblocks && c->bulk.xts_crypt) + { +- c->bulk.xts_crypt (c, c->u_ctr.ctr, outbuf, inbuf, nblocks, encrypt); ++ c->bulk.xts_crypt (&c->context.c, c->u_ctr.ctr, outbuf, inbuf, nblocks, ++ encrypt); + inbuf += nblocks * GCRY_XTS_BLOCK_LEN; + outbuf += nblocks * GCRY_XTS_BLOCK_LEN; + inbuflen -= nblocks * GCRY_XTS_BLOCK_LEN; +@@ -106,10 +107,10 @@ _gcry_cipher_xts_crypt (gcry_cipher_hd_t + while (nblocks) + { + /* Xor-Encrypt/Decrypt-Xor block. */ +- buf_xor (tmp.x64, inbuf, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); ++ cipher_block_xor (tmp.x64, inbuf, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); + nburn = crypt_fn (&c->context.c, tmp.x1, tmp.x1); + burn = nburn > burn ? nburn : burn; +- buf_xor (outbuf, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); ++ cipher_block_xor (outbuf, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); + + outbuf += GCRY_XTS_BLOCK_LEN; + inbuf += GCRY_XTS_BLOCK_LEN; +@@ -132,10 +133,10 @@ _gcry_cipher_xts_crypt (gcry_cipher_hd_t + xts_gfmul_byA (tmp.x1, c->u_ctr.ctr); + + /* Decrypt last block first. */ +- buf_xor (outbuf, inbuf, tmp.x64, GCRY_XTS_BLOCK_LEN); ++ cipher_block_xor (outbuf, inbuf, tmp.x64, GCRY_XTS_BLOCK_LEN); + nburn = crypt_fn (&c->context.c, outbuf, outbuf); + burn = nburn > burn ? nburn : burn; +- buf_xor (outbuf, outbuf, tmp.x64, GCRY_XTS_BLOCK_LEN); ++ cipher_block_xor (outbuf, outbuf, tmp.x64, GCRY_XTS_BLOCK_LEN); + + inbuflen -= GCRY_XTS_BLOCK_LEN; + inbuf += GCRY_XTS_BLOCK_LEN; +@@ -146,15 +147,15 @@ _gcry_cipher_xts_crypt (gcry_cipher_hd_t + outbuf -= GCRY_XTS_BLOCK_LEN; + + /* Steal ciphertext from previous block. */ +- buf_cpy (tmp.x64, outbuf, GCRY_XTS_BLOCK_LEN); ++ cipher_block_cpy (tmp.x64, outbuf, GCRY_XTS_BLOCK_LEN); + buf_cpy (tmp.x64, inbuf, inbuflen); + buf_cpy (outbuf + GCRY_XTS_BLOCK_LEN, outbuf, inbuflen); + + /* Decrypt/Encrypt last block. */ +- buf_xor (tmp.x64, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); ++ cipher_block_xor (tmp.x64, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); + nburn = crypt_fn (&c->context.c, tmp.x1, tmp.x1); + burn = nburn > burn ? nburn : burn; +- buf_xor (outbuf, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); ++ cipher_block_xor (outbuf, tmp.x64, c->u_ctr.ctr, GCRY_XTS_BLOCK_LEN); + } + + /* Auto-increment data-unit sequence number */ +@@ -168,3 +169,21 @@ _gcry_cipher_xts_crypt (gcry_cipher_hd_t + + return 0; + } ++ ++ ++gcry_err_code_t ++_gcry_cipher_xts_encrypt (gcry_cipher_hd_t c, ++ unsigned char *outbuf, size_t outbuflen, ++ const unsigned char *inbuf, size_t inbuflen) ++{ ++ return _gcry_cipher_xts_crypt (c, outbuf, outbuflen, inbuf, inbuflen, 1); ++} ++ ++ ++gcry_err_code_t ++_gcry_cipher_xts_decrypt (gcry_cipher_hd_t c, ++ unsigned char *outbuf, size_t outbuflen, ++ const unsigned char *inbuf, size_t inbuflen) ++{ ++ return _gcry_cipher_xts_crypt (c, outbuf, outbuflen, inbuf, inbuflen, 0); ++} +diff -up libgcrypt-1.8.5/cipher/des.c.aes-perf libgcrypt-1.8.5/cipher/des.c +--- libgcrypt-1.8.5/cipher/des.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/des.c 2020-04-22 18:29:41.669862248 +0200 +@@ -119,6 +119,7 @@ + #include "g10lib.h" + #include "cipher.h" + #include "bufhelp.h" ++#include "cipher-internal.h" + #include "cipher-selftest.h" + + +@@ -197,7 +198,8 @@ static unsigned int do_tripledes_encrypt + static unsigned int do_tripledes_decrypt(void *context, byte *outbuf, + const byte *inbuf ); + static gcry_err_code_t do_tripledes_setkey(void *context, const byte *key, +- unsigned keylen); ++ unsigned keylen, ++ gcry_cipher_hd_t hd); + + static int initialized; + +@@ -940,7 +942,7 @@ _gcry_3des_ctr_enc(void *context, unsign + /* Encrypt the counter. */ + tripledes_ecb_encrypt (ctx, ctr, tmpbuf); + /* XOR the input with the encrypted counter and store in output. */ +- buf_xor(outbuf, tmpbuf, inbuf, DES_BLOCKSIZE); ++ cipher_block_xor(outbuf, tmpbuf, inbuf, DES_BLOCKSIZE); + outbuf += DES_BLOCKSIZE; + inbuf += DES_BLOCKSIZE; + /* Increment the counter. */ +@@ -996,7 +998,7 @@ _gcry_3des_cbc_dec(void *context, unsign + the intermediate result to SAVEBUF. */ + tripledes_ecb_decrypt (ctx, inbuf, savebuf); + +- buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, DES_BLOCKSIZE); ++ cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, DES_BLOCKSIZE); + inbuf += DES_BLOCKSIZE; + outbuf += DES_BLOCKSIZE; + } +@@ -1041,7 +1043,7 @@ _gcry_3des_cfb_dec(void *context, unsign + for ( ;nblocks; nblocks-- ) + { + tripledes_ecb_encrypt (ctx, iv, iv); +- buf_xor_n_copy(outbuf, iv, inbuf, DES_BLOCKSIZE); ++ cipher_block_xor_n_copy(outbuf, iv, inbuf, DES_BLOCKSIZE); + outbuf += DES_BLOCKSIZE; + inbuf += DES_BLOCKSIZE; + } +@@ -1086,7 +1088,8 @@ is_weak_key ( const byte *key ) + + /* Alternative setkey for selftests; need larger key than default. */ + static gcry_err_code_t +-bulk_selftest_setkey (void *context, const byte *__key, unsigned __keylen) ++bulk_selftest_setkey (void *context, const byte *__key, unsigned __keylen, ++ gcry_cipher_hd_t hd) + { + static const unsigned char key[24] ATTR_ALIGNED_16 = { + 0x66,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, +@@ -1094,10 +1097,11 @@ bulk_selftest_setkey (void *context, con + 0x18,0x2A,0x39,0x47,0x5E,0x6F,0x75,0x82 + }; + ++ (void)hd; + (void)__key; + (void)__keylen; + +- return do_tripledes_setkey(context, key, sizeof(key)); ++ return do_tripledes_setkey(context, key, sizeof(key), NULL); + } + + +@@ -1349,10 +1353,13 @@ selftest (void) + + + static gcry_err_code_t +-do_tripledes_setkey ( void *context, const byte *key, unsigned keylen ) ++do_tripledes_setkey ( void *context, const byte *key, unsigned keylen, ++ gcry_cipher_hd_t hd ) + { + struct _tripledes_ctx *ctx = (struct _tripledes_ctx *) context; + ++ (void)hd; ++ + if( keylen != 24 ) + return GPG_ERR_INV_KEYLEN; + +@@ -1413,10 +1420,13 @@ do_tripledes_decrypt( void *context, byt + } + + static gcry_err_code_t +-do_des_setkey (void *context, const byte *key, unsigned keylen) ++do_des_setkey (void *context, const byte *key, unsigned keylen, ++ gcry_cipher_hd_t hd) + { + struct _des_ctx *ctx = (struct _des_ctx *) context; + ++ (void)hd; ++ + if (keylen != 8) + return GPG_ERR_INV_KEYLEN; + +diff -up libgcrypt-1.8.5/cipher/gost28147.c.aes-perf libgcrypt-1.8.5/cipher/gost28147.c +--- libgcrypt-1.8.5/cipher/gost28147.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/gost28147.c 2020-04-22 18:29:41.669862248 +0200 +@@ -39,11 +39,14 @@ + #include "gost-sb.h" + + static gcry_err_code_t +-gost_setkey (void *c, const byte *key, unsigned keylen) ++gost_setkey (void *c, const byte *key, unsigned keylen, ++ gcry_cipher_hd_t hd) + { + int i; + GOST28147_context *ctx = c; + ++ (void)hd; ++ + if (keylen != 256 / 8) + return GPG_ERR_INV_KEYLEN; + +diff -up libgcrypt-1.8.5/cipher/idea.c.aes-perf libgcrypt-1.8.5/cipher/idea.c +--- libgcrypt-1.8.5/cipher/idea.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/idea.c 2020-04-22 18:29:41.670862229 +0200 +@@ -258,10 +258,12 @@ do_setkey( IDEA_context *c, const byte * + } + + static gcry_err_code_t +-idea_setkey (void *context, const byte *key, unsigned int keylen) ++idea_setkey (void *context, const byte *key, unsigned int keylen, ++ gcry_cipher_hd_t hd) + { + IDEA_context *ctx = context; + int rc = do_setkey (ctx, key, keylen); ++ (void)hd; + _gcry_burn_stack (23+6*sizeof(void*)); + return rc; + } +diff -up libgcrypt-1.8.5/cipher/Makefile.am.aes-perf libgcrypt-1.8.5/cipher/Makefile.am +--- libgcrypt-1.8.5/cipher/Makefile.am.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/Makefile.am 2020-04-22 18:29:41.670862229 +0200 +@@ -83,7 +83,8 @@ rijndael.c rijndael-internal.h rijndael- + rijndael-padlock.c rijndael-amd64.S rijndael-arm.S \ + rijndael-ssse3-amd64.c rijndael-ssse3-amd64-asm.S \ + rijndael-armv8-ce.c rijndael-armv8-aarch32-ce.S rijndael-armv8-aarch64-ce.S \ +- rijndael-aarch64.S \ ++ rijndael-aarch64.S rijndael-ppc.c rijndael-ppc9le.c \ ++ rijndael-ppc-common.h rijndael-ppc-functions.h \ + rmd160.c \ + rsa.c \ + salsa20.c salsa20-amd64.S salsa20-armv7-neon.S \ +@@ -128,3 +129,23 @@ tiger.o: $(srcdir)/tiger.c + + tiger.lo: $(srcdir)/tiger.c + `echo $(LTCOMPILE) -c $(srcdir)/tiger.c | $(o_flag_munging) ` ++ ++if ENABLE_PPC_VCRYPTO_EXTRA_CFLAGS ++ppc_vcrypto_cflags = -maltivec -mvsx -mcrypto ++else ++ppc_vcrypto_cflags = ++endif ++ ++rijndael-ppc.o: $(srcdir)/rijndael-ppc.c Makefile ++ `echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< ` ++ ++rijndael-ppc.lo: $(srcdir)/rijndael-ppc.c Makefile ++ `echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< ` ++ ++rijndael-ppc9le.o: $(srcdir)/rijndael-ppc9le.c Makefile ++ `echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< ` ++ ++rijndael-ppc9le.lo: $(srcdir)/rijndael-ppc9le.c Makefile ++ `echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< ` ++ ++ +diff -up libgcrypt-1.8.5/cipher/rfc2268.c.aes-perf libgcrypt-1.8.5/cipher/rfc2268.c +--- libgcrypt-1.8.5/cipher/rfc2268.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/rfc2268.c 2020-04-22 18:29:41.670862229 +0200 +@@ -262,8 +262,10 @@ setkey_core (void *context, const unsign + } + + static gpg_err_code_t +-do_setkey (void *context, const unsigned char *key, unsigned int keylen) ++do_setkey (void *context, const unsigned char *key, unsigned int keylen, ++ gcry_cipher_hd_t hd) + { ++ (void)hd; + return setkey_core (context, key, keylen, 1); + } + +diff -up libgcrypt-1.8.5/cipher/rijndael-aesni.c.aes-perf libgcrypt-1.8.5/cipher/rijndael-aesni.c +--- libgcrypt-1.8.5/cipher/rijndael-aesni.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/rijndael-aesni.c 2020-04-28 11:22:26.025519954 +0200 +@@ -327,8 +327,8 @@ _gcry_aes_aesni_do_setkey (RIJNDAEL_cont + + + /* Make a decryption key from an encryption key. */ +-void +-_gcry_aes_aesni_prepare_decryption (RIJNDAEL_context *ctx) ++static inline void ++do_aesni_prepare_decryption (RIJNDAEL_context *ctx) + { + /* The AES-NI decrypt instructions use the Equivalent Inverse + Cipher, thus we can't use the the standard decrypt key +@@ -338,8 +338,6 @@ _gcry_aes_aesni_prepare_decryption (RIJN + int rr; + int r; + +- aesni_prepare(); +- + #define DO_AESNI_AESIMC() \ + asm volatile ("movdqa %[ekey], %%xmm1\n\t" \ + /*"aesimc %%xmm1, %%xmm1\n\t"*/ \ +@@ -375,7 +373,13 @@ _gcry_aes_aesni_prepare_decryption (RIJN + dkey[r] = ekey[0]; + + #undef DO_AESNI_AESIMC ++} + ++void ++_gcry_aes_aesni_prepare_decryption (RIJNDAEL_context *ctx) ++{ ++ aesni_prepare(); ++ do_aesni_prepare_decryption (ctx); + aesni_cleanup(); + } + +@@ -1023,8 +1027,8 @@ _gcry_aes_aesni_encrypt (const RIJNDAEL_ + + + void +-_gcry_aes_aesni_cfb_enc (RIJNDAEL_context *ctx, unsigned char *outbuf, +- const unsigned char *inbuf, unsigned char *iv, ++_gcry_aes_aesni_cfb_enc (RIJNDAEL_context *ctx, unsigned char *iv, ++ unsigned char *outbuf, const unsigned char *inbuf, + size_t nblocks) + { + aesni_prepare (); +@@ -1059,8 +1063,8 @@ _gcry_aes_aesni_cfb_enc (RIJNDAEL_contex + + + void +-_gcry_aes_aesni_cbc_enc (RIJNDAEL_context *ctx, unsigned char *outbuf, +- const unsigned char *inbuf, unsigned char *iv, ++_gcry_aes_aesni_cbc_enc (RIJNDAEL_context *ctx, unsigned char *iv, ++ unsigned char *outbuf, const unsigned char *inbuf, + size_t nblocks, int cbc_mac) + { + aesni_prepare_2_6_variable; +@@ -1105,8 +1109,8 @@ _gcry_aes_aesni_cbc_enc (RIJNDAEL_contex + + + void +-_gcry_aes_aesni_ctr_enc (RIJNDAEL_context *ctx, unsigned char *outbuf, +- const unsigned char *inbuf, unsigned char *ctr, ++_gcry_aes_aesni_ctr_enc (RIJNDAEL_context *ctx, unsigned char *ctr, ++ unsigned char *outbuf, const unsigned char *inbuf, + size_t nblocks) + { + static const unsigned char be_mask[16] __attribute__ ((aligned (16))) = +@@ -1160,8 +1164,8 @@ _gcry_aes_aesni_decrypt (const RIJNDAEL_ + + + void +-_gcry_aes_aesni_cfb_dec (RIJNDAEL_context *ctx, unsigned char *outbuf, +- const unsigned char *inbuf, unsigned char *iv, ++_gcry_aes_aesni_cfb_dec (RIJNDAEL_context *ctx, unsigned char *iv, ++ unsigned char *outbuf, const unsigned char *inbuf, + size_t nblocks) + { + aesni_prepare_2_6_variable; +@@ -1245,15 +1249,21 @@ _gcry_aes_aesni_cfb_dec (RIJNDAEL_contex + + + void +-_gcry_aes_aesni_cbc_dec (RIJNDAEL_context *ctx, unsigned char *outbuf, +- const unsigned char *inbuf, unsigned char *iv, +- size_t nblocks) ++_gcry_aes_aesni_cbc_dec (RIJNDAEL_context *ctx, unsigned char *iv, ++ unsigned char *outbuf, const unsigned char *inbuf, ++ size_t nblocks) + { + aesni_prepare_2_6_variable; + + aesni_prepare (); + aesni_prepare_2_6(); + ++ if ( !ctx->decryption_prepared ) ++ { ++ do_aesni_prepare_decryption ( ctx ); ++ ctx->decryption_prepared = 1; ++ } ++ + asm volatile + ("movdqu %[iv], %%xmm5\n\t" /* use xmm5 as fast IV storage */ + : /* No output */ +@@ -1514,6 +1524,12 @@ aesni_ocb_dec (gcry_cipher_hd_t c, void + aesni_prepare (); + aesni_prepare_2_6 (); + ++ if ( !ctx->decryption_prepared ) ++ { ++ do_aesni_prepare_decryption ( ctx ); ++ ctx->decryption_prepared = 1; ++ } ++ + /* Preload Offset and Checksum */ + asm volatile ("movdqu %[iv], %%xmm5\n\t" + "movdqu %[ctr], %%xmm6\n\t" +@@ -1665,7 +1681,7 @@ aesni_ocb_dec (gcry_cipher_hd_t c, void + } + + +-void ++size_t + _gcry_aes_aesni_ocb_crypt(gcry_cipher_hd_t c, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks, int encrypt) + { +@@ -1673,10 +1689,12 @@ _gcry_aes_aesni_ocb_crypt(gcry_cipher_hd + aesni_ocb_enc(c, outbuf_arg, inbuf_arg, nblocks); + else + aesni_ocb_dec(c, outbuf_arg, inbuf_arg, nblocks); ++ ++ return 0; + } + + +-void ++size_t + _gcry_aes_aesni_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg, + size_t nblocks) + { +@@ -1810,7 +1828,306 @@ _gcry_aes_aesni_ocb_auth (gcry_cipher_hd + + aesni_cleanup (); + aesni_cleanup_2_6 (); ++ ++ return 0; + } + + ++static const u64 xts_gfmul_const[16] __attribute__ ((aligned (16))) = ++ { 0x87, 0x01 }; ++ ++ ++static void ++_gcry_aes_aesni_xts_enc (RIJNDAEL_context *ctx, unsigned char *tweak, ++ unsigned char *outbuf, const unsigned char *inbuf, ++ size_t nblocks) ++{ ++ aesni_prepare_2_6_variable; ++ ++ aesni_prepare (); ++ aesni_prepare_2_6 (); ++ ++ /* Preload Tweak */ ++ asm volatile ("movdqu %[tweak], %%xmm5\n\t" ++ "movdqa %[gfmul], %%xmm6\n\t" ++ : ++ : [tweak] "m" (*tweak), ++ [gfmul] "m" (*xts_gfmul_const) ++ : "memory" ); ++ ++ for ( ;nblocks >= 4; nblocks -= 4 ) ++ { ++ asm volatile ("pshufd $0x13, %%xmm5, %%xmm4\n\t" ++ "movdqu %[inbuf0], %%xmm1\n\t" ++ "pxor %%xmm5, %%xmm1\n\t" ++ "movdqu %%xmm5, %[outbuf0]\n\t" ++ ++ "movdqa %%xmm4, %%xmm0\n\t" ++ "paddd %%xmm4, %%xmm4\n\t" ++ "psrad $31, %%xmm0\n\t" ++ "paddq %%xmm5, %%xmm5\n\t" ++ "pand %%xmm6, %%xmm0\n\t" ++ "pxor %%xmm0, %%xmm5\n\t" ++ : [outbuf0] "=m" (*(outbuf + 0 * 16)) ++ : [inbuf0] "m" (*(inbuf + 0 * 16)) ++ : "memory" ); ++ ++ asm volatile ("movdqu %[inbuf1], %%xmm2\n\t" ++ "pxor %%xmm5, %%xmm2\n\t" ++ "movdqu %%xmm5, %[outbuf1]\n\t" ++ ++ "movdqa %%xmm4, %%xmm0\n\t" ++ "paddd %%xmm4, %%xmm4\n\t" ++ "psrad $31, %%xmm0\n\t" ++ "paddq %%xmm5, %%xmm5\n\t" ++ "pand %%xmm6, %%xmm0\n\t" ++ "pxor %%xmm0, %%xmm5\n\t" ++ : [outbuf1] "=m" (*(outbuf + 1 * 16)) ++ : [inbuf1] "m" (*(inbuf + 1 * 16)) ++ : "memory" ); ++ ++ asm volatile ("movdqu %[inbuf2], %%xmm3\n\t" ++ "pxor %%xmm5, %%xmm3\n\t" ++ "movdqu %%xmm5, %[outbuf2]\n\t" ++ ++ "movdqa %%xmm4, %%xmm0\n\t" ++ "paddd %%xmm4, %%xmm4\n\t" ++ "psrad $31, %%xmm0\n\t" ++ "paddq %%xmm5, %%xmm5\n\t" ++ "pand %%xmm6, %%xmm0\n\t" ++ "pxor %%xmm0, %%xmm5\n\t" ++ : [outbuf2] "=m" (*(outbuf + 2 * 16)) ++ : [inbuf2] "m" (*(inbuf + 2 * 16)) ++ : "memory" ); ++ ++ asm volatile ("movdqa %%xmm4, %%xmm0\n\t" ++ "movdqu %[inbuf3], %%xmm4\n\t" ++ "pxor %%xmm5, %%xmm4\n\t" ++ "movdqu %%xmm5, %[outbuf3]\n\t" ++ ++ "psrad $31, %%xmm0\n\t" ++ "paddq %%xmm5, %%xmm5\n\t" ++ "pand %%xmm6, %%xmm0\n\t" ++ "pxor %%xmm0, %%xmm5\n\t" ++ : [outbuf3] "=m" (*(outbuf + 3 * 16)) ++ : [inbuf3] "m" (*(inbuf + 3 * 16)) ++ : "memory" ); ++ ++ do_aesni_enc_vec4 (ctx); ++ ++ asm volatile ("movdqu %[outbuf0], %%xmm0\n\t" ++ "pxor %%xmm0, %%xmm1\n\t" ++ "movdqu %[outbuf1], %%xmm0\n\t" ++ "movdqu %%xmm1, %[outbuf0]\n\t" ++ "movdqu %[outbuf2], %%xmm1\n\t" ++ "pxor %%xmm0, %%xmm2\n\t" ++ "movdqu %[outbuf3], %%xmm0\n\t" ++ "pxor %%xmm1, %%xmm3\n\t" ++ "pxor %%xmm0, %%xmm4\n\t" ++ "movdqu %%xmm2, %[outbuf1]\n\t" ++ "movdqu %%xmm3, %[outbuf2]\n\t" ++ "movdqu %%xmm4, %[outbuf3]\n\t" ++ : [outbuf0] "+m" (*(outbuf + 0 * 16)), ++ [outbuf1] "+m" (*(outbuf + 1 * 16)), ++ [outbuf2] "+m" (*(outbuf + 2 * 16)), ++ [outbuf3] "+m" (*(outbuf + 3 * 16)) ++ : ++ : "memory" ); ++ ++ outbuf += BLOCKSIZE * 4; ++ inbuf += BLOCKSIZE * 4; ++ } ++ ++ for ( ;nblocks; nblocks-- ) ++ { ++ asm volatile ("movdqu %[inbuf], %%xmm0\n\t" ++ "pxor %%xmm5, %%xmm0\n\t" ++ "movdqa %%xmm5, %%xmm4\n\t" ++ ++ "pshufd $0x13, %%xmm5, %%xmm1\n\t" ++ "psrad $31, %%xmm1\n\t" ++ "paddq %%xmm5, %%xmm5\n\t" ++ "pand %%xmm6, %%xmm1\n\t" ++ "pxor %%xmm1, %%xmm5\n\t" ++ : ++ : [inbuf] "m" (*inbuf) ++ : "memory" ); ++ ++ do_aesni_enc (ctx); ++ ++ asm volatile ("pxor %%xmm4, %%xmm0\n\t" ++ "movdqu %%xmm0, %[outbuf]\n\t" ++ : [outbuf] "=m" (*outbuf) ++ : ++ : "memory" ); ++ ++ outbuf += BLOCKSIZE; ++ inbuf += BLOCKSIZE; ++ } ++ ++ asm volatile ("movdqu %%xmm5, %[tweak]\n\t" ++ : [tweak] "=m" (*tweak) ++ : ++ : "memory" ); ++ ++ aesni_cleanup (); ++ aesni_cleanup_2_6 (); ++} ++ ++ ++static void ++_gcry_aes_aesni_xts_dec (RIJNDAEL_context *ctx, unsigned char *tweak, ++ unsigned char *outbuf, const unsigned char *inbuf, ++ size_t nblocks) ++{ ++ aesni_prepare_2_6_variable; ++ ++ aesni_prepare (); ++ aesni_prepare_2_6 (); ++ ++ if ( !ctx->decryption_prepared ) ++ { ++ do_aesni_prepare_decryption ( ctx ); ++ ctx->decryption_prepared = 1; ++ } ++ ++ /* Preload Tweak */ ++ asm volatile ("movdqu %[tweak], %%xmm5\n\t" ++ "movdqa %[gfmul], %%xmm6\n\t" ++ : ++ : [tweak] "m" (*tweak), ++ [gfmul] "m" (*xts_gfmul_const) ++ : "memory" ); ++ ++ for ( ;nblocks >= 4; nblocks -= 4 ) ++ { ++ asm volatile ("pshufd $0x13, %%xmm5, %%xmm4\n\t" ++ "movdqu %[inbuf0], %%xmm1\n\t" ++ "pxor %%xmm5, %%xmm1\n\t" ++ "movdqu %%xmm5, %[outbuf0]\n\t" ++ ++ "movdqa %%xmm4, %%xmm0\n\t" ++ "paddd %%xmm4, %%xmm4\n\t" ++ "psrad $31, %%xmm0\n\t" ++ "paddq %%xmm5, %%xmm5\n\t" ++ "pand %%xmm6, %%xmm0\n\t" ++ "pxor %%xmm0, %%xmm5\n\t" ++ : [outbuf0] "=m" (*(outbuf + 0 * 16)) ++ : [inbuf0] "m" (*(inbuf + 0 * 16)) ++ : "memory" ); ++ ++ asm volatile ("movdqu %[inbuf1], %%xmm2\n\t" ++ "pxor %%xmm5, %%xmm2\n\t" ++ "movdqu %%xmm5, %[outbuf1]\n\t" ++ ++ "movdqa %%xmm4, %%xmm0\n\t" ++ "paddd %%xmm4, %%xmm4\n\t" ++ "psrad $31, %%xmm0\n\t" ++ "paddq %%xmm5, %%xmm5\n\t" ++ "pand %%xmm6, %%xmm0\n\t" ++ "pxor %%xmm0, %%xmm5\n\t" ++ : [outbuf1] "=m" (*(outbuf + 1 * 16)) ++ : [inbuf1] "m" (*(inbuf + 1 * 16)) ++ : "memory" ); ++ ++ asm volatile ("movdqu %[inbuf2], %%xmm3\n\t" ++ "pxor %%xmm5, %%xmm3\n\t" ++ "movdqu %%xmm5, %[outbuf2]\n\t" ++ ++ "movdqa %%xmm4, %%xmm0\n\t" ++ "paddd %%xmm4, %%xmm4\n\t" ++ "psrad $31, %%xmm0\n\t" ++ "paddq %%xmm5, %%xmm5\n\t" ++ "pand %%xmm6, %%xmm0\n\t" ++ "pxor %%xmm0, %%xmm5\n\t" ++ : [outbuf2] "=m" (*(outbuf + 2 * 16)) ++ : [inbuf2] "m" (*(inbuf + 2 * 16)) ++ : "memory" ); ++ ++ asm volatile ("movdqa %%xmm4, %%xmm0\n\t" ++ "movdqu %[inbuf3], %%xmm4\n\t" ++ "pxor %%xmm5, %%xmm4\n\t" ++ "movdqu %%xmm5, %[outbuf3]\n\t" ++ ++ "psrad $31, %%xmm0\n\t" ++ "paddq %%xmm5, %%xmm5\n\t" ++ "pand %%xmm6, %%xmm0\n\t" ++ "pxor %%xmm0, %%xmm5\n\t" ++ : [outbuf3] "=m" (*(outbuf + 3 * 16)) ++ : [inbuf3] "m" (*(inbuf + 3 * 16)) ++ : "memory" ); ++ ++ do_aesni_dec_vec4 (ctx); ++ ++ asm volatile ("movdqu %[outbuf0], %%xmm0\n\t" ++ "pxor %%xmm0, %%xmm1\n\t" ++ "movdqu %[outbuf1], %%xmm0\n\t" ++ "movdqu %%xmm1, %[outbuf0]\n\t" ++ "movdqu %[outbuf2], %%xmm1\n\t" ++ "pxor %%xmm0, %%xmm2\n\t" ++ "movdqu %[outbuf3], %%xmm0\n\t" ++ "pxor %%xmm1, %%xmm3\n\t" ++ "pxor %%xmm0, %%xmm4\n\t" ++ "movdqu %%xmm2, %[outbuf1]\n\t" ++ "movdqu %%xmm3, %[outbuf2]\n\t" ++ "movdqu %%xmm4, %[outbuf3]\n\t" ++ : [outbuf0] "+m" (*(outbuf + 0 * 16)), ++ [outbuf1] "+m" (*(outbuf + 1 * 16)), ++ [outbuf2] "+m" (*(outbuf + 2 * 16)), ++ [outbuf3] "+m" (*(outbuf + 3 * 16)) ++ : ++ : "memory" ); ++ ++ outbuf += BLOCKSIZE * 4; ++ inbuf += BLOCKSIZE * 4; ++ } ++ ++ for ( ;nblocks; nblocks-- ) ++ { ++ asm volatile ("movdqu %[inbuf], %%xmm0\n\t" ++ "pxor %%xmm5, %%xmm0\n\t" ++ "movdqa %%xmm5, %%xmm4\n\t" ++ ++ "pshufd $0x13, %%xmm5, %%xmm1\n\t" ++ "psrad $31, %%xmm1\n\t" ++ "paddq %%xmm5, %%xmm5\n\t" ++ "pand %%xmm6, %%xmm1\n\t" ++ "pxor %%xmm1, %%xmm5\n\t" ++ : ++ : [inbuf] "m" (*inbuf) ++ : "memory" ); ++ ++ do_aesni_dec (ctx); ++ ++ asm volatile ("pxor %%xmm4, %%xmm0\n\t" ++ "movdqu %%xmm0, %[outbuf]\n\t" ++ : [outbuf] "=m" (*outbuf) ++ : ++ : "memory" ); ++ ++ outbuf += BLOCKSIZE; ++ inbuf += BLOCKSIZE; ++ } ++ ++ asm volatile ("movdqu %%xmm5, %[tweak]\n\t" ++ : [tweak] "=m" (*tweak) ++ : ++ : "memory" ); ++ ++ aesni_cleanup (); ++ aesni_cleanup_2_6 (); ++} ++ ++ ++void ++_gcry_aes_aesni_xts_crypt (RIJNDAEL_context *ctx, unsigned char *tweak, ++ unsigned char *outbuf, const unsigned char *inbuf, ++ size_t nblocks, int encrypt) ++{ ++ if (encrypt) ++ _gcry_aes_aesni_xts_enc(ctx, tweak, outbuf, inbuf, nblocks); ++ else ++ _gcry_aes_aesni_xts_dec(ctx, tweak, outbuf, inbuf, nblocks); ++} ++ + #endif /* USE_AESNI */ +diff -up libgcrypt-1.8.5/cipher/rijndael-armv8-aarch32-ce.S.aes-perf libgcrypt-1.8.5/cipher/rijndael-armv8-aarch32-ce.S +--- libgcrypt-1.8.5/cipher/rijndael-armv8-aarch32-ce.S.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/rijndael-armv8-aarch32-ce.S 2020-04-22 18:29:41.673862172 +0200 +@@ -1517,6 +1517,317 @@ _gcry_aes_ocb_auth_armv8_ce: + .size _gcry_aes_ocb_auth_armv8_ce,.-_gcry_aes_ocb_auth_armv8_ce; + + ++ ++/* ++ * void _gcry_aes_xts_enc_armv8_ce (const void *keysched, ++ * unsigned char *outbuf, ++ * const unsigned char *inbuf, ++ * unsigned char *iv, unsigned int nrounds); ++ */ ++ ++.align 3 ++.globl _gcry_aes_xts_enc_armv8_ce ++.type _gcry_aes_xts_enc_armv8_ce,%function; ++_gcry_aes_xts_enc_armv8_ce: ++ /* input: ++ * r0: keysched ++ * r1: outbuf ++ * r2: inbuf ++ * r3: iv ++ * %st+0: nblocks => r4 ++ * %st+4: nrounds => r5 ++ */ ++ ++ vpush {q4-q7} ++ push {r4-r12,lr} /* 4*16 + 4*10 = 104b */ ++ ldr r4, [sp, #(104+0)] ++ ldr r5, [sp, #(104+4)] ++ cmp r4, #0 ++ beq .Lxts_enc_skip ++ ++ cmp r5, #12 ++ ++ vld1.8 {q0}, [r3] /* load tweak */ ++ mov r7, #0x87; ++ ++ aes_preload_keys(r0, r6); ++ ++ beq .Lxts_enc_entry_192 ++ bhi .Lxts_enc_entry_256 ++ ++#define CTR_XTS(bits, ...) \ ++ .Lxts_enc_entry_##bits: \ ++ cmp r4, #4; \ ++ blo .Lxts_enc_loop_##bits; \ ++ \ ++ .Lxts_enc_loop4_##bits: \ ++ sub r4, r4, #4; \ ++ veor q9, q9, q9; \ ++ \ ++ vld1.8 {q1-q2}, [r2]!; /* load plaintext */ \ ++ veor q1, q1, q0; \ ++ cmp r4, #4; \ ++ vmov.u32 d18[0], r7; \ ++ vst1.8 {q0}, [r1]!; /* store tweak0 to temp */ \ ++ \ ++ vshr.s64 d16, d1, #63; \ ++ vshr.u64 d17, d0, #63; \ ++ vadd.u64 q0, q0, q0; \ ++ vand d16, d16, d18; \ ++ veor q0, q0, q8; \ ++ \ ++ vld1.8 {q3-q4}, [r2]!; /* load plaintext */ \ ++ veor q2, q2, q0; \ ++ vst1.8 {q0}, [r1]!; /* store tweak1 to temp */ \ ++ \ ++ vshr.s64 d16, d1, #63; \ ++ vshr.u64 d17, d0, #63; \ ++ vadd.u64 q0, q0, q0; \ ++ vand d16, d16, d18; \ ++ veor q0, q0, q8; \ ++ \ ++ veor q3, q3, q0; \ ++ vst1.8 {q0}, [r1]!; /* store tweak2 to temp */ \ ++ \ ++ vshr.s64 d16, d1, #63; \ ++ vshr.u64 d17, d0, #63; \ ++ vadd.u64 q0, q0, q0; \ ++ vand d16, d16, d18; \ ++ veor q0, q0, q8; \ ++ \ ++ veor q4, q4, q0; \ ++ vst1.8 {q0}, [r1]; /* store tweak3 to temp */ \ ++ sub r1, r1, #48; \ ++ \ ++ vshr.s64 d16, d1, #63; \ ++ vshr.u64 d17, d0, #63; \ ++ vadd.u64 q0, q0, q0; \ ++ vand d16, d16, d18; \ ++ veor q0, q0, q8; \ ++ \ ++ do_aes_4_##bits(e, mc, q1, q2, q3, q4, ##__VA_ARGS__); \ ++ \ ++ vld1.8 {q8-q9}, [r1]!; /* load tweak from temp */ \ ++ veor q1, q1, q8; \ ++ veor q2, q2, q9; \ ++ vld1.8 {q8-q9}, [r1]; /* load tweak from temp */ \ ++ sub r1, r1, #32; \ ++ veor q3, q3, q8; \ ++ veor q4, q4, q9; \ ++ vst1.8 {q1-q2}, [r1]!; /* store plaintext */ \ ++ vst1.8 {q3-q4}, [r1]!; /* store plaintext */ \ ++ \ ++ bhs .Lxts_enc_loop4_##bits; \ ++ cmp r4, #0; \ ++ beq .Lxts_enc_done; \ ++ \ ++ .Lxts_enc_loop_##bits: \ ++ \ ++ vld1.8 {q1}, [r2]!; /* load ciphertext */ \ ++ \ ++ veor q9, q9, q9; \ ++ veor q1, q1, q0; \ ++ vmov.u32 d18[0], r7; \ ++ vmov q2, q0; \ ++ \ ++ vshr.s64 d16, d1, #63; \ ++ vshr.u64 d17, d0, #63; \ ++ vadd.u64 q0, q0, q0; \ ++ vand d16, d16, d18; \ ++ veor q0, q0, q8; \ ++ subs r4, r4, #1; \ ++ \ ++ do_aes_one##bits(e, mc, q1, q1, ##__VA_ARGS__); \ ++ \ ++ veor q1, q1, q2; \ ++ vst1.8 {q1}, [r1]!; /* store plaintext */ \ ++ \ ++ bne .Lxts_enc_loop_##bits; \ ++ b .Lxts_enc_done; ++ ++ CTR_XTS(128re, r0, r6) ++ CTR_XTS(192, r0, r6) ++ CTR_XTS(256, r0, r6) ++ ++#undef CTR_XTS ++ ++.Lxts_enc_done: ++ vst1.8 {q0}, [r3] /* store tweak */ ++ ++ CLEAR_REG(q0) ++ CLEAR_REG(q1) ++ CLEAR_REG(q2) ++ CLEAR_REG(q3) ++ CLEAR_REG(q8) ++ CLEAR_REG(q9) ++ CLEAR_REG(q10) ++ CLEAR_REG(q11) ++ CLEAR_REG(q12) ++ CLEAR_REG(q13) ++ CLEAR_REG(q14) ++ ++.Lxts_enc_skip: ++ pop {r4-r12,lr} ++ vpop {q4-q7} ++ bx lr ++.size _gcry_aes_xts_enc_armv8_ce,.-_gcry_aes_xts_enc_armv8_ce; ++ ++ ++/* ++ * void _gcry_aes_xts_dec_armv8_ce (const void *keysched, ++ * unsigned char *outbuf, ++ * const unsigned char *inbuf, ++ * unsigned char *iv, unsigned int nrounds); ++ */ ++ ++.align 3 ++.globl _gcry_aes_xts_dec_armv8_ce ++.type _gcry_aes_xts_dec_armv8_ce,%function; ++_gcry_aes_xts_dec_armv8_ce: ++ /* input: ++ * r0: keysched ++ * r1: outbuf ++ * r2: inbuf ++ * r3: iv ++ * %st+0: nblocks => r4 ++ * %st+4: nrounds => r5 ++ */ ++ ++ vpush {q4-q7} ++ push {r4-r12,lr} /* 4*16 + 4*10 = 104b */ ++ ldr r4, [sp, #(104+0)] ++ ldr r5, [sp, #(104+4)] ++ cmp r4, #0 ++ beq .Lxts_dec_skip ++ ++ cmp r5, #12 ++ ++ vld1.8 {q0}, [r3] /* load tweak */ ++ mov r7, #0x87; ++ ++ aes_preload_keys(r0, r6); ++ ++ beq .Lxts_dec_entry_192 ++ bhi .Lxts_dec_entry_256 ++ ++#define CTR_XTS(bits, ...) \ ++ .Lxts_dec_entry_##bits: \ ++ cmp r4, #4; \ ++ blo .Lxts_dec_loop_##bits; \ ++ \ ++ .Lxts_dec_loop4_##bits: \ ++ sub r4, r4, #4; \ ++ veor q9, q9, q9; \ ++ \ ++ vld1.8 {q1-q2}, [r2]!; /* load plaintext */ \ ++ veor q1, q1, q0; \ ++ cmp r4, #4; \ ++ vmov.u32 d18[0], r7; \ ++ vst1.8 {q0}, [r1]!; /* store tweak0 to temp */ \ ++ \ ++ vshr.s64 d16, d1, #63; \ ++ vshr.u64 d17, d0, #63; \ ++ vadd.u64 q0, q0, q0; \ ++ vand d16, d16, d18; \ ++ veor q0, q0, q8; \ ++ \ ++ vld1.8 {q3-q4}, [r2]!; /* load plaintext */ \ ++ veor q2, q2, q0; \ ++ vst1.8 {q0}, [r1]!; /* store tweak1 to temp */ \ ++ \ ++ vshr.s64 d16, d1, #63; \ ++ vshr.u64 d17, d0, #63; \ ++ vadd.u64 q0, q0, q0; \ ++ vand d16, d16, d18; \ ++ veor q0, q0, q8; \ ++ \ ++ veor q3, q3, q0; \ ++ vst1.8 {q0}, [r1]!; /* store tweak2 to temp */ \ ++ \ ++ vshr.s64 d16, d1, #63; \ ++ vshr.u64 d17, d0, #63; \ ++ vadd.u64 q0, q0, q0; \ ++ vand d16, d16, d18; \ ++ veor q0, q0, q8; \ ++ \ ++ veor q4, q4, q0; \ ++ vst1.8 {q0}, [r1]; /* store tweak3 to temp */ \ ++ sub r1, r1, #48; \ ++ \ ++ vshr.s64 d16, d1, #63; \ ++ vshr.u64 d17, d0, #63; \ ++ vadd.u64 q0, q0, q0; \ ++ vand d16, d16, d18; \ ++ veor q0, q0, q8; \ ++ \ ++ do_aes_4_##bits(d, imc, q1, q2, q3, q4, ##__VA_ARGS__); \ ++ \ ++ vld1.8 {q8-q9}, [r1]!; /* load tweak from temp */ \ ++ veor q1, q1, q8; \ ++ veor q2, q2, q9; \ ++ vld1.8 {q8-q9}, [r1]; /* load tweak from temp */ \ ++ sub r1, r1, #32; \ ++ veor q3, q3, q8; \ ++ veor q4, q4, q9; \ ++ vst1.8 {q1-q2}, [r1]!; /* store plaintext */ \ ++ vst1.8 {q3-q4}, [r1]!; /* store plaintext */ \ ++ \ ++ bhs .Lxts_dec_loop4_##bits; \ ++ cmp r4, #0; \ ++ beq .Lxts_dec_done; \ ++ \ ++ .Lxts_dec_loop_##bits: \ ++ \ ++ vld1.8 {q1}, [r2]!; /* load ciphertext */ \ ++ \ ++ veor q9, q9, q9; \ ++ veor q1, q1, q0; \ ++ vmov.u32 d18[0], r7; \ ++ vmov q2, q0; \ ++ \ ++ vshr.s64 d16, d1, #63; \ ++ vshr.u64 d17, d0, #63; \ ++ vadd.u64 q0, q0, q0; \ ++ vand d16, d16, d18; \ ++ veor q0, q0, q8; \ ++ subs r4, r4, #1; \ ++ \ ++ do_aes_one##bits(d, imc, q1, q1, ##__VA_ARGS__); \ ++ \ ++ veor q1, q1, q2; \ ++ vst1.8 {q1}, [r1]!; /* store plaintext */ \ ++ \ ++ bne .Lxts_dec_loop_##bits; \ ++ b .Lxts_dec_done; ++ ++ CTR_XTS(128re, r0, r6) ++ CTR_XTS(192, r0, r6) ++ CTR_XTS(256, r0, r6) ++ ++#undef CTR_XTS ++ ++.Lxts_dec_done: ++ vst1.8 {q0}, [r3] /* store tweak */ ++ ++ CLEAR_REG(q0) ++ CLEAR_REG(q1) ++ CLEAR_REG(q2) ++ CLEAR_REG(q3) ++ CLEAR_REG(q8) ++ CLEAR_REG(q9) ++ CLEAR_REG(q10) ++ CLEAR_REG(q11) ++ CLEAR_REG(q12) ++ CLEAR_REG(q13) ++ CLEAR_REG(q14) ++ ++.Lxts_dec_skip: ++ pop {r4-r12,lr} ++ vpop {q4-q7} ++ bx lr ++.size _gcry_aes_xts_dec_armv8_ce,.-_gcry_aes_xts_dec_armv8_ce; ++ ++ + /* + * u32 _gcry_aes_sbox4_armv8_ce(u32 in4b); + */ +diff -up libgcrypt-1.8.5/cipher/rijndael-armv8-aarch64-ce.S.aes-perf libgcrypt-1.8.5/cipher/rijndael-armv8-aarch64-ce.S +--- libgcrypt-1.8.5/cipher/rijndael-armv8-aarch64-ce.S.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/rijndael-armv8-aarch64-ce.S 2020-04-22 18:29:41.674862153 +0200 +@@ -1157,8 +1157,8 @@ _gcry_aes_ocb_auth_armv8_ce: + * w6: nrounds => w7 + * w7: blkn => w12 + */ +- mov x12, x7 +- mov x7, x6 ++ mov w12, w7 ++ mov w7, w6 + mov x6, x5 + mov x5, x4 + mov x4, x3 +@@ -1277,6 +1277,284 @@ _gcry_aes_ocb_auth_armv8_ce: + + + /* ++ * void _gcry_aes_xts_enc_armv8_ce (const void *keysched, ++ * unsigned char *outbuf, ++ * const unsigned char *inbuf, ++ * unsigned char *tweak, ++ * size_t nblocks, ++ * unsigned int nrounds); ++ */ ++ ++.align 3 ++.globl _gcry_aes_xts_enc_armv8_ce ++.type _gcry_aes_xts_enc_armv8_ce,%function; ++_gcry_aes_xts_enc_armv8_ce: ++ /* input: ++ * r0: keysched ++ * r1: outbuf ++ * r2: inbuf ++ * r3: tweak ++ * x4: nblocks ++ * w5: nrounds ++ */ ++ ++ cbz x4, .Lxts_enc_skip ++ ++ /* load tweak */ ++ ld1 {v0.16b}, [x3] ++ ++ /* load gfmul mask */ ++ mov x6, #0x87 ++ mov x7, #0x01 ++ mov v16.D[0], x6 ++ mov v16.D[1], x7 ++ ++ aes_preload_keys(x0, w5); ++ ++ b.eq .Lxts_enc_entry_192 ++ b.hi .Lxts_enc_entry_256 ++ ++#define XTS_ENC(bits) \ ++ .Lxts_enc_entry_##bits: \ ++ cmp x4, #4; \ ++ b.lo .Lxts_enc_loop_##bits; \ ++ \ ++ .Lxts_enc_loop4_##bits: \ ++ \ ++ ext v4.16b, v0.16b, v0.16b, #8; \ ++ \ ++ sshr v2.2d, v4.2d, #63; \ ++ add v5.2d, v0.2d, v0.2d; \ ++ and v2.16b, v2.16b, v16.16b; \ ++ add v4.2d, v4.2d, v4.2d; \ ++ eor v5.16b, v5.16b, v2.16b; \ ++ \ ++ sshr v2.2d, v4.2d, #63; \ ++ add v6.2d, v5.2d, v5.2d; \ ++ and v2.16b, v2.16b, v16.16b; \ ++ add v4.2d, v4.2d, v4.2d; \ ++ eor v6.16b, v6.16b, v2.16b; \ ++ \ ++ sshr v2.2d, v4.2d, #63; \ ++ add v7.2d, v6.2d, v6.2d; \ ++ and v2.16b, v2.16b, v16.16b; \ ++ add v4.2d, v4.2d, v4.2d; \ ++ eor v7.16b, v7.16b, v2.16b; \ ++ \ ++ sshr v2.2d, v4.2d, #63; \ ++ add v3.2d, v7.2d, v7.2d; \ ++ and v2.16b, v2.16b, v16.16b; \ ++ add v4.2d, v4.2d, v4.2d; \ ++ eor v3.16b, v3.16b, v2.16b; \ ++ ld1 {v1.16b-v2.16b}, [x2], #32; /* load plaintext */ \ ++ st1 {v3.16b}, [x3]; \ ++ sub x4, x4, #4; \ ++ eor v1.16b, v1.16b, v0.16b; \ ++ \ ++ ld1 {v3.16b-v4.16b}, [x2], #32; /* load plaintext */ \ ++ cmp x4, #4; \ ++ eor v2.16b, v2.16b, v5.16b; \ ++ eor v3.16b, v3.16b, v6.16b; \ ++ eor v4.16b, v4.16b, v7.16b; \ ++ \ ++ do_aes_4_##bits(e, mc, v1, v2, v3, v4); \ ++ \ ++ eor v1.16b, v1.16b, v0.16b; \ ++ ld1 {v0.16b}, [x3]; \ ++ eor v2.16b, v2.16b, v5.16b; \ ++ eor v3.16b, v3.16b, v6.16b; \ ++ eor v4.16b, v4.16b, v7.16b; \ ++ st1 {v1.16b-v4.16b}, [x1], #64; /* store plaintext */ \ ++ \ ++ b.hs .Lxts_enc_loop4_##bits; \ ++ CLEAR_REG(v3); \ ++ CLEAR_REG(v4); \ ++ CLEAR_REG(v5); \ ++ CLEAR_REG(v6); \ ++ CLEAR_REG(v7); \ ++ cbz x4, .Lxts_enc_done; \ ++ \ ++ .Lxts_enc_loop_##bits: \ ++ \ ++ ld1 {v1.16b}, [x2], #16; /* load plaintext */ \ ++ ext v3.16b, v0.16b, v0.16b, #8; \ ++ mov v2.16b, v0.16b; \ ++ sshr v3.2d, v3.2d, #63; \ ++ add v0.2d, v0.2d, v0.2d; \ ++ and v3.16b, v3.16b, v16.16b; \ ++ eor v1.16b, v1.16b, v2.16b; \ ++ eor v0.16b, v0.16b, v3.16b; \ ++ sub x4, x4, #1; \ ++ \ ++ do_aes_one##bits(e, mc, v1, v1); \ ++ \ ++ eor v1.16b, v1.16b, v2.16b; \ ++ st1 {v1.16b}, [x1], #16; /* store ciphertext */ \ ++ \ ++ cbnz x4, .Lxts_enc_loop_##bits; \ ++ b .Lxts_enc_done; ++ ++ XTS_ENC(128) ++ XTS_ENC(192) ++ XTS_ENC(256) ++ ++#undef XTS_ENC ++ ++.Lxts_enc_done: ++ aes_clear_keys(w5) ++ ++ st1 {v0.16b}, [x3] /* store tweak */ ++ ++ CLEAR_REG(v0) ++ CLEAR_REG(v1) ++ CLEAR_REG(v2) ++ ++.Lxts_enc_skip: ++ ret ++ ++.size _gcry_aes_xts_enc_armv8_ce,.-_gcry_aes_xts_enc_armv8_ce; ++ ++ ++/* ++ * void _gcry_aes_xts_dec_armv8_ce (const void *keysched, ++ * unsigned char *outbuf, ++ * const unsigned char *inbuf, ++ * unsigned char *tweak, ++ * size_t nblocks, ++ * unsigned int nrounds); ++ */ ++ ++.align 3 ++.globl _gcry_aes_xts_dec_armv8_ce ++.type _gcry_aes_xts_dec_armv8_ce,%function; ++_gcry_aes_xts_dec_armv8_ce: ++ /* input: ++ * r0: keysched ++ * r1: outbuf ++ * r2: inbuf ++ * r3: tweak ++ * x4: nblocks ++ * w5: nrounds ++ */ ++ ++ cbz x4, .Lxts_dec_skip ++ ++ /* load tweak */ ++ ld1 {v0.16b}, [x3] ++ ++ /* load gfmul mask */ ++ mov x6, #0x87 ++ mov x7, #0x01 ++ mov v16.D[0], x6 ++ mov v16.D[1], x7 ++ ++ aes_preload_keys(x0, w5); ++ ++ b.eq .Lxts_dec_entry_192 ++ b.hi .Lxts_dec_entry_256 ++ ++#define XTS_DEC(bits) \ ++ .Lxts_dec_entry_##bits: \ ++ cmp x4, #4; \ ++ b.lo .Lxts_dec_loop_##bits; \ ++ \ ++ .Lxts_dec_loop4_##bits: \ ++ \ ++ ext v4.16b, v0.16b, v0.16b, #8; \ ++ \ ++ sshr v2.2d, v4.2d, #63; \ ++ add v5.2d, v0.2d, v0.2d; \ ++ and v2.16b, v2.16b, v16.16b; \ ++ add v4.2d, v4.2d, v4.2d; \ ++ eor v5.16b, v5.16b, v2.16b; \ ++ \ ++ sshr v2.2d, v4.2d, #63; \ ++ add v6.2d, v5.2d, v5.2d; \ ++ and v2.16b, v2.16b, v16.16b; \ ++ add v4.2d, v4.2d, v4.2d; \ ++ eor v6.16b, v6.16b, v2.16b; \ ++ \ ++ sshr v2.2d, v4.2d, #63; \ ++ add v7.2d, v6.2d, v6.2d; \ ++ and v2.16b, v2.16b, v16.16b; \ ++ add v4.2d, v4.2d, v4.2d; \ ++ eor v7.16b, v7.16b, v2.16b; \ ++ \ ++ sshr v2.2d, v4.2d, #63; \ ++ add v3.2d, v7.2d, v7.2d; \ ++ and v2.16b, v2.16b, v16.16b; \ ++ add v4.2d, v4.2d, v4.2d; \ ++ eor v3.16b, v3.16b, v2.16b; \ ++ ld1 {v1.16b-v2.16b}, [x2], #32; /* load plaintext */ \ ++ st1 {v3.16b}, [x3]; \ ++ sub x4, x4, #4; \ ++ eor v1.16b, v1.16b, v0.16b; \ ++ \ ++ ld1 {v3.16b-v4.16b}, [x2], #32; /* load plaintext */ \ ++ cmp x4, #4; \ ++ eor v2.16b, v2.16b, v5.16b; \ ++ eor v3.16b, v3.16b, v6.16b; \ ++ eor v4.16b, v4.16b, v7.16b; \ ++ \ ++ do_aes_4_##bits(d, imc, v1, v2, v3, v4); \ ++ \ ++ eor v1.16b, v1.16b, v0.16b; \ ++ ld1 {v0.16b}, [x3]; \ ++ eor v2.16b, v2.16b, v5.16b; \ ++ eor v3.16b, v3.16b, v6.16b; \ ++ eor v4.16b, v4.16b, v7.16b; \ ++ st1 {v1.16b-v4.16b}, [x1], #64; /* store plaintext */ \ ++ \ ++ b.hs .Lxts_dec_loop4_##bits; \ ++ CLEAR_REG(v3); \ ++ CLEAR_REG(v4); \ ++ CLEAR_REG(v5); \ ++ CLEAR_REG(v6); \ ++ CLEAR_REG(v7); \ ++ cbz x4, .Lxts_dec_done; \ ++ \ ++ .Lxts_dec_loop_##bits: \ ++ \ ++ ld1 {v1.16b}, [x2], #16; /* load plaintext */ \ ++ ext v3.16b, v0.16b, v0.16b, #8; \ ++ mov v2.16b, v0.16b; \ ++ sshr v3.2d, v3.2d, #63; \ ++ add v0.2d, v0.2d, v0.2d; \ ++ and v3.16b, v3.16b, v16.16b; \ ++ eor v1.16b, v1.16b, v2.16b; \ ++ eor v0.16b, v0.16b, v3.16b; \ ++ sub x4, x4, #1; \ ++ \ ++ do_aes_one##bits(d, imc, v1, v1); \ ++ \ ++ eor v1.16b, v1.16b, v2.16b; \ ++ st1 {v1.16b}, [x1], #16; /* store ciphertext */ \ ++ \ ++ cbnz x4, .Lxts_dec_loop_##bits; \ ++ b .Lxts_dec_done; ++ ++ XTS_DEC(128) ++ XTS_DEC(192) ++ XTS_DEC(256) ++ ++#undef XTS_DEC ++ ++.Lxts_dec_done: ++ aes_clear_keys(w5) ++ ++ st1 {v0.16b}, [x3] /* store tweak */ ++ ++ CLEAR_REG(v0) ++ CLEAR_REG(v1) ++ CLEAR_REG(v2) ++ ++.Lxts_dec_skip: ++ ret ++ ++.size _gcry_aes_xts_dec_armv8_ce,.-_gcry_aes_xts_dec_armv8_ce; ++ ++ ++/* + * u32 _gcry_aes_sbox4_armv8_ce(u32 in4b); + */ + .align 3 +diff -up libgcrypt-1.8.5/cipher/rijndael-armv8-ce.c.aes-perf libgcrypt-1.8.5/cipher/rijndael-armv8-ce.c +--- libgcrypt-1.8.5/cipher/rijndael-armv8-ce.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/rijndael-armv8-ce.c 2020-04-22 18:29:41.675862134 +0200 +@@ -101,6 +101,16 @@ extern void _gcry_aes_ocb_auth_armv8_ce + size_t nblocks, + unsigned int nrounds, + unsigned int blkn); ++extern void _gcry_aes_xts_enc_armv8_ce (const void *keysched, ++ unsigned char *outbuf, ++ const unsigned char *inbuf, ++ unsigned char *tweak, ++ size_t nblocks, unsigned int nrounds); ++extern void _gcry_aes_xts_dec_armv8_ce (const void *keysched, ++ unsigned char *outbuf, ++ const unsigned char *inbuf, ++ unsigned char *tweak, ++ size_t nblocks, unsigned int nrounds); + + typedef void (*ocb_crypt_fn_t) (const void *keysched, unsigned char *outbuf, + const unsigned char *inbuf, +@@ -108,6 +118,11 @@ typedef void (*ocb_crypt_fn_t) (const vo + unsigned char *L_table, size_t nblocks, + unsigned int nrounds, unsigned int blkn); + ++typedef void (*xts_crypt_fn_t) (const void *keysched, unsigned char *outbuf, ++ const unsigned char *inbuf, ++ unsigned char *tweak, size_t nblocks, ++ unsigned int nrounds); ++ + void + _gcry_aes_armv8_ce_setkey (RIJNDAEL_context *ctx, const byte *key) + { +@@ -269,8 +284,8 @@ _gcry_aes_armv8_ce_decrypt (const RIJNDA + } + + void +-_gcry_aes_armv8_ce_cbc_enc (const RIJNDAEL_context *ctx, unsigned char *outbuf, +- const unsigned char *inbuf, unsigned char *iv, ++_gcry_aes_armv8_ce_cbc_enc (const RIJNDAEL_context *ctx, unsigned char *iv, ++ unsigned char *outbuf, const unsigned char *inbuf, + size_t nblocks, int cbc_mac) + { + const void *keysched = ctx->keyschenc32; +@@ -281,19 +296,25 @@ _gcry_aes_armv8_ce_cbc_enc (const RIJNDA + } + + void +-_gcry_aes_armv8_ce_cbc_dec (RIJNDAEL_context *ctx, unsigned char *outbuf, +- const unsigned char *inbuf, unsigned char *iv, ++_gcry_aes_armv8_ce_cbc_dec (RIJNDAEL_context *ctx, unsigned char *iv, ++ unsigned char *outbuf, const unsigned char *inbuf, + size_t nblocks) + { + const void *keysched = ctx->keyschdec32; + unsigned int nrounds = ctx->rounds; + ++ if ( !ctx->decryption_prepared ) ++ { ++ _gcry_aes_armv8_ce_prepare_decryption ( ctx ); ++ ctx->decryption_prepared = 1; ++ } ++ + _gcry_aes_cbc_dec_armv8_ce(keysched, outbuf, inbuf, iv, nblocks, nrounds); + } + + void +-_gcry_aes_armv8_ce_cfb_enc (RIJNDAEL_context *ctx, unsigned char *outbuf, +- const unsigned char *inbuf, unsigned char *iv, ++_gcry_aes_armv8_ce_cfb_enc (RIJNDAEL_context *ctx, unsigned char *iv, ++ unsigned char *outbuf, const unsigned char *inbuf, + size_t nblocks) + { + const void *keysched = ctx->keyschenc32; +@@ -303,8 +324,8 @@ _gcry_aes_armv8_ce_cfb_enc (RIJNDAEL_con + } + + void +-_gcry_aes_armv8_ce_cfb_dec (RIJNDAEL_context *ctx, unsigned char *outbuf, +- const unsigned char *inbuf, unsigned char *iv, ++_gcry_aes_armv8_ce_cfb_dec (RIJNDAEL_context *ctx, unsigned char *iv, ++ unsigned char *outbuf, const unsigned char *inbuf, + size_t nblocks) + { + const void *keysched = ctx->keyschenc32; +@@ -314,8 +335,8 @@ _gcry_aes_armv8_ce_cfb_dec (RIJNDAEL_con + } + + void +-_gcry_aes_armv8_ce_ctr_enc (RIJNDAEL_context *ctx, unsigned char *outbuf, +- const unsigned char *inbuf, unsigned char *iv, ++_gcry_aes_armv8_ce_ctr_enc (RIJNDAEL_context *ctx, unsigned char *iv, ++ unsigned char *outbuf, const unsigned char *inbuf, + size_t nblocks) + { + const void *keysched = ctx->keyschenc32; +@@ -324,7 +345,7 @@ _gcry_aes_armv8_ce_ctr_enc (RIJNDAEL_con + _gcry_aes_ctr_enc_armv8_ce(keysched, outbuf, inbuf, iv, nblocks, nrounds); + } + +-void ++size_t + _gcry_aes_armv8_ce_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks, + int encrypt) +@@ -338,13 +359,21 @@ _gcry_aes_armv8_ce_ocb_crypt (gcry_ciphe + unsigned int nrounds = ctx->rounds; + u64 blkn = c->u_mode.ocb.data_nblocks; + ++ if ( !encrypt && !ctx->decryption_prepared ) ++ { ++ _gcry_aes_armv8_ce_prepare_decryption ( ctx ); ++ ctx->decryption_prepared = 1; ++ } ++ + c->u_mode.ocb.data_nblocks = blkn + nblocks; + + crypt_fn(keysched, outbuf, inbuf, c->u_iv.iv, c->u_ctr.ctr, + c->u_mode.ocb.L[0], nblocks, nrounds, (unsigned int)blkn); ++ ++ return 0; + } + +-void ++size_t + _gcry_aes_armv8_ce_ocb_auth (gcry_cipher_hd_t c, void *abuf_arg, + size_t nblocks) + { +@@ -359,6 +388,27 @@ _gcry_aes_armv8_ce_ocb_auth (gcry_cipher + _gcry_aes_ocb_auth_armv8_ce(keysched, abuf, c->u_mode.ocb.aad_offset, + c->u_mode.ocb.aad_sum, c->u_mode.ocb.L[0], + nblocks, nrounds, (unsigned int)blkn); ++ ++ return 0; ++} ++ ++void ++_gcry_aes_armv8_ce_xts_crypt (RIJNDAEL_context *ctx, unsigned char *tweak, ++ unsigned char *outbuf, const unsigned char *inbuf, ++ size_t nblocks, int encrypt) ++{ ++ const void *keysched = encrypt ? ctx->keyschenc32 : ctx->keyschdec32; ++ xts_crypt_fn_t crypt_fn = encrypt ? _gcry_aes_xts_enc_armv8_ce ++ : _gcry_aes_xts_dec_armv8_ce; ++ unsigned int nrounds = ctx->rounds; ++ ++ if ( !encrypt && !ctx->decryption_prepared ) ++ { ++ _gcry_aes_armv8_ce_prepare_decryption ( ctx ); ++ ctx->decryption_prepared = 1; ++ } ++ ++ crypt_fn(keysched, outbuf, inbuf, tweak, nblocks, nrounds); + } + + #endif /* USE_ARM_CE */ +diff -up libgcrypt-1.8.5/cipher/rijndael.c.aes-perf libgcrypt-1.8.5/cipher/rijndael.c +--- libgcrypt-1.8.5/cipher/rijndael.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/rijndael.c 2020-04-22 18:29:41.676862114 +0200 +@@ -77,32 +77,29 @@ extern unsigned int _gcry_aes_aesni_encr + extern unsigned int _gcry_aes_aesni_decrypt (const RIJNDAEL_context *ctx, + unsigned char *dst, + const unsigned char *src); +-extern void _gcry_aes_aesni_cfb_enc (RIJNDAEL_context *ctx, +- unsigned char *outbuf, +- const unsigned char *inbuf, +- unsigned char *iv, size_t nblocks); +-extern void _gcry_aes_aesni_cbc_enc (RIJNDAEL_context *ctx, +- unsigned char *outbuf, +- const unsigned char *inbuf, +- unsigned char *iv, size_t nblocks, +- int cbc_mac); +-extern void _gcry_aes_aesni_ctr_enc (RIJNDAEL_context *ctx, +- unsigned char *outbuf, +- const unsigned char *inbuf, +- unsigned char *ctr, size_t nblocks); +-extern void _gcry_aes_aesni_cfb_dec (RIJNDAEL_context *ctx, +- unsigned char *outbuf, +- const unsigned char *inbuf, +- unsigned char *iv, size_t nblocks); +-extern void _gcry_aes_aesni_cbc_dec (RIJNDAEL_context *ctx, +- unsigned char *outbuf, +- const unsigned char *inbuf, +- unsigned char *iv, size_t nblocks); +-extern void _gcry_aes_aesni_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg, +- const void *inbuf_arg, size_t nblocks, +- int encrypt); +-extern void _gcry_aes_aesni_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg, +- size_t nblocks); ++extern void _gcry_aes_aesni_cfb_enc (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++extern void _gcry_aes_aesni_cbc_enc (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks, int cbc_mac); ++extern void _gcry_aes_aesni_ctr_enc (void *context, unsigned char *ctr, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++extern void _gcry_aes_aesni_cfb_dec (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++extern void _gcry_aes_aesni_cbc_dec (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++extern size_t _gcry_aes_aesni_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg, ++ const void *inbuf_arg, size_t nblocks, ++ int encrypt); ++extern size_t _gcry_aes_aesni_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg, ++ size_t nblocks); ++extern void _gcry_aes_aesni_xts_crypt (void *context, unsigned char *tweak, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks, int encrypt); + #endif + + #ifdef USE_SSSE3 +@@ -116,32 +113,27 @@ extern unsigned int _gcry_aes_ssse3_encr + extern unsigned int _gcry_aes_ssse3_decrypt (const RIJNDAEL_context *ctx, + unsigned char *dst, + const unsigned char *src); +-extern void _gcry_aes_ssse3_cfb_enc (RIJNDAEL_context *ctx, +- unsigned char *outbuf, +- const unsigned char *inbuf, +- unsigned char *iv, size_t nblocks); +-extern void _gcry_aes_ssse3_cbc_enc (RIJNDAEL_context *ctx, +- unsigned char *outbuf, +- const unsigned char *inbuf, +- unsigned char *iv, size_t nblocks, ++extern void _gcry_aes_ssse3_cfb_enc (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++extern void _gcry_aes_ssse3_cbc_enc (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks, + int cbc_mac); +-extern void _gcry_aes_ssse3_ctr_enc (RIJNDAEL_context *ctx, +- unsigned char *outbuf, +- const unsigned char *inbuf, +- unsigned char *ctr, size_t nblocks); +-extern void _gcry_aes_ssse3_cfb_dec (RIJNDAEL_context *ctx, +- unsigned char *outbuf, +- const unsigned char *inbuf, +- unsigned char *iv, size_t nblocks); +-extern void _gcry_aes_ssse3_cbc_dec (RIJNDAEL_context *ctx, +- unsigned char *outbuf, +- const unsigned char *inbuf, +- unsigned char *iv, size_t nblocks); +-extern void _gcry_aes_ssse3_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg, +- const void *inbuf_arg, size_t nblocks, +- int encrypt); +-extern void _gcry_aes_ssse3_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg, +- size_t nblocks); ++extern void _gcry_aes_ssse3_ctr_enc (void *context, unsigned char *ctr, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++extern void _gcry_aes_ssse3_cfb_dec (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++extern void _gcry_aes_ssse3_cbc_dec (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++extern size_t _gcry_aes_ssse3_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg, ++ const void *inbuf_arg, size_t nblocks, ++ int encrypt); ++extern size_t _gcry_aes_ssse3_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg, ++ size_t nblocks); + #endif + + #ifdef USE_PADLOCK +@@ -180,34 +172,110 @@ extern unsigned int _gcry_aes_armv8_ce_d + unsigned char *dst, + const unsigned char *src); + +-extern void _gcry_aes_armv8_ce_cfb_enc (RIJNDAEL_context *ctx, +- unsigned char *outbuf, +- const unsigned char *inbuf, +- unsigned char *iv, size_t nblocks); +-extern void _gcry_aes_armv8_ce_cbc_enc (RIJNDAEL_context *ctx, +- unsigned char *outbuf, +- const unsigned char *inbuf, +- unsigned char *iv, size_t nblocks, ++extern void _gcry_aes_armv8_ce_cfb_enc (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++extern void _gcry_aes_armv8_ce_cbc_enc (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks, + int cbc_mac); +-extern void _gcry_aes_armv8_ce_ctr_enc (RIJNDAEL_context *ctx, +- unsigned char *outbuf, +- const unsigned char *inbuf, +- unsigned char *ctr, size_t nblocks); +-extern void _gcry_aes_armv8_ce_cfb_dec (RIJNDAEL_context *ctx, +- unsigned char *outbuf, +- const unsigned char *inbuf, +- unsigned char *iv, size_t nblocks); +-extern void _gcry_aes_armv8_ce_cbc_dec (RIJNDAEL_context *ctx, +- unsigned char *outbuf, +- const unsigned char *inbuf, +- unsigned char *iv, size_t nblocks); +-extern void _gcry_aes_armv8_ce_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg, +- const void *inbuf_arg, size_t nblocks, +- int encrypt); +-extern void _gcry_aes_armv8_ce_ocb_auth (gcry_cipher_hd_t c, +- const void *abuf_arg, size_t nblocks); ++extern void _gcry_aes_armv8_ce_ctr_enc (void *context, unsigned char *ctr, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++extern void _gcry_aes_armv8_ce_cfb_dec (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++extern void _gcry_aes_armv8_ce_cbc_dec (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++extern size_t _gcry_aes_armv8_ce_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg, ++ const void *inbuf_arg, size_t nblocks, ++ int encrypt); ++extern size_t _gcry_aes_armv8_ce_ocb_auth (gcry_cipher_hd_t c, ++ const void *abuf_arg, size_t nblocks); ++extern void _gcry_aes_armv8_ce_xts_crypt (void *context, unsigned char *tweak, ++ void *outbuf_arg, ++ const void *inbuf_arg, ++ size_t nblocks, int encrypt); + #endif /*USE_ARM_ASM*/ + ++#ifdef USE_PPC_CRYPTO ++/* PowerPC Crypto implementations of AES */ ++extern void _gcry_aes_ppc8_setkey(RIJNDAEL_context *ctx, const byte *key); ++extern void _gcry_aes_ppc8_prepare_decryption(RIJNDAEL_context *ctx); ++ ++extern unsigned int _gcry_aes_ppc8_encrypt(const RIJNDAEL_context *ctx, ++ unsigned char *dst, ++ const unsigned char *src); ++extern unsigned int _gcry_aes_ppc8_decrypt(const RIJNDAEL_context *ctx, ++ unsigned char *dst, ++ const unsigned char *src); ++ ++extern void _gcry_aes_ppc8_cfb_enc (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++extern void _gcry_aes_ppc8_cbc_enc (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks, int cbc_mac); ++extern void _gcry_aes_ppc8_ctr_enc (void *context, unsigned char *ctr, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++extern void _gcry_aes_ppc8_cfb_dec (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++extern void _gcry_aes_ppc8_cbc_dec (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++ ++extern size_t _gcry_aes_ppc8_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg, ++ const void *inbuf_arg, size_t nblocks, ++ int encrypt); ++extern size_t _gcry_aes_ppc8_ocb_auth (gcry_cipher_hd_t c, ++ const void *abuf_arg, size_t nblocks); ++ ++extern void _gcry_aes_ppc8_xts_crypt (void *context, unsigned char *tweak, ++ void *outbuf_arg, ++ const void *inbuf_arg, ++ size_t nblocks, int encrypt); ++#endif /*USE_PPC_CRYPTO*/ ++ ++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE ++/* Power9 little-endian crypto implementations of AES */ ++extern unsigned int _gcry_aes_ppc9le_encrypt(const RIJNDAEL_context *ctx, ++ unsigned char *dst, ++ const unsigned char *src); ++extern unsigned int _gcry_aes_ppc9le_decrypt(const RIJNDAEL_context *ctx, ++ unsigned char *dst, ++ const unsigned char *src); ++ ++extern void _gcry_aes_ppc9le_cfb_enc (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++extern void _gcry_aes_ppc9le_cbc_enc (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks, int cbc_mac); ++extern void _gcry_aes_ppc9le_ctr_enc (void *context, unsigned char *ctr, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++extern void _gcry_aes_ppc9le_cfb_dec (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++extern void _gcry_aes_ppc9le_cbc_dec (void *context, unsigned char *iv, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks); ++ ++extern size_t _gcry_aes_ppc9le_ocb_crypt (gcry_cipher_hd_t c, void *outbuf_arg, ++ const void *inbuf_arg, size_t nblocks, ++ int encrypt); ++extern size_t _gcry_aes_ppc9le_ocb_auth (gcry_cipher_hd_t c, ++ const void *abuf_arg, size_t nblocks); ++ ++extern void _gcry_aes_ppc9le_xts_crypt (void *context, unsigned char *tweak, ++ void *outbuf_arg, ++ const void *inbuf_arg, ++ size_t nblocks, int encrypt); ++#endif /*USE_PPC_CRYPTO_WITH_PPC9LE*/ ++ + static unsigned int do_encrypt (const RIJNDAEL_context *ctx, unsigned char *bx, + const unsigned char *ax); + static unsigned int do_decrypt (const RIJNDAEL_context *ctx, unsigned char *bx, +@@ -260,7 +328,8 @@ static void prefetch_dec(void) + + /* Perform the key setup. */ + static gcry_err_code_t +-do_setkey (RIJNDAEL_context *ctx, const byte *key, const unsigned keylen) ++do_setkey (RIJNDAEL_context *ctx, const byte *key, const unsigned keylen, ++ gcry_cipher_hd_t hd) + { + static int initialized = 0; + static const char *selftest_failed = 0; +@@ -268,7 +337,7 @@ do_setkey (RIJNDAEL_context *ctx, const + int i,j, r, t, rconpointer = 0; + int KC; + #if defined(USE_AESNI) || defined(USE_PADLOCK) || defined(USE_SSSE3) \ +- || defined(USE_ARM_CE) ++ || defined(USE_ARM_CE) || defined(USE_PPC_CRYPTO) + unsigned int hwfeatures; + #endif + +@@ -310,7 +379,7 @@ do_setkey (RIJNDAEL_context *ctx, const + ctx->rounds = rounds; + + #if defined(USE_AESNI) || defined(USE_PADLOCK) || defined(USE_SSSE3) \ +- || defined(USE_ARM_CE) ++ || defined(USE_ARM_CE) || defined(USE_PPC_CRYPTO) + hwfeatures = _gcry_get_hw_features (); + #endif + +@@ -327,6 +396,12 @@ do_setkey (RIJNDAEL_context *ctx, const + #ifdef USE_ARM_CE + ctx->use_arm_ce = 0; + #endif ++#ifdef USE_PPC_CRYPTO ++ ctx->use_ppc_crypto = 0; ++#endif ++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE ++ ctx->use_ppc9le_crypto = 0; ++#endif + + if (0) + { +@@ -340,6 +415,17 @@ do_setkey (RIJNDAEL_context *ctx, const + ctx->prefetch_enc_fn = NULL; + ctx->prefetch_dec_fn = NULL; + ctx->use_aesni = 1; ++ if (hd) ++ { ++ hd->bulk.cfb_enc = _gcry_aes_aesni_cfb_enc; ++ hd->bulk.cfb_dec = _gcry_aes_aesni_cfb_dec; ++ hd->bulk.cbc_enc = _gcry_aes_aesni_cbc_enc; ++ hd->bulk.cbc_dec = _gcry_aes_aesni_cbc_dec; ++ hd->bulk.ctr_enc = _gcry_aes_aesni_ctr_enc; ++ hd->bulk.ocb_crypt = _gcry_aes_aesni_ocb_crypt; ++ hd->bulk.ocb_auth = _gcry_aes_aesni_ocb_auth; ++ hd->bulk.xts_crypt = _gcry_aes_aesni_xts_crypt; ++ } + } + #endif + #ifdef USE_PADLOCK +@@ -361,6 +447,16 @@ do_setkey (RIJNDAEL_context *ctx, const + ctx->prefetch_enc_fn = NULL; + ctx->prefetch_dec_fn = NULL; + ctx->use_ssse3 = 1; ++ if (hd) ++ { ++ hd->bulk.cfb_enc = _gcry_aes_ssse3_cfb_enc; ++ hd->bulk.cfb_dec = _gcry_aes_ssse3_cfb_dec; ++ hd->bulk.cbc_enc = _gcry_aes_ssse3_cbc_enc; ++ hd->bulk.cbc_dec = _gcry_aes_ssse3_cbc_dec; ++ hd->bulk.ctr_enc = _gcry_aes_ssse3_ctr_enc; ++ hd->bulk.ocb_crypt = _gcry_aes_ssse3_ocb_crypt; ++ hd->bulk.ocb_auth = _gcry_aes_ssse3_ocb_auth; ++ } + } + #endif + #ifdef USE_ARM_CE +@@ -371,6 +467,60 @@ do_setkey (RIJNDAEL_context *ctx, const + ctx->prefetch_enc_fn = NULL; + ctx->prefetch_dec_fn = NULL; + ctx->use_arm_ce = 1; ++ if (hd) ++ { ++ hd->bulk.cfb_enc = _gcry_aes_armv8_ce_cfb_enc; ++ hd->bulk.cfb_dec = _gcry_aes_armv8_ce_cfb_dec; ++ hd->bulk.cbc_enc = _gcry_aes_armv8_ce_cbc_enc; ++ hd->bulk.cbc_dec = _gcry_aes_armv8_ce_cbc_dec; ++ hd->bulk.ctr_enc = _gcry_aes_armv8_ce_ctr_enc; ++ hd->bulk.ocb_crypt = _gcry_aes_armv8_ce_ocb_crypt; ++ hd->bulk.ocb_auth = _gcry_aes_armv8_ce_ocb_auth; ++ hd->bulk.xts_crypt = _gcry_aes_armv8_ce_xts_crypt; ++ } ++ } ++#endif ++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE ++ else if ((hwfeatures & HWF_PPC_VCRYPTO) && (hwfeatures & HWF_PPC_ARCH_3_00)) ++ { ++ ctx->encrypt_fn = _gcry_aes_ppc9le_encrypt; ++ ctx->decrypt_fn = _gcry_aes_ppc9le_decrypt; ++ ctx->prefetch_enc_fn = NULL; ++ ctx->prefetch_dec_fn = NULL; ++ ctx->use_ppc_crypto = 1; /* same key-setup as USE_PPC_CRYPTO */ ++ ctx->use_ppc9le_crypto = 1; ++ if (hd) ++ { ++ hd->bulk.cfb_enc = _gcry_aes_ppc9le_cfb_enc; ++ hd->bulk.cfb_dec = _gcry_aes_ppc9le_cfb_dec; ++ hd->bulk.cbc_enc = _gcry_aes_ppc9le_cbc_enc; ++ hd->bulk.cbc_dec = _gcry_aes_ppc9le_cbc_dec; ++ hd->bulk.ctr_enc = _gcry_aes_ppc9le_ctr_enc; ++ hd->bulk.ocb_crypt = _gcry_aes_ppc9le_ocb_crypt; ++ hd->bulk.ocb_auth = _gcry_aes_ppc9le_ocb_auth; ++ hd->bulk.xts_crypt = _gcry_aes_ppc9le_xts_crypt; ++ } ++ } ++#endif ++#ifdef USE_PPC_CRYPTO ++ else if (hwfeatures & HWF_PPC_VCRYPTO) ++ { ++ ctx->encrypt_fn = _gcry_aes_ppc8_encrypt; ++ ctx->decrypt_fn = _gcry_aes_ppc8_decrypt; ++ ctx->prefetch_enc_fn = NULL; ++ ctx->prefetch_dec_fn = NULL; ++ ctx->use_ppc_crypto = 1; ++ if (hd) ++ { ++ hd->bulk.cfb_enc = _gcry_aes_ppc8_cfb_enc; ++ hd->bulk.cfb_dec = _gcry_aes_ppc8_cfb_dec; ++ hd->bulk.cbc_enc = _gcry_aes_ppc8_cbc_enc; ++ hd->bulk.cbc_dec = _gcry_aes_ppc8_cbc_dec; ++ hd->bulk.ctr_enc = _gcry_aes_ppc8_ctr_enc; ++ hd->bulk.ocb_crypt = _gcry_aes_ppc8_ocb_crypt; ++ hd->bulk.ocb_auth = _gcry_aes_ppc8_ocb_auth; ++ hd->bulk.xts_crypt = _gcry_aes_ppc8_xts_crypt; ++ } + } + #endif + else +@@ -399,6 +549,10 @@ do_setkey (RIJNDAEL_context *ctx, const + else if (ctx->use_arm_ce) + _gcry_aes_armv8_ce_setkey (ctx, key); + #endif ++#ifdef USE_PPC_CRYPTO ++ else if (ctx->use_ppc_crypto) ++ _gcry_aes_ppc8_setkey (ctx, key); ++#endif + else + { + const byte *sbox = ((const byte *)encT) + 1; +@@ -503,10 +657,11 @@ do_setkey (RIJNDAEL_context *ctx, const + + + static gcry_err_code_t +-rijndael_setkey (void *context, const byte *key, const unsigned keylen) ++rijndael_setkey (void *context, const byte *key, const unsigned keylen, ++ gcry_cipher_hd_t hd) + { + RIJNDAEL_context *ctx = context; +- return do_setkey (ctx, key, keylen); ++ return do_setkey (ctx, key, keylen, hd); + } + + +@@ -535,7 +690,19 @@ prepare_decryption( RIJNDAEL_context *ct + { + _gcry_aes_armv8_ce_prepare_decryption (ctx); + } +-#endif /*USE_SSSE3*/ ++#endif /*USE_ARM_CE*/ ++#ifdef USE_ARM_CE ++ else if (ctx->use_arm_ce) ++ { ++ _gcry_aes_armv8_ce_prepare_decryption (ctx); ++ } ++#endif /*USE_ARM_CE*/ ++#ifdef USE_PPC_CRYPTO ++ else if (ctx->use_ppc_crypto) ++ { ++ _gcry_aes_ppc8_prepare_decryption (ctx); ++ } ++#endif + #ifdef USE_PADLOCK + else if (ctx->use_padlock) + { +@@ -790,42 +957,56 @@ _gcry_aes_cfb_enc (void *context, unsign + const unsigned char *inbuf = inbuf_arg; + unsigned int burn_depth = 0; + +- if (ctx->prefetch_enc_fn) +- ctx->prefetch_enc_fn(); +- + if (0) + ; + #ifdef USE_AESNI + else if (ctx->use_aesni) + { +- _gcry_aes_aesni_cfb_enc (ctx, outbuf, inbuf, iv, nblocks); +- burn_depth = 0; ++ _gcry_aes_aesni_cfb_enc (ctx, iv, outbuf, inbuf, nblocks); ++ return; + } + #endif /*USE_AESNI*/ + #ifdef USE_SSSE3 + else if (ctx->use_ssse3) + { +- _gcry_aes_ssse3_cfb_enc (ctx, outbuf, inbuf, iv, nblocks); +- burn_depth = 0; ++ _gcry_aes_ssse3_cfb_enc (ctx, iv, outbuf, inbuf, nblocks); ++ return; + } + #endif /*USE_SSSE3*/ + #ifdef USE_ARM_CE + else if (ctx->use_arm_ce) + { +- _gcry_aes_armv8_ce_cfb_enc (ctx, outbuf, inbuf, iv, nblocks); +- burn_depth = 0; ++ _gcry_aes_armv8_ce_cfb_enc (ctx, iv, outbuf, inbuf, nblocks); ++ return; + } + #endif /*USE_ARM_CE*/ ++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE ++ else if (ctx->use_ppc9le_crypto) ++ { ++ _gcry_aes_ppc9le_cfb_enc (ctx, iv, outbuf, inbuf, nblocks); ++ return; ++ } ++#endif /*USE_PPC_CRYPTO_WITH_PPC9LE*/ ++#ifdef USE_PPC_CRYPTO ++ else if (ctx->use_ppc_crypto) ++ { ++ _gcry_aes_ppc8_cfb_enc (ctx, iv, outbuf, inbuf, nblocks); ++ return; ++ } ++#endif /*USE_PPC_CRYPTO*/ + else + { + rijndael_cryptfn_t encrypt_fn = ctx->encrypt_fn; + ++ if (ctx->prefetch_enc_fn) ++ ctx->prefetch_enc_fn(); ++ + for ( ;nblocks; nblocks-- ) + { + /* Encrypt the IV. */ + burn_depth = encrypt_fn (ctx, iv, iv); + /* XOR the input with the IV and store input into IV. */ +- buf_xor_2dst(outbuf, iv, inbuf, BLOCKSIZE); ++ cipher_block_xor_2dst(outbuf, iv, inbuf, BLOCKSIZE); + outbuf += BLOCKSIZE; + inbuf += BLOCKSIZE; + } +@@ -851,41 +1032,55 @@ _gcry_aes_cbc_enc (void *context, unsign + unsigned char *last_iv; + unsigned int burn_depth = 0; + +- if (ctx->prefetch_enc_fn) +- ctx->prefetch_enc_fn(); +- + if (0) + ; + #ifdef USE_AESNI + else if (ctx->use_aesni) + { +- _gcry_aes_aesni_cbc_enc (ctx, outbuf, inbuf, iv, nblocks, cbc_mac); +- burn_depth = 0; ++ _gcry_aes_aesni_cbc_enc (ctx, iv, outbuf, inbuf, nblocks, cbc_mac); ++ return; + } + #endif /*USE_AESNI*/ + #ifdef USE_SSSE3 + else if (ctx->use_ssse3) + { +- _gcry_aes_ssse3_cbc_enc (ctx, outbuf, inbuf, iv, nblocks, cbc_mac); +- burn_depth = 0; ++ _gcry_aes_ssse3_cbc_enc (ctx, iv, outbuf, inbuf, nblocks, cbc_mac); ++ return; + } + #endif /*USE_SSSE3*/ + #ifdef USE_ARM_CE + else if (ctx->use_arm_ce) + { +- _gcry_aes_armv8_ce_cbc_enc (ctx, outbuf, inbuf, iv, nblocks, cbc_mac); +- burn_depth = 0; ++ _gcry_aes_armv8_ce_cbc_enc (ctx, iv, outbuf, inbuf, nblocks, cbc_mac); ++ return; + } + #endif /*USE_ARM_CE*/ ++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE ++ else if (ctx->use_ppc9le_crypto) ++ { ++ _gcry_aes_ppc9le_cbc_enc (ctx, iv, outbuf, inbuf, nblocks, cbc_mac); ++ return; ++ } ++#endif /*USE_PPC_CRYPTO_WITH_PPC9LE*/ ++#ifdef USE_PPC_CRYPTO ++ else if (ctx->use_ppc_crypto) ++ { ++ _gcry_aes_ppc8_cbc_enc (ctx, iv, outbuf, inbuf, nblocks, cbc_mac); ++ return; ++ } ++#endif /*USE_PPC_CRYPTO*/ + else + { + rijndael_cryptfn_t encrypt_fn = ctx->encrypt_fn; + ++ if (ctx->prefetch_enc_fn) ++ ctx->prefetch_enc_fn(); ++ + last_iv = iv; + + for ( ;nblocks; nblocks-- ) + { +- buf_xor(outbuf, inbuf, last_iv, BLOCKSIZE); ++ cipher_block_xor(outbuf, inbuf, last_iv, BLOCKSIZE); + + burn_depth = encrypt_fn (ctx, outbuf, outbuf); + +@@ -896,7 +1091,7 @@ _gcry_aes_cbc_enc (void *context, unsign + } + + if (last_iv != iv) +- buf_cpy (iv, last_iv, BLOCKSIZE); ++ cipher_block_cpy (iv, last_iv, BLOCKSIZE); + } + + if (burn_depth) +@@ -920,43 +1115,57 @@ _gcry_aes_ctr_enc (void *context, unsign + unsigned int burn_depth = 0; + int i; + +- if (ctx->prefetch_enc_fn) +- ctx->prefetch_enc_fn(); +- + if (0) + ; + #ifdef USE_AESNI + else if (ctx->use_aesni) + { +- _gcry_aes_aesni_ctr_enc (ctx, outbuf, inbuf, ctr, nblocks); +- burn_depth = 0; ++ _gcry_aes_aesni_ctr_enc (ctx, ctr, outbuf, inbuf, nblocks); ++ return; + } + #endif /*USE_AESNI*/ + #ifdef USE_SSSE3 + else if (ctx->use_ssse3) + { +- _gcry_aes_ssse3_ctr_enc (ctx, outbuf, inbuf, ctr, nblocks); +- burn_depth = 0; ++ _gcry_aes_ssse3_ctr_enc (ctx, ctr, outbuf, inbuf, nblocks); ++ return; + } + #endif /*USE_SSSE3*/ + #ifdef USE_ARM_CE + else if (ctx->use_arm_ce) + { +- _gcry_aes_armv8_ce_ctr_enc (ctx, outbuf, inbuf, ctr, nblocks); +- burn_depth = 0; ++ _gcry_aes_armv8_ce_ctr_enc (ctx, ctr, outbuf, inbuf, nblocks); ++ return; + } + #endif /*USE_ARM_CE*/ ++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE ++ else if (ctx->use_ppc9le_crypto) ++ { ++ _gcry_aes_ppc9le_ctr_enc (ctx, ctr, outbuf, inbuf, nblocks); ++ return; ++ } ++#endif /*USE_PPC_CRYPTO_WITH_PPC9LE*/ ++#ifdef USE_PPC_CRYPTO ++ else if (ctx->use_ppc_crypto) ++ { ++ _gcry_aes_ppc8_ctr_enc (ctx, ctr, outbuf, inbuf, nblocks); ++ return; ++ } ++#endif /*USE_PPC_CRYPTO*/ + else + { + union { unsigned char x1[16] ATTR_ALIGNED_16; u32 x32[4]; } tmp; + rijndael_cryptfn_t encrypt_fn = ctx->encrypt_fn; + ++ if (ctx->prefetch_enc_fn) ++ ctx->prefetch_enc_fn(); ++ + for ( ;nblocks; nblocks-- ) + { + /* Encrypt the counter. */ + burn_depth = encrypt_fn (ctx, tmp.x1, ctr); + /* XOR the input with the encrypted counter and store in output. */ +- buf_xor(outbuf, tmp.x1, inbuf, BLOCKSIZE); ++ cipher_block_xor(outbuf, tmp.x1, inbuf, BLOCKSIZE); + outbuf += BLOCKSIZE; + inbuf += BLOCKSIZE; + /* Increment the counter. */ +@@ -1187,40 +1396,54 @@ _gcry_aes_cfb_dec (void *context, unsign + const unsigned char *inbuf = inbuf_arg; + unsigned int burn_depth = 0; + +- if (ctx->prefetch_enc_fn) +- ctx->prefetch_enc_fn(); +- + if (0) + ; + #ifdef USE_AESNI + else if (ctx->use_aesni) + { +- _gcry_aes_aesni_cfb_dec (ctx, outbuf, inbuf, iv, nblocks); +- burn_depth = 0; ++ _gcry_aes_aesni_cfb_dec (ctx, iv, outbuf, inbuf, nblocks); ++ return; + } + #endif /*USE_AESNI*/ + #ifdef USE_SSSE3 + else if (ctx->use_ssse3) + { +- _gcry_aes_ssse3_cfb_dec (ctx, outbuf, inbuf, iv, nblocks); +- burn_depth = 0; ++ _gcry_aes_ssse3_cfb_dec (ctx, iv, outbuf, inbuf, nblocks); ++ return; + } + #endif /*USE_SSSE3*/ + #ifdef USE_ARM_CE + else if (ctx->use_arm_ce) + { +- _gcry_aes_armv8_ce_cfb_dec (ctx, outbuf, inbuf, iv, nblocks); +- burn_depth = 0; ++ _gcry_aes_armv8_ce_cfb_dec (ctx, iv, outbuf, inbuf, nblocks); ++ return; + } + #endif /*USE_ARM_CE*/ ++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE ++ else if (ctx->use_ppc9le_crypto) ++ { ++ _gcry_aes_ppc9le_cfb_dec (ctx, iv, outbuf, inbuf, nblocks); ++ return; ++ } ++#endif /*USE_PPC_CRYPTO_WITH_PPC9LE*/ ++#ifdef USE_PPC_CRYPTO ++ else if (ctx->use_ppc_crypto) ++ { ++ _gcry_aes_ppc8_cfb_dec (ctx, iv, outbuf, inbuf, nblocks); ++ return; ++ } ++#endif /*USE_PPC_CRYPTO*/ + else + { + rijndael_cryptfn_t encrypt_fn = ctx->encrypt_fn; + ++ if (ctx->prefetch_enc_fn) ++ ctx->prefetch_enc_fn(); ++ + for ( ;nblocks; nblocks-- ) + { + burn_depth = encrypt_fn (ctx, iv, iv); +- buf_xor_n_copy(outbuf, iv, inbuf, BLOCKSIZE); ++ cipher_block_xor_n_copy(outbuf, iv, inbuf, BLOCKSIZE); + outbuf += BLOCKSIZE; + inbuf += BLOCKSIZE; + } +@@ -1245,39 +1468,53 @@ _gcry_aes_cbc_dec (void *context, unsign + const unsigned char *inbuf = inbuf_arg; + unsigned int burn_depth = 0; + +- check_decryption_preparation (ctx); +- +- if (ctx->prefetch_dec_fn) +- ctx->prefetch_dec_fn(); +- + if (0) + ; + #ifdef USE_AESNI + else if (ctx->use_aesni) + { +- _gcry_aes_aesni_cbc_dec (ctx, outbuf, inbuf, iv, nblocks); +- burn_depth = 0; ++ _gcry_aes_aesni_cbc_dec (ctx, iv, outbuf, inbuf, nblocks); ++ return; + } + #endif /*USE_AESNI*/ + #ifdef USE_SSSE3 + else if (ctx->use_ssse3) + { +- _gcry_aes_ssse3_cbc_dec (ctx, outbuf, inbuf, iv, nblocks); +- burn_depth = 0; ++ _gcry_aes_ssse3_cbc_dec (ctx, iv, outbuf, inbuf, nblocks); ++ return; + } + #endif /*USE_SSSE3*/ + #ifdef USE_ARM_CE + else if (ctx->use_arm_ce) + { +- _gcry_aes_armv8_ce_cbc_dec (ctx, outbuf, inbuf, iv, nblocks); +- burn_depth = 0; ++ _gcry_aes_armv8_ce_cbc_dec (ctx, iv, outbuf, inbuf, nblocks); ++ return; + } + #endif /*USE_ARM_CE*/ ++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE ++ else if (ctx->use_ppc9le_crypto) ++ { ++ _gcry_aes_ppc9le_cbc_dec (ctx, iv, outbuf, inbuf, nblocks); ++ return; ++ } ++#endif /*USE_PPC_CRYPTO_WITH_PPC9LE*/ ++#ifdef USE_PPC_CRYPTO ++ else if (ctx->use_ppc_crypto) ++ { ++ _gcry_aes_ppc8_cbc_dec (ctx, iv, outbuf, inbuf, nblocks); ++ return; ++ } ++#endif /*USE_PPC_CRYPTO*/ + else + { + unsigned char savebuf[BLOCKSIZE] ATTR_ALIGNED_16; + rijndael_cryptfn_t decrypt_fn = ctx->decrypt_fn; + ++ check_decryption_preparation (ctx); ++ ++ if (ctx->prefetch_dec_fn) ++ ctx->prefetch_dec_fn(); ++ + for ( ;nblocks; nblocks-- ) + { + /* INBUF is needed later and it may be identical to OUTBUF, so store +@@ -1285,7 +1522,7 @@ _gcry_aes_cbc_dec (void *context, unsign + + burn_depth = decrypt_fn (ctx, savebuf, inbuf); + +- buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, BLOCKSIZE); ++ cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, BLOCKSIZE); + inbuf += BLOCKSIZE; + outbuf += BLOCKSIZE; + } +@@ -1309,62 +1546,61 @@ _gcry_aes_ocb_crypt (gcry_cipher_hd_t c, + const unsigned char *inbuf = inbuf_arg; + unsigned int burn_depth = 0; + +- if (encrypt) +- { +- if (ctx->prefetch_enc_fn) +- ctx->prefetch_enc_fn(); +- } +- else +- { +- check_decryption_preparation (ctx); +- +- if (ctx->prefetch_dec_fn) +- ctx->prefetch_dec_fn(); +- } +- + if (0) + ; + #ifdef USE_AESNI + else if (ctx->use_aesni) + { +- _gcry_aes_aesni_ocb_crypt (c, outbuf, inbuf, nblocks, encrypt); +- burn_depth = 0; ++ return _gcry_aes_aesni_ocb_crypt (c, outbuf, inbuf, nblocks, encrypt); + } + #endif /*USE_AESNI*/ + #ifdef USE_SSSE3 + else if (ctx->use_ssse3) + { +- _gcry_aes_ssse3_ocb_crypt (c, outbuf, inbuf, nblocks, encrypt); +- burn_depth = 0; ++ return _gcry_aes_ssse3_ocb_crypt (c, outbuf, inbuf, nblocks, encrypt); + } + #endif /*USE_SSSE3*/ + #ifdef USE_ARM_CE + else if (ctx->use_arm_ce) + { +- _gcry_aes_armv8_ce_ocb_crypt (c, outbuf, inbuf, nblocks, encrypt); +- burn_depth = 0; ++ return _gcry_aes_armv8_ce_ocb_crypt (c, outbuf, inbuf, nblocks, encrypt); + } + #endif /*USE_ARM_CE*/ ++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE ++ else if (ctx->use_ppc9le_crypto) ++ { ++ return _gcry_aes_ppc9le_ocb_crypt (c, outbuf, inbuf, nblocks, encrypt); ++ } ++#endif /*USE_PPC_CRYPTO_WITH_PPC9LE*/ ++#ifdef USE_PPC_CRYPTO ++ else if (ctx->use_ppc_crypto) ++ { ++ return _gcry_aes_ppc8_ocb_crypt (c, outbuf, inbuf, nblocks, encrypt); ++ } ++#endif /*USE_PPC_CRYPTO*/ + else if (encrypt) + { + union { unsigned char x1[16] ATTR_ALIGNED_16; u32 x32[4]; } l_tmp; + rijndael_cryptfn_t encrypt_fn = ctx->encrypt_fn; + ++ if (ctx->prefetch_enc_fn) ++ ctx->prefetch_enc_fn(); ++ + for ( ;nblocks; nblocks-- ) + { + u64 i = ++c->u_mode.ocb.data_nblocks; + const unsigned char *l = ocb_get_l(c, i); + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ +- buf_xor_1 (c->u_iv.iv, l, BLOCKSIZE); +- buf_cpy (l_tmp.x1, inbuf, BLOCKSIZE); ++ cipher_block_xor_1 (c->u_iv.iv, l, BLOCKSIZE); ++ cipher_block_cpy (l_tmp.x1, inbuf, BLOCKSIZE); + /* Checksum_i = Checksum_{i-1} xor P_i */ +- buf_xor_1 (c->u_ctr.ctr, l_tmp.x1, BLOCKSIZE); ++ cipher_block_xor_1 (c->u_ctr.ctr, l_tmp.x1, BLOCKSIZE); + /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */ +- buf_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE); ++ cipher_block_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE); + burn_depth = encrypt_fn (ctx, l_tmp.x1, l_tmp.x1); +- buf_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE); +- buf_cpy (outbuf, l_tmp.x1, BLOCKSIZE); ++ cipher_block_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE); ++ cipher_block_cpy (outbuf, l_tmp.x1, BLOCKSIZE); + + inbuf += BLOCKSIZE; + outbuf += BLOCKSIZE; +@@ -1375,21 +1611,26 @@ _gcry_aes_ocb_crypt (gcry_cipher_hd_t c, + union { unsigned char x1[16] ATTR_ALIGNED_16; u32 x32[4]; } l_tmp; + rijndael_cryptfn_t decrypt_fn = ctx->decrypt_fn; + ++ check_decryption_preparation (ctx); ++ ++ if (ctx->prefetch_dec_fn) ++ ctx->prefetch_dec_fn(); ++ + for ( ;nblocks; nblocks-- ) + { + u64 i = ++c->u_mode.ocb.data_nblocks; + const unsigned char *l = ocb_get_l(c, i); + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ +- buf_xor_1 (c->u_iv.iv, l, BLOCKSIZE); +- buf_cpy (l_tmp.x1, inbuf, BLOCKSIZE); ++ cipher_block_xor_1 (c->u_iv.iv, l, BLOCKSIZE); ++ cipher_block_cpy (l_tmp.x1, inbuf, BLOCKSIZE); + /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */ +- buf_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE); ++ cipher_block_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE); + burn_depth = decrypt_fn (ctx, l_tmp.x1, l_tmp.x1); +- buf_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE); ++ cipher_block_xor_1 (l_tmp.x1, c->u_iv.iv, BLOCKSIZE); + /* Checksum_i = Checksum_{i-1} xor P_i */ +- buf_xor_1 (c->u_ctr.ctr, l_tmp.x1, BLOCKSIZE); +- buf_cpy (outbuf, l_tmp.x1, BLOCKSIZE); ++ cipher_block_xor_1 (c->u_ctr.ctr, l_tmp.x1, BLOCKSIZE); ++ cipher_block_cpy (outbuf, l_tmp.x1, BLOCKSIZE); + + inbuf += BLOCKSIZE; + outbuf += BLOCKSIZE; +@@ -1411,48 +1652,58 @@ _gcry_aes_ocb_auth (gcry_cipher_hd_t c, + const unsigned char *abuf = abuf_arg; + unsigned int burn_depth = 0; + +- if (ctx->prefetch_enc_fn) +- ctx->prefetch_enc_fn(); +- + if (0) + ; + #ifdef USE_AESNI + else if (ctx->use_aesni) + { +- _gcry_aes_aesni_ocb_auth (c, abuf, nblocks); +- burn_depth = 0; ++ return _gcry_aes_aesni_ocb_auth (c, abuf, nblocks); + } + #endif /*USE_AESNI*/ + #ifdef USE_SSSE3 + else if (ctx->use_ssse3) + { +- _gcry_aes_ssse3_ocb_auth (c, abuf, nblocks); +- burn_depth = 0; ++ return _gcry_aes_ssse3_ocb_auth (c, abuf, nblocks); + } + #endif /*USE_SSSE3*/ + #ifdef USE_ARM_CE + else if (ctx->use_arm_ce) + { +- _gcry_aes_armv8_ce_ocb_auth (c, abuf, nblocks); +- burn_depth = 0; ++ return _gcry_aes_armv8_ce_ocb_auth (c, abuf, nblocks); + } + #endif /*USE_ARM_CE*/ ++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE ++ else if (ctx->use_ppc9le_crypto) ++ { ++ return _gcry_aes_ppc9le_ocb_auth (c, abuf, nblocks); ++ } ++#endif /*USE_PPC_CRYPTO_WITH_PPC9LE*/ ++#ifdef USE_PPC_CRYPTO ++ else if (ctx->use_ppc_crypto) ++ { ++ return _gcry_aes_ppc8_ocb_auth (c, abuf, nblocks); ++ } ++#endif /*USE_PPC_CRYPTO*/ + else + { + union { unsigned char x1[16] ATTR_ALIGNED_16; u32 x32[4]; } l_tmp; + rijndael_cryptfn_t encrypt_fn = ctx->encrypt_fn; + ++ if (ctx->prefetch_enc_fn) ++ ctx->prefetch_enc_fn(); ++ + for ( ;nblocks; nblocks-- ) + { + u64 i = ++c->u_mode.ocb.aad_nblocks; + const unsigned char *l = ocb_get_l(c, i); + + /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ +- buf_xor_1 (c->u_mode.ocb.aad_offset, l, BLOCKSIZE); ++ cipher_block_xor_1 (c->u_mode.ocb.aad_offset, l, BLOCKSIZE); + /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) */ +- buf_xor (l_tmp.x1, c->u_mode.ocb.aad_offset, abuf, BLOCKSIZE); ++ cipher_block_xor (l_tmp.x1, c->u_mode.ocb.aad_offset, abuf, ++ BLOCKSIZE); + burn_depth = encrypt_fn (ctx, l_tmp.x1, l_tmp.x1); +- buf_xor_1 (c->u_mode.ocb.aad_sum, l_tmp.x1, BLOCKSIZE); ++ cipher_block_xor_1 (c->u_mode.ocb.aad_sum, l_tmp.x1, BLOCKSIZE); + + abuf += BLOCKSIZE; + } +@@ -1467,6 +1718,106 @@ _gcry_aes_ocb_auth (gcry_cipher_hd_t c, + } + + ++/* Bulk encryption/decryption of complete blocks in XTS mode. */ ++void ++_gcry_aes_xts_crypt (void *context, unsigned char *tweak, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks, int encrypt) ++{ ++ RIJNDAEL_context *ctx = context; ++ unsigned char *outbuf = outbuf_arg; ++ const unsigned char *inbuf = inbuf_arg; ++ unsigned int burn_depth = 0; ++ rijndael_cryptfn_t crypt_fn; ++ u64 tweak_lo, tweak_hi, tweak_next_lo, tweak_next_hi, tmp_lo, tmp_hi, carry; ++ ++ if (0) ++ ; ++#ifdef USE_AESNI ++ else if (ctx->use_aesni) ++ { ++ _gcry_aes_aesni_xts_crypt (ctx, tweak, outbuf, inbuf, nblocks, encrypt); ++ return; ++ } ++#endif /*USE_AESNI*/ ++#ifdef USE_ARM_CE ++ else if (ctx->use_arm_ce) ++ { ++ _gcry_aes_armv8_ce_xts_crypt (ctx, tweak, outbuf, inbuf, nblocks, encrypt); ++ return; ++ } ++#endif /*USE_ARM_CE*/ ++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE ++ else if (ctx->use_ppc9le_crypto) ++ { ++ _gcry_aes_ppc9le_xts_crypt (ctx, tweak, outbuf, inbuf, nblocks, encrypt); ++ return; ++ } ++#endif /*USE_PPC_CRYPTO_WITH_PPC9LE*/ ++#ifdef USE_PPC_CRYPTO ++ else if (ctx->use_ppc_crypto) ++ { ++ _gcry_aes_ppc8_xts_crypt (ctx, tweak, outbuf, inbuf, nblocks, encrypt); ++ return; ++ } ++#endif /*USE_PPC_CRYPTO*/ ++ else ++ { ++ if (encrypt) ++ { ++ if (ctx->prefetch_enc_fn) ++ ctx->prefetch_enc_fn(); ++ ++ crypt_fn = ctx->encrypt_fn; ++ } ++ else ++ { ++ check_decryption_preparation (ctx); ++ ++ if (ctx->prefetch_dec_fn) ++ ctx->prefetch_dec_fn(); ++ ++ crypt_fn = ctx->decrypt_fn; ++ } ++ ++ tweak_next_lo = buf_get_le64 (tweak + 0); ++ tweak_next_hi = buf_get_le64 (tweak + 8); ++ ++ while (nblocks) ++ { ++ tweak_lo = tweak_next_lo; ++ tweak_hi = tweak_next_hi; ++ ++ /* Xor-Encrypt/Decrypt-Xor block. */ ++ tmp_lo = buf_get_le64 (inbuf + 0) ^ tweak_lo; ++ tmp_hi = buf_get_le64 (inbuf + 8) ^ tweak_hi; ++ ++ buf_put_le64 (outbuf + 0, tmp_lo); ++ buf_put_le64 (outbuf + 8, tmp_hi); ++ ++ /* Generate next tweak. */ ++ carry = -(tweak_next_hi >> 63) & 0x87; ++ tweak_next_hi = (tweak_next_hi << 1) + (tweak_next_lo >> 63); ++ tweak_next_lo = (tweak_next_lo << 1) ^ carry; ++ ++ burn_depth = crypt_fn (ctx, outbuf, outbuf); ++ ++ buf_put_le64 (outbuf + 0, buf_get_le64 (outbuf + 0) ^ tweak_lo); ++ buf_put_le64 (outbuf + 8, buf_get_le64 (outbuf + 8) ^ tweak_hi); ++ ++ outbuf += GCRY_XTS_BLOCK_LEN; ++ inbuf += GCRY_XTS_BLOCK_LEN; ++ nblocks--; ++ } ++ ++ buf_put_le64 (tweak + 0, tweak_next_lo); ++ buf_put_le64 (tweak + 8, tweak_next_hi); ++ } ++ ++ if (burn_depth) ++ _gcry_burn_stack (burn_depth + 5 * sizeof(void *)); ++} ++ + + /* Run the self-tests for AES 128. Returns NULL on success. */ + static const char* +@@ -1522,7 +1873,7 @@ selftest_basic_128 (void) + if (!ctx) + return "failed to allocate memory"; + +- rijndael_setkey (ctx, key_128, sizeof (key_128)); ++ rijndael_setkey (ctx, key_128, sizeof (key_128), NULL); + rijndael_encrypt (ctx, scratch, plaintext_128); + if (memcmp (scratch, ciphertext_128, sizeof (ciphertext_128))) + { +@@ -1565,7 +1916,7 @@ selftest_basic_192 (void) + ctx = _gcry_cipher_selftest_alloc_ctx (sizeof *ctx, &ctxmem); + if (!ctx) + return "failed to allocate memory"; +- rijndael_setkey (ctx, key_192, sizeof(key_192)); ++ rijndael_setkey (ctx, key_192, sizeof(key_192), NULL); + rijndael_encrypt (ctx, scratch, plaintext_192); + if (memcmp (scratch, ciphertext_192, sizeof (ciphertext_192))) + { +@@ -1610,7 +1961,7 @@ selftest_basic_256 (void) + ctx = _gcry_cipher_selftest_alloc_ctx (sizeof *ctx, &ctxmem); + if (!ctx) + return "failed to allocate memory"; +- rijndael_setkey (ctx, key_256, sizeof(key_256)); ++ rijndael_setkey (ctx, key_256, sizeof(key_256), NULL); + rijndael_encrypt (ctx, scratch, plaintext_256); + if (memcmp (scratch, ciphertext_256, sizeof (ciphertext_256))) + { +diff -up libgcrypt-1.8.5/cipher/rijndael-internal.h.aes-perf libgcrypt-1.8.5/cipher/rijndael-internal.h +--- libgcrypt-1.8.5/cipher/rijndael-internal.h.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/rijndael-internal.h 2020-04-22 18:29:41.676862114 +0200 +@@ -73,7 +73,7 @@ + # define USE_PADLOCK 1 + # endif + # endif +-#endif /*ENABLE_PADLOCK_SUPPORT*/ ++#endif /* ENABLE_PADLOCK_SUPPORT */ + + /* USE_AESNI inidicates whether to compile with Intel AES-NI code. We + need the vector-size attribute which seems to be available since +@@ -102,6 +102,23 @@ + # endif + #endif /* ENABLE_ARM_CRYPTO_SUPPORT */ + ++/* USE_PPC_CRYPTO indicates whether to enable PowerPC vector crypto ++ * accelerated code. USE_PPC_CRYPTO_WITH_PPC9LE indicates whether to ++ * enable POWER9 optimized variant. */ ++#undef USE_PPC_CRYPTO ++#undef USE_PPC_CRYPTO_WITH_PPC9LE ++#ifdef ENABLE_PPC_CRYPTO_SUPPORT ++# if defined(HAVE_COMPATIBLE_CC_PPC_ALTIVEC) && \ ++ defined(HAVE_GCC_INLINE_ASM_PPC_ALTIVEC) ++# if __GNUC__ >= 4 ++# define USE_PPC_CRYPTO 1 ++# if !defined(WORDS_BIGENDIAN) && defined(HAVE_GCC_INLINE_ASM_PPC_ARCH_3_00) ++# define USE_PPC_CRYPTO_WITH_PPC9LE 1 ++# endif ++# endif ++# endif ++#endif /* ENABLE_PPC_CRYPTO_SUPPORT */ ++ + struct RIJNDAEL_context_s; + + typedef unsigned int (*rijndael_cryptfn_t)(const struct RIJNDAEL_context_s *ctx, +@@ -150,6 +167,12 @@ typedef struct RIJNDAEL_context_s + #ifdef USE_ARM_CE + unsigned int use_arm_ce:1; /* ARMv8 CE shall be used. */ + #endif /*USE_ARM_CE*/ ++#ifdef USE_PPC_CRYPTO ++ unsigned int use_ppc_crypto:1; /* PowerPC crypto shall be used. */ ++#endif /*USE_PPC_CRYPTO*/ ++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE ++ unsigned int use_ppc9le_crypto:1; /* POWER9 LE crypto shall be used. */ ++#endif + rijndael_cryptfn_t encrypt_fn; + rijndael_cryptfn_t decrypt_fn; + rijndael_prefetchfn_t prefetch_enc_fn; +diff -up libgcrypt-1.8.5/cipher/rijndael-ppc9le.c.aes-perf libgcrypt-1.8.5/cipher/rijndael-ppc9le.c +--- libgcrypt-1.8.5/cipher/rijndael-ppc9le.c.aes-perf 2020-04-22 18:29:41.677862096 +0200 ++++ libgcrypt-1.8.5/cipher/rijndael-ppc9le.c 2020-04-22 18:29:41.677862096 +0200 +@@ -0,0 +1,102 @@ ++/* Rijndael (AES) for GnuPG - PowerPC Vector Crypto AES implementation ++ * Copyright (C) 2019 Shawn Landden ++ * Copyright (C) 2019-2020 Jussi Kivilinna ++ * ++ * 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 . ++ * ++ * Alternatively, this code may be used in OpenSSL from The OpenSSL Project, ++ * and Cryptogams by Andy Polyakov, and if made part of a release of either ++ * or both projects, is thereafter dual-licensed under the license said project ++ * is released under. ++ */ ++ ++#include ++ ++#include "rijndael-internal.h" ++#include "cipher-internal.h" ++#include "bufhelp.h" ++ ++#ifdef USE_PPC_CRYPTO_WITH_PPC9LE ++ ++#include "rijndael-ppc-common.h" ++ ++ ++static ASM_FUNC_ATTR_INLINE block ++asm_load_be_const(void) ++{ ++ static const block vec_dummy = { 0 }; ++ return vec_dummy; ++} ++ ++static ASM_FUNC_ATTR_INLINE block ++asm_be_swap(block vec, block be_bswap_const) ++{ ++ (void)be_bswap_const; ++ return vec; ++} ++ ++static ASM_FUNC_ATTR_INLINE block ++asm_load_be_noswap(unsigned long offset, const void *ptr) ++{ ++ block vec; ++#if __GNUC__ >= 4 ++ if (__builtin_constant_p (offset) && offset == 0) ++ __asm__ volatile ("lxvb16x %x0,0,%1\n\t" ++ : "=wa" (vec) ++ : "r" ((uintptr_t)ptr) ++ : "memory"); ++ else ++#endif ++ __asm__ volatile ("lxvb16x %x0,%1,%2\n\t" ++ : "=wa" (vec) ++ : "r" (offset), "r" ((uintptr_t)ptr) ++ : "memory", "r0"); ++ return vec; ++} ++ ++static ASM_FUNC_ATTR_INLINE void ++asm_store_be_noswap(block vec, unsigned long offset, void *ptr) ++{ ++#if __GNUC__ >= 4 ++ if (__builtin_constant_p (offset) && offset == 0) ++ __asm__ volatile ("stxvb16x %x0,0,%1\n\t" ++ : ++ : "wa" (vec), "r" ((uintptr_t)ptr) ++ : "memory"); ++ else ++#endif ++ __asm__ volatile ("stxvb16x %x0,%1,%2\n\t" ++ : ++ : "wa" (vec), "r" (offset), "r" ((uintptr_t)ptr) ++ : "memory", "r0"); ++} ++ ++ ++#define GCRY_AES_PPC9LE 1 ++#define ENCRYPT_BLOCK_FUNC _gcry_aes_ppc9le_encrypt ++#define DECRYPT_BLOCK_FUNC _gcry_aes_ppc9le_decrypt ++#define CFB_ENC_FUNC _gcry_aes_ppc9le_cfb_enc ++#define CFB_DEC_FUNC _gcry_aes_ppc9le_cfb_dec ++#define CBC_ENC_FUNC _gcry_aes_ppc9le_cbc_enc ++#define CBC_DEC_FUNC _gcry_aes_ppc9le_cbc_dec ++#define CTR_ENC_FUNC _gcry_aes_ppc9le_ctr_enc ++#define OCB_CRYPT_FUNC _gcry_aes_ppc9le_ocb_crypt ++#define OCB_AUTH_FUNC _gcry_aes_ppc9le_ocb_auth ++#define XTS_CRYPT_FUNC _gcry_aes_ppc9le_xts_crypt ++ ++#include ++ ++#endif /* USE_PPC_CRYPTO */ +diff -up libgcrypt-1.8.5/cipher/rijndael-ppc.c.aes-perf libgcrypt-1.8.5/cipher/rijndael-ppc.c +--- libgcrypt-1.8.5/cipher/rijndael-ppc.c.aes-perf 2020-04-22 18:29:41.677862096 +0200 ++++ libgcrypt-1.8.5/cipher/rijndael-ppc.c 2020-04-22 18:29:41.677862096 +0200 +@@ -0,0 +1,259 @@ ++/* Rijndael (AES) for GnuPG - PowerPC Vector Crypto AES implementation ++ * Copyright (C) 2019 Shawn Landden ++ * Copyright (C) 2019-2020 Jussi Kivilinna ++ * ++ * 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 . ++ * ++ * Alternatively, this code may be used in OpenSSL from The OpenSSL Project, ++ * and Cryptogams by Andy Polyakov, and if made part of a release of either ++ * or both projects, is thereafter dual-licensed under the license said project ++ * is released under. ++ */ ++ ++#include ++ ++#include "rijndael-internal.h" ++#include "cipher-internal.h" ++#include "bufhelp.h" ++ ++#ifdef USE_PPC_CRYPTO ++ ++#include "rijndael-ppc-common.h" ++ ++ ++#ifdef WORDS_BIGENDIAN ++static const block vec_bswap32_const = ++ { 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 }; ++#else ++static const block vec_bswap32_const_neg = ++ { ~3, ~2, ~1, ~0, ~7, ~6, ~5, ~4, ~11, ~10, ~9, ~8, ~15, ~14, ~13, ~12 }; ++#endif ++ ++ ++static ASM_FUNC_ATTR_INLINE block ++asm_load_be_const(void) ++{ ++#ifndef WORDS_BIGENDIAN ++ return ALIGNED_LOAD (&vec_bswap32_const_neg, 0); ++#else ++ static const block vec_dummy = { 0 }; ++ return vec_dummy; ++#endif ++} ++ ++static ASM_FUNC_ATTR_INLINE block ++asm_be_swap(block vec, block be_bswap_const) ++{ ++ (void)be_bswap_const; ++#ifndef WORDS_BIGENDIAN ++ return asm_vperm1 (vec, be_bswap_const); ++#else ++ return vec; ++#endif ++} ++ ++static ASM_FUNC_ATTR_INLINE block ++asm_load_be_noswap(unsigned long offset, const void *ptr) ++{ ++ block vec; ++#if __GNUC__ >= 4 ++ if (__builtin_constant_p (offset) && offset == 0) ++ __asm__ volatile ("lxvw4x %x0,0,%1\n\t" ++ : "=wa" (vec) ++ : "r" ((uintptr_t)ptr) ++ : "memory"); ++ else ++#endif ++ __asm__ volatile ("lxvw4x %x0,%1,%2\n\t" ++ : "=wa" (vec) ++ : "r" (offset), "r" ((uintptr_t)ptr) ++ : "memory", "r0"); ++ /* NOTE: vec needs to be be-swapped using 'asm_be_swap' by caller */ ++ return vec; ++} ++ ++static ASM_FUNC_ATTR_INLINE void ++asm_store_be_noswap(block vec, unsigned long offset, void *ptr) ++{ ++ /* NOTE: vec be-swapped using 'asm_be_swap' by caller */ ++#if __GNUC__ >= 4 ++ if (__builtin_constant_p (offset) && offset == 0) ++ __asm__ volatile ("stxvw4x %x0,0,%1\n\t" ++ : ++ : "wa" (vec), "r" ((uintptr_t)ptr) ++ : "memory"); ++ else ++#endif ++ __asm__ volatile ("stxvw4x %x0,%1,%2\n\t" ++ : ++ : "wa" (vec), "r" (offset), "r" ((uintptr_t)ptr) ++ : "memory", "r0"); ++} ++ ++ ++static ASM_FUNC_ATTR_INLINE u32 ++_gcry_aes_sbox4_ppc8(u32 fourbytes) ++{ ++ union ++ { ++ PROPERLY_ALIGNED_TYPE dummy; ++ block data_vec; ++ u32 data32[4]; ++ } u; ++ ++ u.data32[0] = fourbytes; ++ u.data_vec = vec_sbox_be(u.data_vec); ++ return u.data32[0]; ++} ++ ++void ++_gcry_aes_ppc8_setkey (RIJNDAEL_context *ctx, const byte *key) ++{ ++ const block bige_const = asm_load_be_const(); ++ union ++ { ++ PROPERLY_ALIGNED_TYPE dummy; ++ byte data[MAXKC][4]; ++ u32 data32[MAXKC]; ++ } tkk[2]; ++ unsigned int rounds = ctx->rounds; ++ int KC = rounds - 6; ++ unsigned int keylen = KC * 4; ++ u128_t *ekey = (u128_t *)(void *)ctx->keyschenc; ++ unsigned int i, r, t; ++ byte rcon = 1; ++ int j; ++#define k tkk[0].data ++#define k_u32 tkk[0].data32 ++#define tk tkk[1].data ++#define tk_u32 tkk[1].data32 ++#define W (ctx->keyschenc) ++#define W_u32 (ctx->keyschenc32) ++ ++ for (i = 0; i < keylen; i++) ++ { ++ k[i >> 2][i & 3] = key[i]; ++ } ++ ++ for (j = KC-1; j >= 0; j--) ++ { ++ tk_u32[j] = k_u32[j]; ++ } ++ r = 0; ++ t = 0; ++ /* Copy values into round key array. */ ++ for (j = 0; (j < KC) && (r < rounds + 1); ) ++ { ++ for (; (j < KC) && (t < 4); j++, t++) ++ { ++ W_u32[r][t] = le_bswap32(tk_u32[j]); ++ } ++ if (t == 4) ++ { ++ r++; ++ t = 0; ++ } ++ } ++ while (r < rounds + 1) ++ { ++ tk_u32[0] ^= ++ le_bswap32( ++ _gcry_aes_sbox4_ppc8(rol(le_bswap32(tk_u32[KC - 1]), 24)) ^ rcon); ++ ++ if (KC != 8) ++ { ++ for (j = 1; j < KC; j++) ++ { ++ tk_u32[j] ^= tk_u32[j-1]; ++ } ++ } ++ else ++ { ++ for (j = 1; j < KC/2; j++) ++ { ++ tk_u32[j] ^= tk_u32[j-1]; ++ } ++ ++ tk_u32[KC/2] ^= ++ le_bswap32(_gcry_aes_sbox4_ppc8(le_bswap32(tk_u32[KC/2 - 1]))); ++ ++ for (j = KC/2 + 1; j < KC; j++) ++ { ++ tk_u32[j] ^= tk_u32[j-1]; ++ } ++ } ++ ++ /* Copy values into round key array. */ ++ for (j = 0; (j < KC) && (r < rounds + 1); ) ++ { ++ for (; (j < KC) && (t < 4); j++, t++) ++ { ++ W_u32[r][t] = le_bswap32(tk_u32[j]); ++ } ++ if (t == 4) ++ { ++ r++; ++ t = 0; ++ } ++ } ++ ++ rcon = (rcon << 1) ^ (-(rcon >> 7) & 0x1b); ++ } ++ ++ /* Store in big-endian order. */ ++ for (r = 0; r <= rounds; r++) ++ { ++#ifndef WORDS_BIGENDIAN ++ VEC_STORE_BE(ekey, r, ALIGNED_LOAD (ekey, r), bige_const); ++#else ++ block rvec = ALIGNED_LOAD (ekey, r); ++ ALIGNED_STORE (ekey, r, ++ vec_perm(rvec, rvec, vec_bswap32_const)); ++ (void)bige_const; ++#endif ++ } ++ ++#undef W ++#undef tk ++#undef k ++#undef W_u32 ++#undef tk_u32 ++#undef k_u32 ++ wipememory(&tkk, sizeof(tkk)); ++} ++ ++void ++_gcry_aes_ppc8_prepare_decryption (RIJNDAEL_context *ctx) ++{ ++ internal_aes_ppc_prepare_decryption (ctx); ++} ++ ++ ++#define GCRY_AES_PPC8 1 ++#define ENCRYPT_BLOCK_FUNC _gcry_aes_ppc8_encrypt ++#define DECRYPT_BLOCK_FUNC _gcry_aes_ppc8_decrypt ++#define CFB_ENC_FUNC _gcry_aes_ppc8_cfb_enc ++#define CFB_DEC_FUNC _gcry_aes_ppc8_cfb_dec ++#define CBC_ENC_FUNC _gcry_aes_ppc8_cbc_enc ++#define CBC_DEC_FUNC _gcry_aes_ppc8_cbc_dec ++#define CTR_ENC_FUNC _gcry_aes_ppc8_ctr_enc ++#define OCB_CRYPT_FUNC _gcry_aes_ppc8_ocb_crypt ++#define OCB_AUTH_FUNC _gcry_aes_ppc8_ocb_auth ++#define XTS_CRYPT_FUNC _gcry_aes_ppc8_xts_crypt ++ ++#include ++ ++#endif /* USE_PPC_CRYPTO */ +diff -up libgcrypt-1.8.5/cipher/rijndael-ppc-common.h.aes-perf libgcrypt-1.8.5/cipher/rijndael-ppc-common.h +--- libgcrypt-1.8.5/cipher/rijndael-ppc-common.h.aes-perf 2020-04-22 18:29:41.678862076 +0200 ++++ libgcrypt-1.8.5/cipher/rijndael-ppc-common.h 2020-04-22 18:29:41.678862076 +0200 +@@ -0,0 +1,342 @@ ++/* Rijndael (AES) for GnuPG - PowerPC Vector Crypto AES implementation ++ * Copyright (C) 2019 Shawn Landden ++ * Copyright (C) 2019-2020 Jussi Kivilinna ++ * ++ * 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 . ++ * ++ * Alternatively, this code may be used in OpenSSL from The OpenSSL Project, ++ * and Cryptogams by Andy Polyakov, and if made part of a release of either ++ * or both projects, is thereafter dual-licensed under the license said project ++ * is released under. ++ */ ++ ++#ifndef G10_RIJNDAEL_PPC_COMMON_H ++#define G10_RIJNDAEL_PPC_COMMON_H ++ ++#include ++ ++ ++typedef vector unsigned char block; ++ ++typedef union ++{ ++ u32 data32[4]; ++} __attribute__((packed, aligned(1), may_alias)) u128_t; ++ ++ ++#define ALWAYS_INLINE inline __attribute__((always_inline)) ++#define NO_INLINE __attribute__((noinline)) ++#define NO_INSTRUMENT_FUNCTION __attribute__((no_instrument_function)) ++ ++#define ASM_FUNC_ATTR NO_INSTRUMENT_FUNCTION ++#define ASM_FUNC_ATTR_INLINE ASM_FUNC_ATTR ALWAYS_INLINE ++#define ASM_FUNC_ATTR_NOINLINE ASM_FUNC_ATTR NO_INLINE ++ ++ ++#define ALIGNED_LOAD(in_ptr, offs) \ ++ (asm_aligned_ld ((offs) * 16, (const void *)(in_ptr))) ++ ++#define ALIGNED_STORE(out_ptr, offs, vec) \ ++ (asm_aligned_st ((vec), (offs) * 16, (void *)(out_ptr))) ++ ++#define VEC_BE_SWAP(vec, bige_const) (asm_be_swap ((vec), (bige_const))) ++ ++#define VEC_LOAD_BE(in_ptr, offs, bige_const) \ ++ (asm_be_swap (asm_load_be_noswap ((offs) * 16, (const void *)(in_ptr)), \ ++ bige_const)) ++ ++#define VEC_LOAD_BE_NOSWAP(in_ptr, offs) \ ++ (asm_load_be_noswap ((offs) * 16, (const unsigned char *)(in_ptr))) ++ ++#define VEC_STORE_BE(out_ptr, offs, vec, bige_const) \ ++ (asm_store_be_noswap (asm_be_swap ((vec), (bige_const)), (offs) * 16, \ ++ (void *)(out_ptr))) ++ ++#define VEC_STORE_BE_NOSWAP(out_ptr, offs, vec) \ ++ (asm_store_be_noswap ((vec), (offs) * 16, (void *)(out_ptr))) ++ ++ ++#define ROUND_KEY_VARIABLES \ ++ block rkey0, rkeylast ++ ++#define PRELOAD_ROUND_KEYS(nrounds) \ ++ do { \ ++ rkey0 = ALIGNED_LOAD (rk, 0); \ ++ rkeylast = ALIGNED_LOAD (rk, nrounds); \ ++ } while (0) ++ ++#define AES_ENCRYPT(blk, nrounds) \ ++ do { \ ++ blk ^= rkey0; \ ++ blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 1)); \ ++ blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 2)); \ ++ blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 3)); \ ++ blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 4)); \ ++ blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 5)); \ ++ blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 6)); \ ++ blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 7)); \ ++ blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 8)); \ ++ blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 9)); \ ++ if (nrounds >= 12) \ ++ { \ ++ blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 10)); \ ++ blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 11)); \ ++ if (rounds > 12) \ ++ { \ ++ blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 12)); \ ++ blk = asm_cipher_be (blk, ALIGNED_LOAD (rk, 13)); \ ++ } \ ++ } \ ++ blk = asm_cipherlast_be (blk, rkeylast); \ ++ } while (0) ++ ++#define AES_DECRYPT(blk, nrounds) \ ++ do { \ ++ blk ^= rkey0; \ ++ blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 1)); \ ++ blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 2)); \ ++ blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 3)); \ ++ blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 4)); \ ++ blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 5)); \ ++ blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 6)); \ ++ blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 7)); \ ++ blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 8)); \ ++ blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 9)); \ ++ if (nrounds >= 12) \ ++ { \ ++ blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 10)); \ ++ blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 11)); \ ++ if (rounds > 12) \ ++ { \ ++ blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 12)); \ ++ blk = asm_ncipher_be (blk, ALIGNED_LOAD (rk, 13)); \ ++ } \ ++ } \ ++ blk = asm_ncipherlast_be (blk, rkeylast); \ ++ } while (0) ++ ++ ++#define ROUND_KEY_VARIABLES_ALL \ ++ block rkey0, rkey1, rkey2, rkey3, rkey4, rkey5, rkey6, rkey7, rkey8, \ ++ rkey9, rkey10, rkey11, rkey12, rkey13, rkeylast ++ ++#define PRELOAD_ROUND_KEYS_ALL(nrounds) \ ++ do { \ ++ rkey0 = ALIGNED_LOAD (rk, 0); \ ++ rkey1 = ALIGNED_LOAD (rk, 1); \ ++ rkey2 = ALIGNED_LOAD (rk, 2); \ ++ rkey3 = ALIGNED_LOAD (rk, 3); \ ++ rkey4 = ALIGNED_LOAD (rk, 4); \ ++ rkey5 = ALIGNED_LOAD (rk, 5); \ ++ rkey6 = ALIGNED_LOAD (rk, 6); \ ++ rkey7 = ALIGNED_LOAD (rk, 7); \ ++ rkey8 = ALIGNED_LOAD (rk, 8); \ ++ rkey9 = ALIGNED_LOAD (rk, 9); \ ++ if (nrounds >= 12) \ ++ { \ ++ rkey10 = ALIGNED_LOAD (rk, 10); \ ++ rkey11 = ALIGNED_LOAD (rk, 11); \ ++ if (rounds > 12) \ ++ { \ ++ rkey12 = ALIGNED_LOAD (rk, 12); \ ++ rkey13 = ALIGNED_LOAD (rk, 13); \ ++ } \ ++ } \ ++ rkeylast = ALIGNED_LOAD (rk, nrounds); \ ++ } while (0) ++ ++#define AES_ENCRYPT_ALL(blk, nrounds) \ ++ do { \ ++ blk ^= rkey0; \ ++ blk = asm_cipher_be (blk, rkey1); \ ++ blk = asm_cipher_be (blk, rkey2); \ ++ blk = asm_cipher_be (blk, rkey3); \ ++ blk = asm_cipher_be (blk, rkey4); \ ++ blk = asm_cipher_be (blk, rkey5); \ ++ blk = asm_cipher_be (blk, rkey6); \ ++ blk = asm_cipher_be (blk, rkey7); \ ++ blk = asm_cipher_be (blk, rkey8); \ ++ blk = asm_cipher_be (blk, rkey9); \ ++ if (nrounds >= 12) \ ++ { \ ++ blk = asm_cipher_be (blk, rkey10); \ ++ blk = asm_cipher_be (blk, rkey11); \ ++ if (rounds > 12) \ ++ { \ ++ blk = asm_cipher_be (blk, rkey12); \ ++ blk = asm_cipher_be (blk, rkey13); \ ++ } \ ++ } \ ++ blk = asm_cipherlast_be (blk, rkeylast); \ ++ } while (0) ++ ++ ++static ASM_FUNC_ATTR_INLINE block ++asm_aligned_ld(unsigned long offset, const void *ptr) ++{ ++ block vec; ++#if __GNUC__ >= 4 ++ if (__builtin_constant_p (offset) && offset == 0) ++ __asm__ volatile ("lvx %0,0,%1\n\t" ++ : "=v" (vec) ++ : "r" ((uintptr_t)ptr) ++ : "memory"); ++ else ++#endif ++ __asm__ volatile ("lvx %0,%1,%2\n\t" ++ : "=v" (vec) ++ : "r" (offset), "r" ((uintptr_t)ptr) ++ : "memory", "r0"); ++ return vec; ++} ++ ++static ASM_FUNC_ATTR_INLINE void ++asm_aligned_st(block vec, unsigned long offset, void *ptr) ++{ ++#if __GNUC__ >= 4 ++ if (__builtin_constant_p (offset) && offset == 0) ++ __asm__ volatile ("stvx %0,0,%1\n\t" ++ : ++ : "v" (vec), "r" ((uintptr_t)ptr) ++ : "memory"); ++ else ++#endif ++ __asm__ volatile ("stvx %0,%1,%2\n\t" ++ : ++ : "v" (vec), "r" (offset), "r" ((uintptr_t)ptr) ++ : "memory", "r0"); ++} ++ ++static ASM_FUNC_ATTR_INLINE block ++asm_vperm1(block vec, block mask) ++{ ++ block o; ++ __asm__ volatile ("vperm %0,%1,%1,%2\n\t" ++ : "=v" (o) ++ : "v" (vec), "v" (mask)); ++ return o; ++} ++ ++static ASM_FUNC_ATTR_INLINE block ++asm_add_uint128(block a, block b) ++{ ++ block res; ++ __asm__ volatile ("vadduqm %0,%1,%2\n\t" ++ : "=v" (res) ++ : "v" (a), "v" (b)); ++ return res; ++} ++ ++static ASM_FUNC_ATTR_INLINE block ++asm_add_uint64(block a, block b) ++{ ++ block res; ++ __asm__ volatile ("vaddudm %0,%1,%2\n\t" ++ : "=v" (res) ++ : "v" (a), "v" (b)); ++ return res; ++} ++ ++static ASM_FUNC_ATTR_INLINE block ++asm_sra_int64(block a, block b) ++{ ++ block res; ++ __asm__ volatile ("vsrad %0,%1,%2\n\t" ++ : "=v" (res) ++ : "v" (a), "v" (b)); ++ return res; ++} ++ ++static block ++asm_swap_uint64_halfs(block a) ++{ ++ block res; ++ __asm__ volatile ("xxswapd %x0, %x1" ++ : "=wa" (res) ++ : "wa" (a)); ++ return res; ++} ++ ++static ASM_FUNC_ATTR_INLINE block ++asm_xor(block a, block b) ++{ ++ block res; ++ __asm__ volatile ("vxor %0,%1,%2\n\t" ++ : "=v" (res) ++ : "v" (a), "v" (b)); ++ return res; ++} ++ ++static ASM_FUNC_ATTR_INLINE block ++asm_cipher_be(block b, block rk) ++{ ++ block o; ++ __asm__ volatile ("vcipher %0, %1, %2\n\t" ++ : "=v" (o) ++ : "v" (b), "v" (rk)); ++ return o; ++} ++ ++static ASM_FUNC_ATTR_INLINE block ++asm_cipherlast_be(block b, block rk) ++{ ++ block o; ++ __asm__ volatile ("vcipherlast %0, %1, %2\n\t" ++ : "=v" (o) ++ : "v" (b), "v" (rk)); ++ return o; ++} ++ ++static ASM_FUNC_ATTR_INLINE block ++asm_ncipher_be(block b, block rk) ++{ ++ block o; ++ __asm__ volatile ("vncipher %0, %1, %2\n\t" ++ : "=v" (o) ++ : "v" (b), "v" (rk)); ++ return o; ++} ++ ++static ASM_FUNC_ATTR_INLINE block ++asm_ncipherlast_be(block b, block rk) ++{ ++ block o; ++ __asm__ volatile ("vncipherlast %0, %1, %2\n\t" ++ : "=v" (o) ++ : "v" (b), "v" (rk)); ++ return o; ++} ++ ++ ++/* Make a decryption key from an encryption key. */ ++static ASM_FUNC_ATTR_INLINE void ++internal_aes_ppc_prepare_decryption (RIJNDAEL_context *ctx) ++{ ++ u128_t *ekey = (u128_t *)(void *)ctx->keyschenc; ++ u128_t *dkey = (u128_t *)(void *)ctx->keyschdec; ++ int rounds = ctx->rounds; ++ int rr; ++ int r; ++ ++ r = 0; ++ rr = rounds; ++ for (r = 0, rr = rounds; r <= rounds; r++, rr--) ++ { ++ ALIGNED_STORE (dkey, r, ALIGNED_LOAD (ekey, rr)); ++ } ++} ++ ++#endif /* G10_RIJNDAEL_PPC_COMMON_H */ +diff -up libgcrypt-1.8.5/cipher/rijndael-ppc-functions.h.aes-perf libgcrypt-1.8.5/cipher/rijndael-ppc-functions.h +--- libgcrypt-1.8.5/cipher/rijndael-ppc-functions.h.aes-perf 2020-04-22 18:29:41.679862057 +0200 ++++ libgcrypt-1.8.5/cipher/rijndael-ppc-functions.h 2020-04-22 18:29:41.679862057 +0200 +@@ -0,0 +1,2020 @@ ++/* Rijndael (AES) for GnuPG - PowerPC Vector Crypto AES implementation ++ * Copyright (C) 2019 Shawn Landden ++ * Copyright (C) 2019-2020 Jussi Kivilinna ++ * ++ * 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 . ++ * ++ * Alternatively, this code may be used in OpenSSL from The OpenSSL Project, ++ * and Cryptogams by Andy Polyakov, and if made part of a release of either ++ * or both projects, is thereafter dual-licensed under the license said project ++ * is released under. ++ */ ++ ++unsigned int ENCRYPT_BLOCK_FUNC (const RIJNDAEL_context *ctx, ++ unsigned char *out, ++ const unsigned char *in) ++{ ++ const block bige_const = asm_load_be_const(); ++ const u128_t *rk = (u128_t *)&ctx->keyschenc; ++ int rounds = ctx->rounds; ++ ROUND_KEY_VARIABLES; ++ block b; ++ ++ b = VEC_LOAD_BE (in, 0, bige_const); ++ ++ PRELOAD_ROUND_KEYS (rounds); ++ ++ AES_ENCRYPT (b, rounds); ++ VEC_STORE_BE (out, 0, b, bige_const); ++ ++ return 0; /* does not use stack */ ++} ++ ++ ++unsigned int DECRYPT_BLOCK_FUNC (const RIJNDAEL_context *ctx, ++ unsigned char *out, ++ const unsigned char *in) ++{ ++ const block bige_const = asm_load_be_const(); ++ const u128_t *rk = (u128_t *)&ctx->keyschdec; ++ int rounds = ctx->rounds; ++ ROUND_KEY_VARIABLES; ++ block b; ++ ++ b = VEC_LOAD_BE (in, 0, bige_const); ++ ++ PRELOAD_ROUND_KEYS (rounds); ++ ++ AES_DECRYPT (b, rounds); ++ VEC_STORE_BE (out, 0, b, bige_const); ++ ++ return 0; /* does not use stack */ ++} ++ ++ ++void CFB_ENC_FUNC (void *context, unsigned char *iv_arg, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks) ++{ ++ const block bige_const = asm_load_be_const(); ++ RIJNDAEL_context *ctx = context; ++ const u128_t *rk = (u128_t *)&ctx->keyschenc; ++ const u128_t *in = (const u128_t *)inbuf_arg; ++ u128_t *out = (u128_t *)outbuf_arg; ++ int rounds = ctx->rounds; ++ ROUND_KEY_VARIABLES_ALL; ++ block rkeylast_orig; ++ block iv; ++ ++ iv = VEC_LOAD_BE (iv_arg, 0, bige_const); ++ ++ PRELOAD_ROUND_KEYS_ALL (rounds); ++ rkeylast_orig = rkeylast; ++ ++ for (; nblocks >= 2; nblocks -= 2) ++ { ++ block in2, iv1; ++ ++ rkeylast = rkeylast_orig ^ VEC_LOAD_BE (in, 0, bige_const); ++ in2 = VEC_LOAD_BE (in + 1, 0, bige_const); ++ in += 2; ++ ++ AES_ENCRYPT_ALL (iv, rounds); ++ ++ iv1 = iv; ++ rkeylast = rkeylast_orig ^ in2; ++ ++ AES_ENCRYPT_ALL (iv, rounds); ++ ++ VEC_STORE_BE (out++, 0, iv1, bige_const); ++ VEC_STORE_BE (out++, 0, iv, bige_const); ++ } ++ ++ for (; nblocks; nblocks--) ++ { ++ rkeylast = rkeylast_orig ^ VEC_LOAD_BE (in++, 0, bige_const); ++ ++ AES_ENCRYPT_ALL (iv, rounds); ++ ++ VEC_STORE_BE (out++, 0, iv, bige_const); ++ } ++ ++ VEC_STORE_BE (iv_arg, 0, iv, bige_const); ++} ++ ++void CFB_DEC_FUNC (void *context, unsigned char *iv_arg, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks) ++{ ++ const block bige_const = asm_load_be_const(); ++ RIJNDAEL_context *ctx = context; ++ const u128_t *rk = (u128_t *)&ctx->keyschenc; ++ const u128_t *in = (const u128_t *)inbuf_arg; ++ u128_t *out = (u128_t *)outbuf_arg; ++ int rounds = ctx->rounds; ++ ROUND_KEY_VARIABLES; ++ block rkeylast_orig; ++ block iv, b, bin; ++ block in0, in1, in2, in3, in4, in5, in6, in7; ++ block b0, b1, b2, b3, b4, b5, b6, b7; ++ block rkey; ++ ++ iv = VEC_LOAD_BE (iv_arg, 0, bige_const); ++ ++ PRELOAD_ROUND_KEYS (rounds); ++ rkeylast_orig = rkeylast; ++ ++ for (; nblocks >= 8; nblocks -= 8) ++ { ++ in0 = iv; ++ in1 = VEC_LOAD_BE_NOSWAP (in, 0); ++ in2 = VEC_LOAD_BE_NOSWAP (in, 1); ++ in3 = VEC_LOAD_BE_NOSWAP (in, 2); ++ in4 = VEC_LOAD_BE_NOSWAP (in, 3); ++ in1 = VEC_BE_SWAP (in1, bige_const); ++ in2 = VEC_BE_SWAP (in2, bige_const); ++ in5 = VEC_LOAD_BE_NOSWAP (in, 4); ++ in6 = VEC_LOAD_BE_NOSWAP (in, 5); ++ in3 = VEC_BE_SWAP (in3, bige_const); ++ in4 = VEC_BE_SWAP (in4, bige_const); ++ in7 = VEC_LOAD_BE_NOSWAP (in, 6); ++ iv = VEC_LOAD_BE_NOSWAP (in, 7); ++ in += 8; ++ in5 = VEC_BE_SWAP (in5, bige_const); ++ in6 = VEC_BE_SWAP (in6, bige_const); ++ b0 = asm_xor (rkey0, in0); ++ b1 = asm_xor (rkey0, in1); ++ in7 = VEC_BE_SWAP (in7, bige_const); ++ iv = VEC_BE_SWAP (iv, bige_const); ++ b2 = asm_xor (rkey0, in2); ++ b3 = asm_xor (rkey0, in3); ++ b4 = asm_xor (rkey0, in4); ++ b5 = asm_xor (rkey0, in5); ++ b6 = asm_xor (rkey0, in6); ++ b7 = asm_xor (rkey0, in7); ++ ++#define DO_ROUND(r) \ ++ rkey = ALIGNED_LOAD (rk, r); \ ++ b0 = asm_cipher_be (b0, rkey); \ ++ b1 = asm_cipher_be (b1, rkey); \ ++ b2 = asm_cipher_be (b2, rkey); \ ++ b3 = asm_cipher_be (b3, rkey); \ ++ b4 = asm_cipher_be (b4, rkey); \ ++ b5 = asm_cipher_be (b5, rkey); \ ++ b6 = asm_cipher_be (b6, rkey); \ ++ b7 = asm_cipher_be (b7, rkey); ++ ++ DO_ROUND(1); ++ DO_ROUND(2); ++ DO_ROUND(3); ++ DO_ROUND(4); ++ DO_ROUND(5); ++ DO_ROUND(6); ++ DO_ROUND(7); ++ DO_ROUND(8); ++ DO_ROUND(9); ++ if (rounds >= 12) ++ { ++ DO_ROUND(10); ++ DO_ROUND(11); ++ if (rounds > 12) ++ { ++ DO_ROUND(12); ++ DO_ROUND(13); ++ } ++ } ++ ++#undef DO_ROUND ++ ++ in1 = asm_xor (rkeylast, in1); ++ in2 = asm_xor (rkeylast, in2); ++ in3 = asm_xor (rkeylast, in3); ++ in4 = asm_xor (rkeylast, in4); ++ b0 = asm_cipherlast_be (b0, in1); ++ b1 = asm_cipherlast_be (b1, in2); ++ in5 = asm_xor (rkeylast, in5); ++ in6 = asm_xor (rkeylast, in6); ++ b2 = asm_cipherlast_be (b2, in3); ++ b3 = asm_cipherlast_be (b3, in4); ++ in7 = asm_xor (rkeylast, in7); ++ in0 = asm_xor (rkeylast, iv); ++ b0 = VEC_BE_SWAP (b0, bige_const); ++ b1 = VEC_BE_SWAP (b1, bige_const); ++ b4 = asm_cipherlast_be (b4, in5); ++ b5 = asm_cipherlast_be (b5, in6); ++ b2 = VEC_BE_SWAP (b2, bige_const); ++ b3 = VEC_BE_SWAP (b3, bige_const); ++ b6 = asm_cipherlast_be (b6, in7); ++ b7 = asm_cipherlast_be (b7, in0); ++ b4 = VEC_BE_SWAP (b4, bige_const); ++ b5 = VEC_BE_SWAP (b5, bige_const); ++ b6 = VEC_BE_SWAP (b6, bige_const); ++ b7 = VEC_BE_SWAP (b7, bige_const); ++ VEC_STORE_BE_NOSWAP (out, 0, b0); ++ VEC_STORE_BE_NOSWAP (out, 1, b1); ++ VEC_STORE_BE_NOSWAP (out, 2, b2); ++ VEC_STORE_BE_NOSWAP (out, 3, b3); ++ VEC_STORE_BE_NOSWAP (out, 4, b4); ++ VEC_STORE_BE_NOSWAP (out, 5, b5); ++ VEC_STORE_BE_NOSWAP (out, 6, b6); ++ VEC_STORE_BE_NOSWAP (out, 7, b7); ++ out += 8; ++ } ++ ++ if (nblocks >= 4) ++ { ++ in0 = iv; ++ in1 = VEC_LOAD_BE (in, 0, bige_const); ++ in2 = VEC_LOAD_BE (in, 1, bige_const); ++ in3 = VEC_LOAD_BE (in, 2, bige_const); ++ iv = VEC_LOAD_BE (in, 3, bige_const); ++ ++ b0 = asm_xor (rkey0, in0); ++ b1 = asm_xor (rkey0, in1); ++ b2 = asm_xor (rkey0, in2); ++ b3 = asm_xor (rkey0, in3); ++ ++#define DO_ROUND(r) \ ++ rkey = ALIGNED_LOAD (rk, r); \ ++ b0 = asm_cipher_be (b0, rkey); \ ++ b1 = asm_cipher_be (b1, rkey); \ ++ b2 = asm_cipher_be (b2, rkey); \ ++ b3 = asm_cipher_be (b3, rkey); ++ ++ DO_ROUND(1); ++ DO_ROUND(2); ++ DO_ROUND(3); ++ DO_ROUND(4); ++ DO_ROUND(5); ++ DO_ROUND(6); ++ DO_ROUND(7); ++ DO_ROUND(8); ++ DO_ROUND(9); ++ if (rounds >= 12) ++ { ++ DO_ROUND(10); ++ DO_ROUND(11); ++ if (rounds > 12) ++ { ++ DO_ROUND(12); ++ DO_ROUND(13); ++ } ++ } ++ ++#undef DO_ROUND ++ ++ in1 = asm_xor (rkeylast, in1); ++ in2 = asm_xor (rkeylast, in2); ++ in3 = asm_xor (rkeylast, in3); ++ in0 = asm_xor (rkeylast, iv); ++ b0 = asm_cipherlast_be (b0, in1); ++ b1 = asm_cipherlast_be (b1, in2); ++ b2 = asm_cipherlast_be (b2, in3); ++ b3 = asm_cipherlast_be (b3, in0); ++ VEC_STORE_BE (out, 0, b0, bige_const); ++ VEC_STORE_BE (out, 1, b1, bige_const); ++ VEC_STORE_BE (out, 2, b2, bige_const); ++ VEC_STORE_BE (out, 3, b3, bige_const); ++ ++ in += 4; ++ out += 4; ++ nblocks -= 4; ++ } ++ ++ for (; nblocks; nblocks--) ++ { ++ bin = VEC_LOAD_BE (in, 0, bige_const); ++ rkeylast = rkeylast_orig ^ bin; ++ b = iv; ++ iv = bin; ++ ++ AES_ENCRYPT (b, rounds); ++ ++ VEC_STORE_BE (out, 0, b, bige_const); ++ ++ out++; ++ in++; ++ } ++ ++ VEC_STORE_BE (iv_arg, 0, iv, bige_const); ++} ++ ++ ++void CBC_ENC_FUNC (void *context, unsigned char *iv_arg, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks, int cbc_mac) ++{ ++ const block bige_const = asm_load_be_const(); ++ RIJNDAEL_context *ctx = context; ++ const u128_t *rk = (u128_t *)&ctx->keyschenc; ++ const u128_t *in = (const u128_t *)inbuf_arg; ++ byte *out = (byte *)outbuf_arg; ++ int rounds = ctx->rounds; ++ ROUND_KEY_VARIABLES_ALL; ++ block lastiv, b; ++ unsigned int outadd = -(!cbc_mac) & 16; ++ ++ lastiv = VEC_LOAD_BE (iv_arg, 0, bige_const); ++ ++ PRELOAD_ROUND_KEYS_ALL (rounds); ++ ++ for (; nblocks >= 2; nblocks -= 2) ++ { ++ block in2, lastiv1; ++ ++ b = lastiv ^ VEC_LOAD_BE (in, 0, bige_const); ++ in2 = VEC_LOAD_BE (in + 1, 0, bige_const); ++ in += 2; ++ ++ AES_ENCRYPT_ALL (b, rounds); ++ ++ lastiv1 = b; ++ b = lastiv1 ^ in2; ++ ++ AES_ENCRYPT_ALL (b, rounds); ++ ++ lastiv = b; ++ VEC_STORE_BE ((u128_t *)out, 0, lastiv1, bige_const); ++ out += outadd; ++ VEC_STORE_BE ((u128_t *)out, 0, lastiv, bige_const); ++ out += outadd; ++ } ++ ++ for (; nblocks; nblocks--) ++ { ++ b = lastiv ^ VEC_LOAD_BE (in++, 0, bige_const); ++ ++ AES_ENCRYPT_ALL (b, rounds); ++ ++ lastiv = b; ++ VEC_STORE_BE ((u128_t *)out, 0, b, bige_const); ++ out += outadd; ++ } ++ ++ VEC_STORE_BE (iv_arg, 0, lastiv, bige_const); ++} ++ ++void CBC_DEC_FUNC (void *context, unsigned char *iv_arg, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks) ++{ ++ const block bige_const = asm_load_be_const(); ++ RIJNDAEL_context *ctx = context; ++ const u128_t *rk = (u128_t *)&ctx->keyschdec; ++ const u128_t *in = (const u128_t *)inbuf_arg; ++ u128_t *out = (u128_t *)outbuf_arg; ++ int rounds = ctx->rounds; ++ ROUND_KEY_VARIABLES; ++ block rkeylast_orig; ++ block in0, in1, in2, in3, in4, in5, in6, in7; ++ block b0, b1, b2, b3, b4, b5, b6, b7; ++ block rkey; ++ block iv, b; ++ ++ if (!ctx->decryption_prepared) ++ { ++ internal_aes_ppc_prepare_decryption (ctx); ++ ctx->decryption_prepared = 1; ++ } ++ ++ iv = VEC_LOAD_BE (iv_arg, 0, bige_const); ++ ++ PRELOAD_ROUND_KEYS (rounds); ++ rkeylast_orig = rkeylast; ++ ++ for (; nblocks >= 8; nblocks -= 8) ++ { ++ in0 = VEC_LOAD_BE_NOSWAP (in, 0); ++ in1 = VEC_LOAD_BE_NOSWAP (in, 1); ++ in2 = VEC_LOAD_BE_NOSWAP (in, 2); ++ in3 = VEC_LOAD_BE_NOSWAP (in, 3); ++ in0 = VEC_BE_SWAP (in0, bige_const); ++ in1 = VEC_BE_SWAP (in1, bige_const); ++ in4 = VEC_LOAD_BE_NOSWAP (in, 4); ++ in5 = VEC_LOAD_BE_NOSWAP (in, 5); ++ in2 = VEC_BE_SWAP (in2, bige_const); ++ in3 = VEC_BE_SWAP (in3, bige_const); ++ in6 = VEC_LOAD_BE_NOSWAP (in, 6); ++ in7 = VEC_LOAD_BE_NOSWAP (in, 7); ++ in += 8; ++ b0 = asm_xor (rkey0, in0); ++ b1 = asm_xor (rkey0, in1); ++ in4 = VEC_BE_SWAP (in4, bige_const); ++ in5 = VEC_BE_SWAP (in5, bige_const); ++ b2 = asm_xor (rkey0, in2); ++ b3 = asm_xor (rkey0, in3); ++ in6 = VEC_BE_SWAP (in6, bige_const); ++ in7 = VEC_BE_SWAP (in7, bige_const); ++ b4 = asm_xor (rkey0, in4); ++ b5 = asm_xor (rkey0, in5); ++ b6 = asm_xor (rkey0, in6); ++ b7 = asm_xor (rkey0, in7); ++ ++#define DO_ROUND(r) \ ++ rkey = ALIGNED_LOAD (rk, r); \ ++ b0 = asm_ncipher_be (b0, rkey); \ ++ b1 = asm_ncipher_be (b1, rkey); \ ++ b2 = asm_ncipher_be (b2, rkey); \ ++ b3 = asm_ncipher_be (b3, rkey); \ ++ b4 = asm_ncipher_be (b4, rkey); \ ++ b5 = asm_ncipher_be (b5, rkey); \ ++ b6 = asm_ncipher_be (b6, rkey); \ ++ b7 = asm_ncipher_be (b7, rkey); ++ ++ DO_ROUND(1); ++ DO_ROUND(2); ++ DO_ROUND(3); ++ DO_ROUND(4); ++ DO_ROUND(5); ++ DO_ROUND(6); ++ DO_ROUND(7); ++ DO_ROUND(8); ++ DO_ROUND(9); ++ if (rounds >= 12) ++ { ++ DO_ROUND(10); ++ DO_ROUND(11); ++ if (rounds > 12) ++ { ++ DO_ROUND(12); ++ DO_ROUND(13); ++ } ++ } ++ ++#undef DO_ROUND ++ ++ iv = asm_xor (rkeylast, iv); ++ in0 = asm_xor (rkeylast, in0); ++ in1 = asm_xor (rkeylast, in1); ++ in2 = asm_xor (rkeylast, in2); ++ b0 = asm_ncipherlast_be (b0, iv); ++ iv = in7; ++ b1 = asm_ncipherlast_be (b1, in0); ++ in3 = asm_xor (rkeylast, in3); ++ in4 = asm_xor (rkeylast, in4); ++ b2 = asm_ncipherlast_be (b2, in1); ++ b3 = asm_ncipherlast_be (b3, in2); ++ in5 = asm_xor (rkeylast, in5); ++ in6 = asm_xor (rkeylast, in6); ++ b0 = VEC_BE_SWAP (b0, bige_const); ++ b1 = VEC_BE_SWAP (b1, bige_const); ++ b4 = asm_ncipherlast_be (b4, in3); ++ b5 = asm_ncipherlast_be (b5, in4); ++ b2 = VEC_BE_SWAP (b2, bige_const); ++ b3 = VEC_BE_SWAP (b3, bige_const); ++ b6 = asm_ncipherlast_be (b6, in5); ++ b7 = asm_ncipherlast_be (b7, in6); ++ b4 = VEC_BE_SWAP (b4, bige_const); ++ b5 = VEC_BE_SWAP (b5, bige_const); ++ b6 = VEC_BE_SWAP (b6, bige_const); ++ b7 = VEC_BE_SWAP (b7, bige_const); ++ VEC_STORE_BE_NOSWAP (out, 0, b0); ++ VEC_STORE_BE_NOSWAP (out, 1, b1); ++ VEC_STORE_BE_NOSWAP (out, 2, b2); ++ VEC_STORE_BE_NOSWAP (out, 3, b3); ++ VEC_STORE_BE_NOSWAP (out, 4, b4); ++ VEC_STORE_BE_NOSWAP (out, 5, b5); ++ VEC_STORE_BE_NOSWAP (out, 6, b6); ++ VEC_STORE_BE_NOSWAP (out, 7, b7); ++ out += 8; ++ } ++ ++ if (nblocks >= 4) ++ { ++ in0 = VEC_LOAD_BE (in, 0, bige_const); ++ in1 = VEC_LOAD_BE (in, 1, bige_const); ++ in2 = VEC_LOAD_BE (in, 2, bige_const); ++ in3 = VEC_LOAD_BE (in, 3, bige_const); ++ ++ b0 = asm_xor (rkey0, in0); ++ b1 = asm_xor (rkey0, in1); ++ b2 = asm_xor (rkey0, in2); ++ b3 = asm_xor (rkey0, in3); ++ ++#define DO_ROUND(r) \ ++ rkey = ALIGNED_LOAD (rk, r); \ ++ b0 = asm_ncipher_be (b0, rkey); \ ++ b1 = asm_ncipher_be (b1, rkey); \ ++ b2 = asm_ncipher_be (b2, rkey); \ ++ b3 = asm_ncipher_be (b3, rkey); ++ ++ DO_ROUND(1); ++ DO_ROUND(2); ++ DO_ROUND(3); ++ DO_ROUND(4); ++ DO_ROUND(5); ++ DO_ROUND(6); ++ DO_ROUND(7); ++ DO_ROUND(8); ++ DO_ROUND(9); ++ if (rounds >= 12) ++ { ++ DO_ROUND(10); ++ DO_ROUND(11); ++ if (rounds > 12) ++ { ++ DO_ROUND(12); ++ DO_ROUND(13); ++ } ++ } ++ ++#undef DO_ROUND ++ ++ iv = asm_xor (rkeylast, iv); ++ in0 = asm_xor (rkeylast, in0); ++ in1 = asm_xor (rkeylast, in1); ++ in2 = asm_xor (rkeylast, in2); ++ ++ b0 = asm_ncipherlast_be (b0, iv); ++ iv = in3; ++ b1 = asm_ncipherlast_be (b1, in0); ++ b2 = asm_ncipherlast_be (b2, in1); ++ b3 = asm_ncipherlast_be (b3, in2); ++ ++ VEC_STORE_BE (out, 0, b0, bige_const); ++ VEC_STORE_BE (out, 1, b1, bige_const); ++ VEC_STORE_BE (out, 2, b2, bige_const); ++ VEC_STORE_BE (out, 3, b3, bige_const); ++ ++ in += 4; ++ out += 4; ++ nblocks -= 4; ++ } ++ ++ for (; nblocks; nblocks--) ++ { ++ rkeylast = rkeylast_orig ^ iv; ++ ++ iv = VEC_LOAD_BE (in, 0, bige_const); ++ b = iv; ++ AES_DECRYPT (b, rounds); ++ ++ VEC_STORE_BE (out, 0, b, bige_const); ++ ++ in++; ++ out++; ++ } ++ ++ VEC_STORE_BE (iv_arg, 0, iv, bige_const); ++} ++ ++ ++void CTR_ENC_FUNC (void *context, unsigned char *ctr_arg, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks) ++{ ++ static const unsigned char vec_one_const[16] = ++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; ++ const block bige_const = asm_load_be_const(); ++ RIJNDAEL_context *ctx = context; ++ const u128_t *rk = (u128_t *)&ctx->keyschenc; ++ const u128_t *in = (const u128_t *)inbuf_arg; ++ u128_t *out = (u128_t *)outbuf_arg; ++ int rounds = ctx->rounds; ++ ROUND_KEY_VARIABLES; ++ block rkeylast_orig; ++ block ctr, b, one; ++ ++ ctr = VEC_LOAD_BE (ctr_arg, 0, bige_const); ++ one = VEC_LOAD_BE (&vec_one_const, 0, bige_const); ++ ++ PRELOAD_ROUND_KEYS (rounds); ++ rkeylast_orig = rkeylast; ++ ++ if (nblocks >= 4) ++ { ++ block in0, in1, in2, in3, in4, in5, in6, in7; ++ block b0, b1, b2, b3, b4, b5, b6, b7; ++ block two, three, four; ++ block rkey; ++ ++ two = asm_add_uint128 (one, one); ++ three = asm_add_uint128 (two, one); ++ four = asm_add_uint128 (two, two); ++ ++ for (; nblocks >= 8; nblocks -= 8) ++ { ++ b1 = asm_add_uint128 (ctr, one); ++ b2 = asm_add_uint128 (ctr, two); ++ b3 = asm_add_uint128 (ctr, three); ++ b4 = asm_add_uint128 (ctr, four); ++ b5 = asm_add_uint128 (b1, four); ++ b6 = asm_add_uint128 (b2, four); ++ b7 = asm_add_uint128 (b3, four); ++ b0 = asm_xor (rkey0, ctr); ++ rkey = ALIGNED_LOAD (rk, 1); ++ ctr = asm_add_uint128 (b4, four); ++ b1 = asm_xor (rkey0, b1); ++ b2 = asm_xor (rkey0, b2); ++ b3 = asm_xor (rkey0, b3); ++ b0 = asm_cipher_be (b0, rkey); ++ b1 = asm_cipher_be (b1, rkey); ++ b2 = asm_cipher_be (b2, rkey); ++ b3 = asm_cipher_be (b3, rkey); ++ b4 = asm_xor (rkey0, b4); ++ b5 = asm_xor (rkey0, b5); ++ b6 = asm_xor (rkey0, b6); ++ b7 = asm_xor (rkey0, b7); ++ b4 = asm_cipher_be (b4, rkey); ++ b5 = asm_cipher_be (b5, rkey); ++ b6 = asm_cipher_be (b6, rkey); ++ b7 = asm_cipher_be (b7, rkey); ++ ++#define DO_ROUND(r) \ ++ rkey = ALIGNED_LOAD (rk, r); \ ++ b0 = asm_cipher_be (b0, rkey); \ ++ b1 = asm_cipher_be (b1, rkey); \ ++ b2 = asm_cipher_be (b2, rkey); \ ++ b3 = asm_cipher_be (b3, rkey); \ ++ b4 = asm_cipher_be (b4, rkey); \ ++ b5 = asm_cipher_be (b5, rkey); \ ++ b6 = asm_cipher_be (b6, rkey); \ ++ b7 = asm_cipher_be (b7, rkey); ++ ++ in0 = VEC_LOAD_BE_NOSWAP (in, 0); ++ DO_ROUND(2); ++ in1 = VEC_LOAD_BE_NOSWAP (in, 1); ++ DO_ROUND(3); ++ in2 = VEC_LOAD_BE_NOSWAP (in, 2); ++ DO_ROUND(4); ++ in3 = VEC_LOAD_BE_NOSWAP (in, 3); ++ DO_ROUND(5); ++ in4 = VEC_LOAD_BE_NOSWAP (in, 4); ++ DO_ROUND(6); ++ in5 = VEC_LOAD_BE_NOSWAP (in, 5); ++ DO_ROUND(7); ++ in6 = VEC_LOAD_BE_NOSWAP (in, 6); ++ DO_ROUND(8); ++ in7 = VEC_LOAD_BE_NOSWAP (in, 7); ++ in += 8; ++ DO_ROUND(9); ++ ++ if (rounds >= 12) ++ { ++ DO_ROUND(10); ++ DO_ROUND(11); ++ if (rounds > 12) ++ { ++ DO_ROUND(12); ++ DO_ROUND(13); ++ } ++ } ++ ++#undef DO_ROUND ++ ++ in0 = VEC_BE_SWAP (in0, bige_const); ++ in1 = VEC_BE_SWAP (in1, bige_const); ++ in2 = VEC_BE_SWAP (in2, bige_const); ++ in3 = VEC_BE_SWAP (in3, bige_const); ++ in4 = VEC_BE_SWAP (in4, bige_const); ++ in5 = VEC_BE_SWAP (in5, bige_const); ++ in6 = VEC_BE_SWAP (in6, bige_const); ++ in7 = VEC_BE_SWAP (in7, bige_const); ++ ++ in0 = asm_xor (rkeylast, in0); ++ in1 = asm_xor (rkeylast, in1); ++ in2 = asm_xor (rkeylast, in2); ++ in3 = asm_xor (rkeylast, in3); ++ b0 = asm_cipherlast_be (b0, in0); ++ b1 = asm_cipherlast_be (b1, in1); ++ in4 = asm_xor (rkeylast, in4); ++ in5 = asm_xor (rkeylast, in5); ++ b2 = asm_cipherlast_be (b2, in2); ++ b3 = asm_cipherlast_be (b3, in3); ++ in6 = asm_xor (rkeylast, in6); ++ in7 = asm_xor (rkeylast, in7); ++ b4 = asm_cipherlast_be (b4, in4); ++ b5 = asm_cipherlast_be (b5, in5); ++ b6 = asm_cipherlast_be (b6, in6); ++ b7 = asm_cipherlast_be (b7, in7); ++ ++ b0 = VEC_BE_SWAP (b0, bige_const); ++ b1 = VEC_BE_SWAP (b1, bige_const); ++ b2 = VEC_BE_SWAP (b2, bige_const); ++ b3 = VEC_BE_SWAP (b3, bige_const); ++ b4 = VEC_BE_SWAP (b4, bige_const); ++ b5 = VEC_BE_SWAP (b5, bige_const); ++ b6 = VEC_BE_SWAP (b6, bige_const); ++ b7 = VEC_BE_SWAP (b7, bige_const); ++ VEC_STORE_BE_NOSWAP (out, 0, b0); ++ VEC_STORE_BE_NOSWAP (out, 1, b1); ++ VEC_STORE_BE_NOSWAP (out, 2, b2); ++ VEC_STORE_BE_NOSWAP (out, 3, b3); ++ VEC_STORE_BE_NOSWAP (out, 4, b4); ++ VEC_STORE_BE_NOSWAP (out, 5, b5); ++ VEC_STORE_BE_NOSWAP (out, 6, b6); ++ VEC_STORE_BE_NOSWAP (out, 7, b7); ++ out += 8; ++ } ++ ++ if (nblocks >= 4) ++ { ++ b1 = asm_add_uint128 (ctr, one); ++ b2 = asm_add_uint128 (ctr, two); ++ b3 = asm_add_uint128 (ctr, three); ++ b0 = asm_xor (rkey0, ctr); ++ ctr = asm_add_uint128 (ctr, four); ++ b1 = asm_xor (rkey0, b1); ++ b2 = asm_xor (rkey0, b2); ++ b3 = asm_xor (rkey0, b3); ++ ++#define DO_ROUND(r) \ ++ rkey = ALIGNED_LOAD (rk, r); \ ++ b0 = asm_cipher_be (b0, rkey); \ ++ b1 = asm_cipher_be (b1, rkey); \ ++ b2 = asm_cipher_be (b2, rkey); \ ++ b3 = asm_cipher_be (b3, rkey); ++ ++ DO_ROUND(1); ++ DO_ROUND(2); ++ DO_ROUND(3); ++ DO_ROUND(4); ++ DO_ROUND(5); ++ DO_ROUND(6); ++ DO_ROUND(7); ++ DO_ROUND(8); ++ ++ in0 = VEC_LOAD_BE (in, 0, bige_const); ++ in1 = VEC_LOAD_BE (in, 1, bige_const); ++ in2 = VEC_LOAD_BE (in, 2, bige_const); ++ in3 = VEC_LOAD_BE (in, 3, bige_const); ++ ++ DO_ROUND(9); ++ if (rounds >= 12) ++ { ++ DO_ROUND(10); ++ DO_ROUND(11); ++ if (rounds > 12) ++ { ++ DO_ROUND(12); ++ DO_ROUND(13); ++ } ++ } ++ ++#undef DO_ROUND ++ ++ in0 = asm_xor (rkeylast, in0); ++ in1 = asm_xor (rkeylast, in1); ++ in2 = asm_xor (rkeylast, in2); ++ in3 = asm_xor (rkeylast, in3); ++ ++ b0 = asm_cipherlast_be (b0, in0); ++ b1 = asm_cipherlast_be (b1, in1); ++ b2 = asm_cipherlast_be (b2, in2); ++ b3 = asm_cipherlast_be (b3, in3); ++ ++ VEC_STORE_BE (out, 0, b0, bige_const); ++ VEC_STORE_BE (out, 1, b1, bige_const); ++ VEC_STORE_BE (out, 2, b2, bige_const); ++ VEC_STORE_BE (out, 3, b3, bige_const); ++ ++ in += 4; ++ out += 4; ++ nblocks -= 4; ++ } ++ } ++ ++ for (; nblocks; nblocks--) ++ { ++ b = ctr; ++ ctr = asm_add_uint128 (ctr, one); ++ rkeylast = rkeylast_orig ^ VEC_LOAD_BE (in, 0, bige_const); ++ ++ AES_ENCRYPT (b, rounds); ++ ++ VEC_STORE_BE (out, 0, b, bige_const); ++ ++ out++; ++ in++; ++ } ++ ++ VEC_STORE_BE (ctr_arg, 0, ctr, bige_const); ++} ++ ++ ++size_t OCB_CRYPT_FUNC (gcry_cipher_hd_t c, void *outbuf_arg, ++ const void *inbuf_arg, size_t nblocks, ++ int encrypt) ++{ ++ const block bige_const = asm_load_be_const(); ++ RIJNDAEL_context *ctx = (void *)&c->context.c; ++ const u128_t *in = (const u128_t *)inbuf_arg; ++ u128_t *out = (u128_t *)outbuf_arg; ++ int rounds = ctx->rounds; ++ u64 data_nblocks = c->u_mode.ocb.data_nblocks; ++ block l0, l1, l2, l; ++ block b0, b1, b2, b3, b4, b5, b6, b7, b; ++ block iv0, iv1, iv2, iv3, iv4, iv5, iv6, iv7; ++ block rkey, rkeylf; ++ block ctr, iv; ++ ROUND_KEY_VARIABLES; ++ ++ iv = VEC_LOAD_BE (c->u_iv.iv, 0, bige_const); ++ ctr = VEC_LOAD_BE (c->u_ctr.ctr, 0, bige_const); ++ ++ l0 = VEC_LOAD_BE (c->u_mode.ocb.L[0], 0, bige_const); ++ l1 = VEC_LOAD_BE (c->u_mode.ocb.L[1], 0, bige_const); ++ l2 = VEC_LOAD_BE (c->u_mode.ocb.L[2], 0, bige_const); ++ ++ if (encrypt) ++ { ++ const u128_t *rk = (u128_t *)&ctx->keyschenc; ++ ++ PRELOAD_ROUND_KEYS (rounds); ++ ++ for (; nblocks >= 8 && data_nblocks % 8; nblocks--) ++ { ++ l = VEC_LOAD_BE (ocb_get_l (c, ++data_nblocks), 0, bige_const); ++ b = VEC_LOAD_BE (in, 0, bige_const); ++ ++ /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ ++ iv ^= l; ++ /* Checksum_i = Checksum_{i-1} xor P_i */ ++ ctr ^= b; ++ /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */ ++ b ^= iv; ++ AES_ENCRYPT (b, rounds); ++ b ^= iv; ++ ++ VEC_STORE_BE (out, 0, b, bige_const); ++ ++ in += 1; ++ out += 1; ++ } ++ ++ for (; nblocks >= 8; nblocks -= 8) ++ { ++ b0 = VEC_LOAD_BE_NOSWAP (in, 0); ++ b1 = VEC_LOAD_BE_NOSWAP (in, 1); ++ b2 = VEC_LOAD_BE_NOSWAP (in, 2); ++ b3 = VEC_LOAD_BE_NOSWAP (in, 3); ++ b4 = VEC_LOAD_BE_NOSWAP (in, 4); ++ b5 = VEC_LOAD_BE_NOSWAP (in, 5); ++ b6 = VEC_LOAD_BE_NOSWAP (in, 6); ++ b7 = VEC_LOAD_BE_NOSWAP (in, 7); ++ in += 8; ++ l = VEC_LOAD_BE_NOSWAP (ocb_get_l (c, data_nblocks += 8), 0); ++ b0 = VEC_BE_SWAP(b0, bige_const); ++ b1 = VEC_BE_SWAP(b1, bige_const); ++ b2 = VEC_BE_SWAP(b2, bige_const); ++ b3 = VEC_BE_SWAP(b3, bige_const); ++ b4 = VEC_BE_SWAP(b4, bige_const); ++ b5 = VEC_BE_SWAP(b5, bige_const); ++ b6 = VEC_BE_SWAP(b6, bige_const); ++ b7 = VEC_BE_SWAP(b7, bige_const); ++ l = VEC_BE_SWAP(l, bige_const); ++ ++ ctr ^= b0 ^ b1 ^ b2 ^ b3 ^ b4 ^ b5 ^ b6 ^ b7; ++ ++ iv ^= rkey0; ++ ++ iv0 = iv ^ l0; ++ iv1 = iv ^ l0 ^ l1; ++ iv2 = iv ^ l1; ++ iv3 = iv ^ l1 ^ l2; ++ iv4 = iv ^ l1 ^ l2 ^ l0; ++ iv5 = iv ^ l2 ^ l0; ++ iv6 = iv ^ l2; ++ iv7 = iv ^ l2 ^ l; ++ ++ b0 ^= iv0; ++ b1 ^= iv1; ++ b2 ^= iv2; ++ b3 ^= iv3; ++ b4 ^= iv4; ++ b5 ^= iv5; ++ b6 ^= iv6; ++ b7 ^= iv7; ++ iv = iv7 ^ rkey0; ++ ++#define DO_ROUND(r) \ ++ rkey = ALIGNED_LOAD (rk, r); \ ++ b0 = asm_cipher_be (b0, rkey); \ ++ b1 = asm_cipher_be (b1, rkey); \ ++ b2 = asm_cipher_be (b2, rkey); \ ++ b3 = asm_cipher_be (b3, rkey); \ ++ b4 = asm_cipher_be (b4, rkey); \ ++ b5 = asm_cipher_be (b5, rkey); \ ++ b6 = asm_cipher_be (b6, rkey); \ ++ b7 = asm_cipher_be (b7, rkey); ++ ++ DO_ROUND(1); ++ DO_ROUND(2); ++ DO_ROUND(3); ++ DO_ROUND(4); ++ DO_ROUND(5); ++ DO_ROUND(6); ++ DO_ROUND(7); ++ ++ rkeylf = asm_xor (rkeylast, rkey0); ++ ++ DO_ROUND(8); ++ ++ iv0 = asm_xor (rkeylf, iv0); ++ iv1 = asm_xor (rkeylf, iv1); ++ iv2 = asm_xor (rkeylf, iv2); ++ iv3 = asm_xor (rkeylf, iv3); ++ iv4 = asm_xor (rkeylf, iv4); ++ iv5 = asm_xor (rkeylf, iv5); ++ iv6 = asm_xor (rkeylf, iv6); ++ iv7 = asm_xor (rkeylf, iv7); ++ ++ DO_ROUND(9); ++ if (rounds >= 12) ++ { ++ DO_ROUND(10); ++ DO_ROUND(11); ++ if (rounds > 12) ++ { ++ DO_ROUND(12); ++ DO_ROUND(13); ++ } ++ } ++ ++#undef DO_ROUND ++ ++ b0 = asm_cipherlast_be (b0, iv0); ++ b1 = asm_cipherlast_be (b1, iv1); ++ b2 = asm_cipherlast_be (b2, iv2); ++ b3 = asm_cipherlast_be (b3, iv3); ++ b4 = asm_cipherlast_be (b4, iv4); ++ b5 = asm_cipherlast_be (b5, iv5); ++ b6 = asm_cipherlast_be (b6, iv6); ++ b7 = asm_cipherlast_be (b7, iv7); ++ ++ b0 = VEC_BE_SWAP (b0, bige_const); ++ b1 = VEC_BE_SWAP (b1, bige_const); ++ b2 = VEC_BE_SWAP (b2, bige_const); ++ b3 = VEC_BE_SWAP (b3, bige_const); ++ b4 = VEC_BE_SWAP (b4, bige_const); ++ b5 = VEC_BE_SWAP (b5, bige_const); ++ b6 = VEC_BE_SWAP (b6, bige_const); ++ b7 = VEC_BE_SWAP (b7, bige_const); ++ VEC_STORE_BE_NOSWAP (out, 0, b0); ++ VEC_STORE_BE_NOSWAP (out, 1, b1); ++ VEC_STORE_BE_NOSWAP (out, 2, b2); ++ VEC_STORE_BE_NOSWAP (out, 3, b3); ++ VEC_STORE_BE_NOSWAP (out, 4, b4); ++ VEC_STORE_BE_NOSWAP (out, 5, b5); ++ VEC_STORE_BE_NOSWAP (out, 6, b6); ++ VEC_STORE_BE_NOSWAP (out, 7, b7); ++ out += 8; ++ } ++ ++ if (nblocks >= 4 && (data_nblocks % 4) == 0) ++ { ++ b0 = VEC_LOAD_BE (in, 0, bige_const); ++ b1 = VEC_LOAD_BE (in, 1, bige_const); ++ b2 = VEC_LOAD_BE (in, 2, bige_const); ++ b3 = VEC_LOAD_BE (in, 3, bige_const); ++ ++ l = VEC_LOAD_BE (ocb_get_l (c, data_nblocks += 4), 0, bige_const); ++ ++ ctr ^= b0 ^ b1 ^ b2 ^ b3; ++ ++ iv ^= rkey0; ++ ++ iv0 = iv ^ l0; ++ iv1 = iv ^ l0 ^ l1; ++ iv2 = iv ^ l1; ++ iv3 = iv ^ l1 ^ l; ++ ++ b0 ^= iv0; ++ b1 ^= iv1; ++ b2 ^= iv2; ++ b3 ^= iv3; ++ iv = iv3 ^ rkey0; ++ ++#define DO_ROUND(r) \ ++ rkey = ALIGNED_LOAD (rk, r); \ ++ b0 = asm_cipher_be (b0, rkey); \ ++ b1 = asm_cipher_be (b1, rkey); \ ++ b2 = asm_cipher_be (b2, rkey); \ ++ b3 = asm_cipher_be (b3, rkey); ++ ++ DO_ROUND(1); ++ DO_ROUND(2); ++ DO_ROUND(3); ++ DO_ROUND(4); ++ DO_ROUND(5); ++ DO_ROUND(6); ++ DO_ROUND(7); ++ DO_ROUND(8); ++ DO_ROUND(9); ++ if (rounds >= 12) ++ { ++ DO_ROUND(10); ++ DO_ROUND(11); ++ if (rounds > 12) ++ { ++ DO_ROUND(12); ++ DO_ROUND(13); ++ } ++ } ++ ++#undef DO_ROUND ++ ++ rkey = rkeylast ^ rkey0; ++ b0 = asm_cipherlast_be (b0, rkey ^ iv0); ++ b1 = asm_cipherlast_be (b1, rkey ^ iv1); ++ b2 = asm_cipherlast_be (b2, rkey ^ iv2); ++ b3 = asm_cipherlast_be (b3, rkey ^ iv3); ++ ++ VEC_STORE_BE (out, 0, b0, bige_const); ++ VEC_STORE_BE (out, 1, b1, bige_const); ++ VEC_STORE_BE (out, 2, b2, bige_const); ++ VEC_STORE_BE (out, 3, b3, bige_const); ++ ++ in += 4; ++ out += 4; ++ nblocks -= 4; ++ } ++ ++ for (; nblocks; nblocks--) ++ { ++ l = VEC_LOAD_BE (ocb_get_l (c, ++data_nblocks), 0, bige_const); ++ b = VEC_LOAD_BE (in, 0, bige_const); ++ ++ /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ ++ iv ^= l; ++ /* Checksum_i = Checksum_{i-1} xor P_i */ ++ ctr ^= b; ++ /* C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) */ ++ b ^= iv; ++ AES_ENCRYPT (b, rounds); ++ b ^= iv; ++ ++ VEC_STORE_BE (out, 0, b, bige_const); ++ ++ in += 1; ++ out += 1; ++ } ++ } ++ else ++ { ++ const u128_t *rk = (u128_t *)&ctx->keyschdec; ++ ++ if (!ctx->decryption_prepared) ++ { ++ internal_aes_ppc_prepare_decryption (ctx); ++ ctx->decryption_prepared = 1; ++ } ++ ++ PRELOAD_ROUND_KEYS (rounds); ++ ++ for (; nblocks >= 8 && data_nblocks % 8; nblocks--) ++ { ++ l = VEC_LOAD_BE (ocb_get_l (c, ++data_nblocks), 0, bige_const); ++ b = VEC_LOAD_BE (in, 0, bige_const); ++ ++ /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ ++ iv ^= l; ++ /* P_i = Offset_i xor DECIPHER(K, C_i xor Offset_i) */ ++ b ^= iv; ++ AES_DECRYPT (b, rounds); ++ b ^= iv; ++ /* Checksum_i = Checksum_{i-1} xor P_i */ ++ ctr ^= b; ++ ++ VEC_STORE_BE (out, 0, b, bige_const); ++ ++ in += 1; ++ out += 1; ++ } ++ ++ for (; nblocks >= 8; nblocks -= 8) ++ { ++ b0 = VEC_LOAD_BE_NOSWAP (in, 0); ++ b1 = VEC_LOAD_BE_NOSWAP (in, 1); ++ b2 = VEC_LOAD_BE_NOSWAP (in, 2); ++ b3 = VEC_LOAD_BE_NOSWAP (in, 3); ++ b4 = VEC_LOAD_BE_NOSWAP (in, 4); ++ b5 = VEC_LOAD_BE_NOSWAP (in, 5); ++ b6 = VEC_LOAD_BE_NOSWAP (in, 6); ++ b7 = VEC_LOAD_BE_NOSWAP (in, 7); ++ in += 8; ++ l = VEC_LOAD_BE_NOSWAP (ocb_get_l (c, data_nblocks += 8), 0); ++ b0 = VEC_BE_SWAP(b0, bige_const); ++ b1 = VEC_BE_SWAP(b1, bige_const); ++ b2 = VEC_BE_SWAP(b2, bige_const); ++ b3 = VEC_BE_SWAP(b3, bige_const); ++ b4 = VEC_BE_SWAP(b4, bige_const); ++ b5 = VEC_BE_SWAP(b5, bige_const); ++ b6 = VEC_BE_SWAP(b6, bige_const); ++ b7 = VEC_BE_SWAP(b7, bige_const); ++ l = VEC_BE_SWAP(l, bige_const); ++ ++ iv ^= rkey0; ++ ++ iv0 = iv ^ l0; ++ iv1 = iv ^ l0 ^ l1; ++ iv2 = iv ^ l1; ++ iv3 = iv ^ l1 ^ l2; ++ iv4 = iv ^ l1 ^ l2 ^ l0; ++ iv5 = iv ^ l2 ^ l0; ++ iv6 = iv ^ l2; ++ iv7 = iv ^ l2 ^ l; ++ ++ b0 ^= iv0; ++ b1 ^= iv1; ++ b2 ^= iv2; ++ b3 ^= iv3; ++ b4 ^= iv4; ++ b5 ^= iv5; ++ b6 ^= iv6; ++ b7 ^= iv7; ++ iv = iv7 ^ rkey0; ++ ++#define DO_ROUND(r) \ ++ rkey = ALIGNED_LOAD (rk, r); \ ++ b0 = asm_ncipher_be (b0, rkey); \ ++ b1 = asm_ncipher_be (b1, rkey); \ ++ b2 = asm_ncipher_be (b2, rkey); \ ++ b3 = asm_ncipher_be (b3, rkey); \ ++ b4 = asm_ncipher_be (b4, rkey); \ ++ b5 = asm_ncipher_be (b5, rkey); \ ++ b6 = asm_ncipher_be (b6, rkey); \ ++ b7 = asm_ncipher_be (b7, rkey); ++ ++ DO_ROUND(1); ++ DO_ROUND(2); ++ DO_ROUND(3); ++ DO_ROUND(4); ++ DO_ROUND(5); ++ DO_ROUND(6); ++ DO_ROUND(7); ++ ++ rkeylf = asm_xor (rkeylast, rkey0); ++ ++ DO_ROUND(8); ++ ++ iv0 = asm_xor (rkeylf, iv0); ++ iv1 = asm_xor (rkeylf, iv1); ++ iv2 = asm_xor (rkeylf, iv2); ++ iv3 = asm_xor (rkeylf, iv3); ++ iv4 = asm_xor (rkeylf, iv4); ++ iv5 = asm_xor (rkeylf, iv5); ++ iv6 = asm_xor (rkeylf, iv6); ++ iv7 = asm_xor (rkeylf, iv7); ++ ++ DO_ROUND(9); ++ if (rounds >= 12) ++ { ++ DO_ROUND(10); ++ DO_ROUND(11); ++ if (rounds > 12) ++ { ++ DO_ROUND(12); ++ DO_ROUND(13); ++ } ++ } ++ ++#undef DO_ROUND ++ ++ b0 = asm_ncipherlast_be (b0, iv0); ++ b1 = asm_ncipherlast_be (b1, iv1); ++ b2 = asm_ncipherlast_be (b2, iv2); ++ b3 = asm_ncipherlast_be (b3, iv3); ++ b4 = asm_ncipherlast_be (b4, iv4); ++ b5 = asm_ncipherlast_be (b5, iv5); ++ b6 = asm_ncipherlast_be (b6, iv6); ++ b7 = asm_ncipherlast_be (b7, iv7); ++ ++ ctr ^= b0 ^ b1 ^ b2 ^ b3 ^ b4 ^ b5 ^ b6 ^ b7; ++ ++ b0 = VEC_BE_SWAP (b0, bige_const); ++ b1 = VEC_BE_SWAP (b1, bige_const); ++ b2 = VEC_BE_SWAP (b2, bige_const); ++ b3 = VEC_BE_SWAP (b3, bige_const); ++ b4 = VEC_BE_SWAP (b4, bige_const); ++ b5 = VEC_BE_SWAP (b5, bige_const); ++ b6 = VEC_BE_SWAP (b6, bige_const); ++ b7 = VEC_BE_SWAP (b7, bige_const); ++ VEC_STORE_BE_NOSWAP (out, 0, b0); ++ VEC_STORE_BE_NOSWAP (out, 1, b1); ++ VEC_STORE_BE_NOSWAP (out, 2, b2); ++ VEC_STORE_BE_NOSWAP (out, 3, b3); ++ VEC_STORE_BE_NOSWAP (out, 4, b4); ++ VEC_STORE_BE_NOSWAP (out, 5, b5); ++ VEC_STORE_BE_NOSWAP (out, 6, b6); ++ VEC_STORE_BE_NOSWAP (out, 7, b7); ++ out += 8; ++ } ++ ++ if (nblocks >= 4 && (data_nblocks % 4) == 0) ++ { ++ b0 = VEC_LOAD_BE (in, 0, bige_const); ++ b1 = VEC_LOAD_BE (in, 1, bige_const); ++ b2 = VEC_LOAD_BE (in, 2, bige_const); ++ b3 = VEC_LOAD_BE (in, 3, bige_const); ++ ++ l = VEC_LOAD_BE (ocb_get_l (c, data_nblocks += 4), 0, bige_const); ++ ++ iv ^= rkey0; ++ ++ iv0 = iv ^ l0; ++ iv1 = iv ^ l0 ^ l1; ++ iv2 = iv ^ l1; ++ iv3 = iv ^ l1 ^ l; ++ ++ b0 ^= iv0; ++ b1 ^= iv1; ++ b2 ^= iv2; ++ b3 ^= iv3; ++ iv = iv3 ^ rkey0; ++ ++#define DO_ROUND(r) \ ++ rkey = ALIGNED_LOAD (rk, r); \ ++ b0 = asm_ncipher_be (b0, rkey); \ ++ b1 = asm_ncipher_be (b1, rkey); \ ++ b2 = asm_ncipher_be (b2, rkey); \ ++ b3 = asm_ncipher_be (b3, rkey); ++ ++ DO_ROUND(1); ++ DO_ROUND(2); ++ DO_ROUND(3); ++ DO_ROUND(4); ++ DO_ROUND(5); ++ DO_ROUND(6); ++ DO_ROUND(7); ++ DO_ROUND(8); ++ DO_ROUND(9); ++ if (rounds >= 12) ++ { ++ DO_ROUND(10); ++ DO_ROUND(11); ++ if (rounds > 12) ++ { ++ DO_ROUND(12); ++ DO_ROUND(13); ++ } ++ } ++ ++#undef DO_ROUND ++ ++ rkey = rkeylast ^ rkey0; ++ b0 = asm_ncipherlast_be (b0, rkey ^ iv0); ++ b1 = asm_ncipherlast_be (b1, rkey ^ iv1); ++ b2 = asm_ncipherlast_be (b2, rkey ^ iv2); ++ b3 = asm_ncipherlast_be (b3, rkey ^ iv3); ++ ++ VEC_STORE_BE (out, 0, b0, bige_const); ++ VEC_STORE_BE (out, 1, b1, bige_const); ++ VEC_STORE_BE (out, 2, b2, bige_const); ++ VEC_STORE_BE (out, 3, b3, bige_const); ++ ++ ctr ^= b0 ^ b1 ^ b2 ^ b3; ++ ++ in += 4; ++ out += 4; ++ nblocks -= 4; ++ } ++ ++ for (; nblocks; nblocks--) ++ { ++ l = VEC_LOAD_BE (ocb_get_l (c, ++data_nblocks), 0, bige_const); ++ b = VEC_LOAD_BE (in, 0, bige_const); ++ ++ /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ ++ iv ^= l; ++ /* P_i = Offset_i xor DECIPHER(K, C_i xor Offset_i) */ ++ b ^= iv; ++ AES_DECRYPT (b, rounds); ++ b ^= iv; ++ /* Checksum_i = Checksum_{i-1} xor P_i */ ++ ctr ^= b; ++ ++ VEC_STORE_BE (out, 0, b, bige_const); ++ ++ in += 1; ++ out += 1; ++ } ++ } ++ ++ VEC_STORE_BE (c->u_iv.iv, 0, iv, bige_const); ++ VEC_STORE_BE (c->u_ctr.ctr, 0, ctr, bige_const); ++ c->u_mode.ocb.data_nblocks = data_nblocks; ++ ++ return 0; ++} ++ ++size_t OCB_AUTH_FUNC (gcry_cipher_hd_t c, void *abuf_arg, size_t nblocks) ++{ ++ const block bige_const = asm_load_be_const(); ++ RIJNDAEL_context *ctx = (void *)&c->context.c; ++ const u128_t *rk = (u128_t *)&ctx->keyschenc; ++ const u128_t *abuf = (const u128_t *)abuf_arg; ++ int rounds = ctx->rounds; ++ u64 data_nblocks = c->u_mode.ocb.aad_nblocks; ++ block l0, l1, l2, l; ++ block b0, b1, b2, b3, b4, b5, b6, b7, b; ++ block iv0, iv1, iv2, iv3, iv4, iv5, iv6, iv7; ++ block rkey, frkey; ++ block ctr, iv; ++ ROUND_KEY_VARIABLES; ++ ++ iv = VEC_LOAD_BE (c->u_mode.ocb.aad_offset, 0, bige_const); ++ ctr = VEC_LOAD_BE (c->u_mode.ocb.aad_sum, 0, bige_const); ++ ++ l0 = VEC_LOAD_BE (c->u_mode.ocb.L[0], 0, bige_const); ++ l1 = VEC_LOAD_BE (c->u_mode.ocb.L[1], 0, bige_const); ++ l2 = VEC_LOAD_BE (c->u_mode.ocb.L[2], 0, bige_const); ++ ++ PRELOAD_ROUND_KEYS (rounds); ++ ++ for (; nblocks >= 8 && data_nblocks % 8; nblocks--) ++ { ++ l = VEC_LOAD_BE (ocb_get_l (c, ++data_nblocks), 0, bige_const); ++ b = VEC_LOAD_BE (abuf, 0, bige_const); ++ ++ /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ ++ iv ^= l; ++ /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) */ ++ b ^= iv; ++ AES_ENCRYPT (b, rounds); ++ ctr ^= b; ++ ++ abuf += 1; ++ } ++ ++ for (; nblocks >= 8; nblocks -= 8) ++ { ++ b0 = VEC_LOAD_BE (abuf, 0, bige_const); ++ b1 = VEC_LOAD_BE (abuf, 1, bige_const); ++ b2 = VEC_LOAD_BE (abuf, 2, bige_const); ++ b3 = VEC_LOAD_BE (abuf, 3, bige_const); ++ b4 = VEC_LOAD_BE (abuf, 4, bige_const); ++ b5 = VEC_LOAD_BE (abuf, 5, bige_const); ++ b6 = VEC_LOAD_BE (abuf, 6, bige_const); ++ b7 = VEC_LOAD_BE (abuf, 7, bige_const); ++ ++ l = VEC_LOAD_BE (ocb_get_l (c, data_nblocks += 8), 0, bige_const); ++ ++ frkey = rkey0; ++ iv ^= frkey; ++ ++ iv0 = iv ^ l0; ++ iv1 = iv ^ l0 ^ l1; ++ iv2 = iv ^ l1; ++ iv3 = iv ^ l1 ^ l2; ++ iv4 = iv ^ l1 ^ l2 ^ l0; ++ iv5 = iv ^ l2 ^ l0; ++ iv6 = iv ^ l2; ++ iv7 = iv ^ l2 ^ l; ++ ++ b0 ^= iv0; ++ b1 ^= iv1; ++ b2 ^= iv2; ++ b3 ^= iv3; ++ b4 ^= iv4; ++ b5 ^= iv5; ++ b6 ^= iv6; ++ b7 ^= iv7; ++ iv = iv7 ^ frkey; ++ ++#define DO_ROUND(r) \ ++ rkey = ALIGNED_LOAD (rk, r); \ ++ b0 = asm_cipher_be (b0, rkey); \ ++ b1 = asm_cipher_be (b1, rkey); \ ++ b2 = asm_cipher_be (b2, rkey); \ ++ b3 = asm_cipher_be (b3, rkey); \ ++ b4 = asm_cipher_be (b4, rkey); \ ++ b5 = asm_cipher_be (b5, rkey); \ ++ b6 = asm_cipher_be (b6, rkey); \ ++ b7 = asm_cipher_be (b7, rkey); ++ ++ DO_ROUND(1); ++ DO_ROUND(2); ++ DO_ROUND(3); ++ DO_ROUND(4); ++ DO_ROUND(5); ++ DO_ROUND(6); ++ DO_ROUND(7); ++ DO_ROUND(8); ++ DO_ROUND(9); ++ if (rounds >= 12) ++ { ++ DO_ROUND(10); ++ DO_ROUND(11); ++ if (rounds > 12) ++ { ++ DO_ROUND(12); ++ DO_ROUND(13); ++ } ++ } ++ ++#undef DO_ROUND ++ ++ rkey = rkeylast; ++ b0 = asm_cipherlast_be (b0, rkey); ++ b1 = asm_cipherlast_be (b1, rkey); ++ b2 = asm_cipherlast_be (b2, rkey); ++ b3 = asm_cipherlast_be (b3, rkey); ++ b4 = asm_cipherlast_be (b4, rkey); ++ b5 = asm_cipherlast_be (b5, rkey); ++ b6 = asm_cipherlast_be (b6, rkey); ++ b7 = asm_cipherlast_be (b7, rkey); ++ ++ ctr ^= b0 ^ b1 ^ b2 ^ b3 ^ b4 ^ b5 ^ b6 ^ b7; ++ ++ abuf += 8; ++ } ++ ++ if (nblocks >= 4 && (data_nblocks % 4) == 0) ++ { ++ b0 = VEC_LOAD_BE (abuf, 0, bige_const); ++ b1 = VEC_LOAD_BE (abuf, 1, bige_const); ++ b2 = VEC_LOAD_BE (abuf, 2, bige_const); ++ b3 = VEC_LOAD_BE (abuf, 3, bige_const); ++ ++ l = VEC_LOAD_BE (ocb_get_l (c, data_nblocks += 4), 0, bige_const); ++ ++ frkey = rkey0; ++ iv ^= frkey; ++ ++ iv0 = iv ^ l0; ++ iv1 = iv ^ l0 ^ l1; ++ iv2 = iv ^ l1; ++ iv3 = iv ^ l1 ^ l; ++ ++ b0 ^= iv0; ++ b1 ^= iv1; ++ b2 ^= iv2; ++ b3 ^= iv3; ++ iv = iv3 ^ frkey; ++ ++#define DO_ROUND(r) \ ++ rkey = ALIGNED_LOAD (rk, r); \ ++ b0 = asm_cipher_be (b0, rkey); \ ++ b1 = asm_cipher_be (b1, rkey); \ ++ b2 = asm_cipher_be (b2, rkey); \ ++ b3 = asm_cipher_be (b3, rkey); ++ ++ DO_ROUND(1); ++ DO_ROUND(2); ++ DO_ROUND(3); ++ DO_ROUND(4); ++ DO_ROUND(5); ++ DO_ROUND(6); ++ DO_ROUND(7); ++ DO_ROUND(8); ++ DO_ROUND(9); ++ if (rounds >= 12) ++ { ++ DO_ROUND(10); ++ DO_ROUND(11); ++ if (rounds > 12) ++ { ++ DO_ROUND(12); ++ DO_ROUND(13); ++ } ++ } ++ ++#undef DO_ROUND ++ ++ rkey = rkeylast; ++ b0 = asm_cipherlast_be (b0, rkey); ++ b1 = asm_cipherlast_be (b1, rkey); ++ b2 = asm_cipherlast_be (b2, rkey); ++ b3 = asm_cipherlast_be (b3, rkey); ++ ++ ctr ^= b0 ^ b1 ^ b2 ^ b3; ++ ++ abuf += 4; ++ nblocks -= 4; ++ } ++ ++ for (; nblocks; nblocks--) ++ { ++ l = VEC_LOAD_BE (ocb_get_l (c, ++data_nblocks), 0, bige_const); ++ b = VEC_LOAD_BE (abuf, 0, bige_const); ++ ++ /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */ ++ iv ^= l; ++ /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) */ ++ b ^= iv; ++ AES_ENCRYPT (b, rounds); ++ ctr ^= b; ++ ++ abuf += 1; ++ } ++ ++ VEC_STORE_BE (c->u_mode.ocb.aad_offset, 0, iv, bige_const); ++ VEC_STORE_BE (c->u_mode.ocb.aad_sum, 0, ctr, bige_const); ++ c->u_mode.ocb.aad_nblocks = data_nblocks; ++ ++ return 0; ++} ++ ++ ++void XTS_CRYPT_FUNC (void *context, unsigned char *tweak_arg, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks, int encrypt) ++{ ++#ifdef WORDS_BIGENDIAN ++ static const block vec_bswap128_const = ++ { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; ++#else ++ static const block vec_bswap128_const = ++ { ~15, ~14, ~13, ~12, ~11, ~10, ~9, ~8, ~7, ~6, ~5, ~4, ~3, ~2, ~1, ~0 }; ++#endif ++ static const unsigned char vec_tweak_const[16] = ++ { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x87 }; ++ static const vector unsigned long long vec_shift63_const = ++ { 63, 63 }; ++ const block bige_const = asm_load_be_const(); ++ RIJNDAEL_context *ctx = context; ++ const u128_t *in = (const u128_t *)inbuf_arg; ++ u128_t *out = (u128_t *)outbuf_arg; ++ int rounds = ctx->rounds; ++ block tweak; ++ block b0, b1, b2, b3, b4, b5, b6, b7, b, rkey, rkeylf; ++ block tweak0, tweak1, tweak2, tweak3, tweak4, tweak5, tweak6, tweak7; ++ block tweak_const, bswap128_const, shift63_const; ++ ROUND_KEY_VARIABLES; ++ ++ tweak_const = VEC_LOAD_BE (&vec_tweak_const, 0, bige_const); ++ bswap128_const = ALIGNED_LOAD (&vec_bswap128_const, 0); ++ shift63_const = ALIGNED_LOAD (&vec_shift63_const, 0); ++ ++ tweak = VEC_LOAD_BE (tweak_arg, 0, bige_const); ++ tweak = asm_vperm1 (tweak, bswap128_const); ++ ++#define GEN_TWEAK(tout, tin) /* Generate next tweak. */ \ ++ do { \ ++ block tmp1, tmp2; \ ++ tmp1 = asm_swap_uint64_halfs(tin); \ ++ tmp2 = asm_add_uint64(tin, tin); \ ++ tmp1 = asm_sra_int64(tmp1, shift63_const) & tweak_const; \ ++ tout = asm_xor(tmp1, tmp2); \ ++ } while (0) ++ ++ if (encrypt) ++ { ++ const u128_t *rk = (u128_t *)&ctx->keyschenc; ++ ++ PRELOAD_ROUND_KEYS (rounds); ++ ++ for (; nblocks >= 8; nblocks -= 8) ++ { ++ b0 = VEC_LOAD_BE_NOSWAP (in, 0); ++ b1 = VEC_LOAD_BE_NOSWAP (in, 1); ++ b2 = VEC_LOAD_BE_NOSWAP (in, 2); ++ b3 = VEC_LOAD_BE_NOSWAP (in, 3); ++ tweak0 = tweak; ++ GEN_TWEAK (tweak1, tweak0); ++ tweak0 = asm_vperm1 (tweak0, bswap128_const); ++ b4 = VEC_LOAD_BE_NOSWAP (in, 4); ++ b5 = VEC_LOAD_BE_NOSWAP (in, 5); ++ GEN_TWEAK (tweak2, tweak1); ++ tweak1 = asm_vperm1 (tweak1, bswap128_const); ++ b6 = VEC_LOAD_BE_NOSWAP (in, 6); ++ b7 = VEC_LOAD_BE_NOSWAP (in, 7); ++ in += 8; ++ ++ b0 = VEC_BE_SWAP(b0, bige_const); ++ b1 = VEC_BE_SWAP(b1, bige_const); ++ GEN_TWEAK (tweak3, tweak2); ++ tweak2 = asm_vperm1 (tweak2, bswap128_const); ++ GEN_TWEAK (tweak4, tweak3); ++ tweak3 = asm_vperm1 (tweak3, bswap128_const); ++ b2 = VEC_BE_SWAP(b2, bige_const); ++ b3 = VEC_BE_SWAP(b3, bige_const); ++ GEN_TWEAK (tweak5, tweak4); ++ tweak4 = asm_vperm1 (tweak4, bswap128_const); ++ GEN_TWEAK (tweak6, tweak5); ++ tweak5 = asm_vperm1 (tweak5, bswap128_const); ++ b4 = VEC_BE_SWAP(b4, bige_const); ++ b5 = VEC_BE_SWAP(b5, bige_const); ++ GEN_TWEAK (tweak7, tweak6); ++ tweak6 = asm_vperm1 (tweak6, bswap128_const); ++ GEN_TWEAK (tweak, tweak7); ++ tweak7 = asm_vperm1 (tweak7, bswap128_const); ++ b6 = VEC_BE_SWAP(b6, bige_const); ++ b7 = VEC_BE_SWAP(b7, bige_const); ++ ++ tweak0 = asm_xor (tweak0, rkey0); ++ tweak1 = asm_xor (tweak1, rkey0); ++ tweak2 = asm_xor (tweak2, rkey0); ++ tweak3 = asm_xor (tweak3, rkey0); ++ tweak4 = asm_xor (tweak4, rkey0); ++ tweak5 = asm_xor (tweak5, rkey0); ++ tweak6 = asm_xor (tweak6, rkey0); ++ tweak7 = asm_xor (tweak7, rkey0); ++ ++ b0 = asm_xor (b0, tweak0); ++ b1 = asm_xor (b1, tweak1); ++ b2 = asm_xor (b2, tweak2); ++ b3 = asm_xor (b3, tweak3); ++ b4 = asm_xor (b4, tweak4); ++ b5 = asm_xor (b5, tweak5); ++ b6 = asm_xor (b6, tweak6); ++ b7 = asm_xor (b7, tweak7); ++ ++#define DO_ROUND(r) \ ++ rkey = ALIGNED_LOAD (rk, r); \ ++ b0 = asm_cipher_be (b0, rkey); \ ++ b1 = asm_cipher_be (b1, rkey); \ ++ b2 = asm_cipher_be (b2, rkey); \ ++ b3 = asm_cipher_be (b3, rkey); \ ++ b4 = asm_cipher_be (b4, rkey); \ ++ b5 = asm_cipher_be (b5, rkey); \ ++ b6 = asm_cipher_be (b6, rkey); \ ++ b7 = asm_cipher_be (b7, rkey); ++ ++ DO_ROUND(1); ++ DO_ROUND(2); ++ DO_ROUND(3); ++ DO_ROUND(4); ++ DO_ROUND(5); ++ DO_ROUND(6); ++ DO_ROUND(7); ++ ++ rkeylf = asm_xor (rkeylast, rkey0); ++ ++ DO_ROUND(8); ++ ++ tweak0 = asm_xor (tweak0, rkeylf); ++ tweak1 = asm_xor (tweak1, rkeylf); ++ tweak2 = asm_xor (tweak2, rkeylf); ++ tweak3 = asm_xor (tweak3, rkeylf); ++ tweak4 = asm_xor (tweak4, rkeylf); ++ tweak5 = asm_xor (tweak5, rkeylf); ++ tweak6 = asm_xor (tweak6, rkeylf); ++ tweak7 = asm_xor (tweak7, rkeylf); ++ ++ DO_ROUND(9); ++ if (rounds >= 12) ++ { ++ DO_ROUND(10); ++ DO_ROUND(11); ++ if (rounds > 12) ++ { ++ DO_ROUND(12); ++ DO_ROUND(13); ++ } ++ } ++ ++#undef DO_ROUND ++ ++ b0 = asm_cipherlast_be (b0, tweak0); ++ b1 = asm_cipherlast_be (b1, tweak1); ++ b2 = asm_cipherlast_be (b2, tweak2); ++ b3 = asm_cipherlast_be (b3, tweak3); ++ b0 = VEC_BE_SWAP (b0, bige_const); ++ b1 = VEC_BE_SWAP (b1, bige_const); ++ b4 = asm_cipherlast_be (b4, tweak4); ++ b5 = asm_cipherlast_be (b5, tweak5); ++ b2 = VEC_BE_SWAP (b2, bige_const); ++ b3 = VEC_BE_SWAP (b3, bige_const); ++ b6 = asm_cipherlast_be (b6, tweak6); ++ b7 = asm_cipherlast_be (b7, tweak7); ++ VEC_STORE_BE_NOSWAP (out, 0, b0); ++ VEC_STORE_BE_NOSWAP (out, 1, b1); ++ b4 = VEC_BE_SWAP (b4, bige_const); ++ b5 = VEC_BE_SWAP (b5, bige_const); ++ VEC_STORE_BE_NOSWAP (out, 2, b2); ++ VEC_STORE_BE_NOSWAP (out, 3, b3); ++ b6 = VEC_BE_SWAP (b6, bige_const); ++ b7 = VEC_BE_SWAP (b7, bige_const); ++ VEC_STORE_BE_NOSWAP (out, 4, b4); ++ VEC_STORE_BE_NOSWAP (out, 5, b5); ++ VEC_STORE_BE_NOSWAP (out, 6, b6); ++ VEC_STORE_BE_NOSWAP (out, 7, b7); ++ out += 8; ++ } ++ ++ if (nblocks >= 4) ++ { ++ tweak0 = tweak; ++ GEN_TWEAK (tweak1, tweak0); ++ GEN_TWEAK (tweak2, tweak1); ++ GEN_TWEAK (tweak3, tweak2); ++ GEN_TWEAK (tweak, tweak3); ++ ++ b0 = VEC_LOAD_BE (in, 0, bige_const); ++ b1 = VEC_LOAD_BE (in, 1, bige_const); ++ b2 = VEC_LOAD_BE (in, 2, bige_const); ++ b3 = VEC_LOAD_BE (in, 3, bige_const); ++ ++ tweak0 = asm_vperm1 (tweak0, bswap128_const); ++ tweak1 = asm_vperm1 (tweak1, bswap128_const); ++ tweak2 = asm_vperm1 (tweak2, bswap128_const); ++ tweak3 = asm_vperm1 (tweak3, bswap128_const); ++ ++ b0 ^= tweak0 ^ rkey0; ++ b1 ^= tweak1 ^ rkey0; ++ b2 ^= tweak2 ^ rkey0; ++ b3 ^= tweak3 ^ rkey0; ++ ++#define DO_ROUND(r) \ ++ rkey = ALIGNED_LOAD (rk, r); \ ++ b0 = asm_cipher_be (b0, rkey); \ ++ b1 = asm_cipher_be (b1, rkey); \ ++ b2 = asm_cipher_be (b2, rkey); \ ++ b3 = asm_cipher_be (b3, rkey); ++ ++ DO_ROUND(1); ++ DO_ROUND(2); ++ DO_ROUND(3); ++ DO_ROUND(4); ++ DO_ROUND(5); ++ DO_ROUND(6); ++ DO_ROUND(7); ++ DO_ROUND(8); ++ DO_ROUND(9); ++ if (rounds >= 12) ++ { ++ DO_ROUND(10); ++ DO_ROUND(11); ++ if (rounds > 12) ++ { ++ DO_ROUND(12); ++ DO_ROUND(13); ++ } ++ } ++ ++#undef DO_ROUND ++ ++ rkey = rkeylast; ++ b0 = asm_cipherlast_be (b0, rkey ^ tweak0); ++ b1 = asm_cipherlast_be (b1, rkey ^ tweak1); ++ b2 = asm_cipherlast_be (b2, rkey ^ tweak2); ++ b3 = asm_cipherlast_be (b3, rkey ^ tweak3); ++ ++ VEC_STORE_BE (out, 0, b0, bige_const); ++ VEC_STORE_BE (out, 1, b1, bige_const); ++ VEC_STORE_BE (out, 2, b2, bige_const); ++ VEC_STORE_BE (out, 3, b3, bige_const); ++ ++ in += 4; ++ out += 4; ++ nblocks -= 4; ++ } ++ ++ for (; nblocks; nblocks--) ++ { ++ tweak0 = asm_vperm1 (tweak, bswap128_const); ++ ++ /* Xor-Encrypt/Decrypt-Xor block. */ ++ b = VEC_LOAD_BE (in, 0, bige_const) ^ tweak0; ++ ++ /* Generate next tweak. */ ++ GEN_TWEAK (tweak, tweak); ++ ++ AES_ENCRYPT (b, rounds); ++ ++ b ^= tweak0; ++ VEC_STORE_BE (out, 0, b, bige_const); ++ ++ in++; ++ out++; ++ } ++ } ++ else ++ { ++ const u128_t *rk = (u128_t *)&ctx->keyschdec; ++ ++ if (!ctx->decryption_prepared) ++ { ++ internal_aes_ppc_prepare_decryption (ctx); ++ ctx->decryption_prepared = 1; ++ } ++ ++ PRELOAD_ROUND_KEYS (rounds); ++ ++ for (; nblocks >= 8; nblocks -= 8) ++ { ++ b0 = VEC_LOAD_BE_NOSWAP (in, 0); ++ b1 = VEC_LOAD_BE_NOSWAP (in, 1); ++ b2 = VEC_LOAD_BE_NOSWAP (in, 2); ++ b3 = VEC_LOAD_BE_NOSWAP (in, 3); ++ tweak0 = tweak; ++ GEN_TWEAK (tweak1, tweak0); ++ tweak0 = asm_vperm1 (tweak0, bswap128_const); ++ b4 = VEC_LOAD_BE_NOSWAP (in, 4); ++ b5 = VEC_LOAD_BE_NOSWAP (in, 5); ++ GEN_TWEAK (tweak2, tweak1); ++ tweak1 = asm_vperm1 (tweak1, bswap128_const); ++ b6 = VEC_LOAD_BE_NOSWAP (in, 6); ++ b7 = VEC_LOAD_BE_NOSWAP (in, 7); ++ in += 8; ++ ++ b0 = VEC_BE_SWAP(b0, bige_const); ++ b1 = VEC_BE_SWAP(b1, bige_const); ++ GEN_TWEAK (tweak3, tweak2); ++ tweak2 = asm_vperm1 (tweak2, bswap128_const); ++ GEN_TWEAK (tweak4, tweak3); ++ tweak3 = asm_vperm1 (tweak3, bswap128_const); ++ b2 = VEC_BE_SWAP(b2, bige_const); ++ b3 = VEC_BE_SWAP(b3, bige_const); ++ GEN_TWEAK (tweak5, tweak4); ++ tweak4 = asm_vperm1 (tweak4, bswap128_const); ++ GEN_TWEAK (tweak6, tweak5); ++ tweak5 = asm_vperm1 (tweak5, bswap128_const); ++ b4 = VEC_BE_SWAP(b4, bige_const); ++ b5 = VEC_BE_SWAP(b5, bige_const); ++ GEN_TWEAK (tweak7, tweak6); ++ tweak6 = asm_vperm1 (tweak6, bswap128_const); ++ GEN_TWEAK (tweak, tweak7); ++ tweak7 = asm_vperm1 (tweak7, bswap128_const); ++ b6 = VEC_BE_SWAP(b6, bige_const); ++ b7 = VEC_BE_SWAP(b7, bige_const); ++ ++ tweak0 = asm_xor (tweak0, rkey0); ++ tweak1 = asm_xor (tweak1, rkey0); ++ tweak2 = asm_xor (tweak2, rkey0); ++ tweak3 = asm_xor (tweak3, rkey0); ++ tweak4 = asm_xor (tweak4, rkey0); ++ tweak5 = asm_xor (tweak5, rkey0); ++ tweak6 = asm_xor (tweak6, rkey0); ++ tweak7 = asm_xor (tweak7, rkey0); ++ ++ b0 = asm_xor (b0, tweak0); ++ b1 = asm_xor (b1, tweak1); ++ b2 = asm_xor (b2, tweak2); ++ b3 = asm_xor (b3, tweak3); ++ b4 = asm_xor (b4, tweak4); ++ b5 = asm_xor (b5, tweak5); ++ b6 = asm_xor (b6, tweak6); ++ b7 = asm_xor (b7, tweak7); ++ ++#define DO_ROUND(r) \ ++ rkey = ALIGNED_LOAD (rk, r); \ ++ b0 = asm_ncipher_be (b0, rkey); \ ++ b1 = asm_ncipher_be (b1, rkey); \ ++ b2 = asm_ncipher_be (b2, rkey); \ ++ b3 = asm_ncipher_be (b3, rkey); \ ++ b4 = asm_ncipher_be (b4, rkey); \ ++ b5 = asm_ncipher_be (b5, rkey); \ ++ b6 = asm_ncipher_be (b6, rkey); \ ++ b7 = asm_ncipher_be (b7, rkey); ++ ++ DO_ROUND(1); ++ DO_ROUND(2); ++ DO_ROUND(3); ++ DO_ROUND(4); ++ DO_ROUND(5); ++ DO_ROUND(6); ++ DO_ROUND(7); ++ ++ rkeylf = asm_xor (rkeylast, rkey0); ++ ++ DO_ROUND(8); ++ ++ tweak0 = asm_xor (tweak0, rkeylf); ++ tweak1 = asm_xor (tweak1, rkeylf); ++ tweak2 = asm_xor (tweak2, rkeylf); ++ tweak3 = asm_xor (tweak3, rkeylf); ++ tweak4 = asm_xor (tweak4, rkeylf); ++ tweak5 = asm_xor (tweak5, rkeylf); ++ tweak6 = asm_xor (tweak6, rkeylf); ++ tweak7 = asm_xor (tweak7, rkeylf); ++ ++ DO_ROUND(9); ++ if (rounds >= 12) ++ { ++ DO_ROUND(10); ++ DO_ROUND(11); ++ if (rounds > 12) ++ { ++ DO_ROUND(12); ++ DO_ROUND(13); ++ } ++ } ++ ++#undef DO_ROUND ++ ++ b0 = asm_ncipherlast_be (b0, tweak0); ++ b1 = asm_ncipherlast_be (b1, tweak1); ++ b2 = asm_ncipherlast_be (b2, tweak2); ++ b3 = asm_ncipherlast_be (b3, tweak3); ++ b0 = VEC_BE_SWAP (b0, bige_const); ++ b1 = VEC_BE_SWAP (b1, bige_const); ++ b4 = asm_ncipherlast_be (b4, tweak4); ++ b5 = asm_ncipherlast_be (b5, tweak5); ++ b2 = VEC_BE_SWAP (b2, bige_const); ++ b3 = VEC_BE_SWAP (b3, bige_const); ++ b6 = asm_ncipherlast_be (b6, tweak6); ++ b7 = asm_ncipherlast_be (b7, tweak7); ++ VEC_STORE_BE_NOSWAP (out, 0, b0); ++ VEC_STORE_BE_NOSWAP (out, 1, b1); ++ b4 = VEC_BE_SWAP (b4, bige_const); ++ b5 = VEC_BE_SWAP (b5, bige_const); ++ VEC_STORE_BE_NOSWAP (out, 2, b2); ++ VEC_STORE_BE_NOSWAP (out, 3, b3); ++ b6 = VEC_BE_SWAP (b6, bige_const); ++ b7 = VEC_BE_SWAP (b7, bige_const); ++ VEC_STORE_BE_NOSWAP (out, 4, b4); ++ VEC_STORE_BE_NOSWAP (out, 5, b5); ++ VEC_STORE_BE_NOSWAP (out, 6, b6); ++ VEC_STORE_BE_NOSWAP (out, 7, b7); ++ out += 8; ++ } ++ ++ if (nblocks >= 4) ++ { ++ tweak0 = tweak; ++ GEN_TWEAK (tweak1, tweak0); ++ GEN_TWEAK (tweak2, tweak1); ++ GEN_TWEAK (tweak3, tweak2); ++ GEN_TWEAK (tweak, tweak3); ++ ++ b0 = VEC_LOAD_BE (in, 0, bige_const); ++ b1 = VEC_LOAD_BE (in, 1, bige_const); ++ b2 = VEC_LOAD_BE (in, 2, bige_const); ++ b3 = VEC_LOAD_BE (in, 3, bige_const); ++ ++ tweak0 = asm_vperm1 (tweak0, bswap128_const); ++ tweak1 = asm_vperm1 (tweak1, bswap128_const); ++ tweak2 = asm_vperm1 (tweak2, bswap128_const); ++ tweak3 = asm_vperm1 (tweak3, bswap128_const); ++ ++ b0 ^= tweak0 ^ rkey0; ++ b1 ^= tweak1 ^ rkey0; ++ b2 ^= tweak2 ^ rkey0; ++ b3 ^= tweak3 ^ rkey0; ++ ++#define DO_ROUND(r) \ ++ rkey = ALIGNED_LOAD (rk, r); \ ++ b0 = asm_ncipher_be (b0, rkey); \ ++ b1 = asm_ncipher_be (b1, rkey); \ ++ b2 = asm_ncipher_be (b2, rkey); \ ++ b3 = asm_ncipher_be (b3, rkey); ++ ++ DO_ROUND(1); ++ DO_ROUND(2); ++ DO_ROUND(3); ++ DO_ROUND(4); ++ DO_ROUND(5); ++ DO_ROUND(6); ++ DO_ROUND(7); ++ DO_ROUND(8); ++ DO_ROUND(9); ++ if (rounds >= 12) ++ { ++ DO_ROUND(10); ++ DO_ROUND(11); ++ if (rounds > 12) ++ { ++ DO_ROUND(12); ++ DO_ROUND(13); ++ } ++ } ++ ++#undef DO_ROUND ++ ++ rkey = rkeylast; ++ b0 = asm_ncipherlast_be (b0, rkey ^ tweak0); ++ b1 = asm_ncipherlast_be (b1, rkey ^ tweak1); ++ b2 = asm_ncipherlast_be (b2, rkey ^ tweak2); ++ b3 = asm_ncipherlast_be (b3, rkey ^ tweak3); ++ ++ VEC_STORE_BE (out, 0, b0, bige_const); ++ VEC_STORE_BE (out, 1, b1, bige_const); ++ VEC_STORE_BE (out, 2, b2, bige_const); ++ VEC_STORE_BE (out, 3, b3, bige_const); ++ ++ in += 4; ++ out += 4; ++ nblocks -= 4; ++ } ++ ++ for (; nblocks; nblocks--) ++ { ++ tweak0 = asm_vperm1 (tweak, bswap128_const); ++ ++ /* Xor-Encrypt/Decrypt-Xor block. */ ++ b = VEC_LOAD_BE (in, 0, bige_const) ^ tweak0; ++ ++ /* Generate next tweak. */ ++ GEN_TWEAK (tweak, tweak); ++ ++ AES_DECRYPT (b, rounds); ++ ++ b ^= tweak0; ++ VEC_STORE_BE (out, 0, b, bige_const); ++ ++ in++; ++ out++; ++ } ++ } ++ ++ tweak = asm_vperm1 (tweak, bswap128_const); ++ VEC_STORE_BE (tweak_arg, 0, tweak, bige_const); ++ ++#undef GEN_TWEAK ++} +diff -up libgcrypt-1.8.5/cipher/rijndael-ssse3-amd64.c.aes-perf libgcrypt-1.8.5/cipher/rijndael-ssse3-amd64.c +--- libgcrypt-1.8.5/cipher/rijndael-ssse3-amd64.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/rijndael-ssse3-amd64.c 2020-04-22 18:29:41.679862057 +0200 +@@ -208,11 +208,11 @@ _gcry_aes_ssse3_do_setkey (RIJNDAEL_cont + + + /* Make a decryption key from an encryption key. */ +-void +-_gcry_aes_ssse3_prepare_decryption (RIJNDAEL_context *ctx) ++static inline void ++do_ssse3_prepare_decryption (RIJNDAEL_context *ctx, ++ byte ssse3_state[SSSE3_STATE_SIZE]) + { + unsigned int keybits = (ctx->rounds - 10) * 32 + 128; +- byte ssse3_state[SSSE3_STATE_SIZE]; + + vpaes_ssse3_prepare(); + +@@ -237,6 +237,14 @@ _gcry_aes_ssse3_prepare_decryption (RIJN + vpaes_ssse3_cleanup(); + } + ++void ++_gcry_aes_ssse3_prepare_decryption (RIJNDAEL_context *ctx) ++{ ++ byte ssse3_state[SSSE3_STATE_SIZE]; ++ ++ do_ssse3_prepare_decryption(ctx, ssse3_state); ++} ++ + + /* Encrypt one block using the Intel SSSE3 instructions. Block is input + * and output through SSE register xmm0. */ +@@ -295,9 +303,9 @@ _gcry_aes_ssse3_encrypt (const RIJNDAEL_ + + + void +-_gcry_aes_ssse3_cfb_enc (RIJNDAEL_context *ctx, unsigned char *outbuf, +- const unsigned char *inbuf, unsigned char *iv, +- size_t nblocks) ++_gcry_aes_ssse3_cfb_enc (RIJNDAEL_context *ctx, unsigned char *iv, ++ unsigned char *outbuf, const unsigned char *inbuf, ++ size_t nblocks) + { + unsigned int nrounds = ctx->rounds; + byte ssse3_state[SSSE3_STATE_SIZE]; +@@ -334,9 +342,9 @@ _gcry_aes_ssse3_cfb_enc (RIJNDAEL_contex + + + void +-_gcry_aes_ssse3_cbc_enc (RIJNDAEL_context *ctx, unsigned char *outbuf, +- const unsigned char *inbuf, unsigned char *iv, +- size_t nblocks, int cbc_mac) ++_gcry_aes_ssse3_cbc_enc (RIJNDAEL_context *ctx, unsigned char *iv, ++ unsigned char *outbuf, const unsigned char *inbuf, ++ size_t nblocks, int cbc_mac) + { + unsigned int nrounds = ctx->rounds; + byte ssse3_state[SSSE3_STATE_SIZE]; +@@ -379,9 +387,9 @@ _gcry_aes_ssse3_cbc_enc (RIJNDAEL_contex + + + void +-_gcry_aes_ssse3_ctr_enc (RIJNDAEL_context *ctx, unsigned char *outbuf, +- const unsigned char *inbuf, unsigned char *ctr, +- size_t nblocks) ++_gcry_aes_ssse3_ctr_enc (RIJNDAEL_context *ctx, unsigned char *ctr, ++ unsigned char *outbuf, const unsigned char *inbuf, ++ size_t nblocks) + { + 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 }; +@@ -447,7 +455,7 @@ _gcry_aes_ssse3_ctr_enc (RIJNDAEL_contex + + unsigned int + _gcry_aes_ssse3_decrypt (const RIJNDAEL_context *ctx, unsigned char *dst, +- const unsigned char *src) ++ const unsigned char *src) + { + unsigned int nrounds = ctx->rounds; + byte ssse3_state[SSSE3_STATE_SIZE]; +@@ -468,9 +476,9 @@ _gcry_aes_ssse3_decrypt (const RIJNDAEL_ + + + void +-_gcry_aes_ssse3_cfb_dec (RIJNDAEL_context *ctx, unsigned char *outbuf, +- const unsigned char *inbuf, unsigned char *iv, +- size_t nblocks) ++_gcry_aes_ssse3_cfb_dec (RIJNDAEL_context *ctx, unsigned char *iv, ++ unsigned char *outbuf, const unsigned char *inbuf, ++ size_t nblocks) + { + unsigned int nrounds = ctx->rounds; + byte ssse3_state[SSSE3_STATE_SIZE]; +@@ -508,13 +516,19 @@ _gcry_aes_ssse3_cfb_dec (RIJNDAEL_contex + + + void +-_gcry_aes_ssse3_cbc_dec (RIJNDAEL_context *ctx, unsigned char *outbuf, +- const unsigned char *inbuf, unsigned char *iv, +- size_t nblocks) ++_gcry_aes_ssse3_cbc_dec (RIJNDAEL_context *ctx, unsigned char *iv, ++ unsigned char *outbuf, const unsigned char *inbuf, ++ size_t nblocks) + { + unsigned int nrounds = ctx->rounds; + byte ssse3_state[SSSE3_STATE_SIZE]; + ++ if ( !ctx->decryption_prepared ) ++ { ++ do_ssse3_prepare_decryption ( ctx, ssse3_state ); ++ ctx->decryption_prepared = 1; ++ } ++ + vpaes_ssse3_prepare_dec (); + + asm volatile ("movdqu %[iv], %%xmm7\n\t" /* use xmm7 as fast IV storage */ +@@ -626,6 +640,12 @@ ssse3_ocb_dec (gcry_cipher_hd_t c, void + unsigned int nrounds = ctx->rounds; + byte ssse3_state[SSSE3_STATE_SIZE]; + ++ if ( !ctx->decryption_prepared ) ++ { ++ do_ssse3_prepare_decryption ( ctx, ssse3_state ); ++ ctx->decryption_prepared = 1; ++ } ++ + vpaes_ssse3_prepare_dec (); + + /* Preload Offset and Checksum */ +@@ -679,7 +699,7 @@ ssse3_ocb_dec (gcry_cipher_hd_t c, void + } + + +-void ++size_t + _gcry_aes_ssse3_ocb_crypt(gcry_cipher_hd_t c, void *outbuf_arg, + const void *inbuf_arg, size_t nblocks, int encrypt) + { +@@ -687,10 +707,12 @@ _gcry_aes_ssse3_ocb_crypt(gcry_cipher_hd + ssse3_ocb_enc(c, outbuf_arg, inbuf_arg, nblocks); + else + ssse3_ocb_dec(c, outbuf_arg, inbuf_arg, nblocks); ++ ++ return 0; + } + + +-void ++size_t + _gcry_aes_ssse3_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg, + size_t nblocks) + { +@@ -746,6 +768,8 @@ _gcry_aes_ssse3_ocb_auth (gcry_cipher_hd + : "memory" ); + + vpaes_ssse3_cleanup (); ++ ++ return 0; + } + + #endif /* USE_SSSE3 */ +diff -up libgcrypt-1.8.5/cipher/salsa20.c.aes-perf libgcrypt-1.8.5/cipher/salsa20.c +--- libgcrypt-1.8.5/cipher/salsa20.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/salsa20.c 2020-04-22 18:29:41.679862057 +0200 +@@ -366,10 +366,12 @@ salsa20_do_setkey (SALSA20_context_t *ct + + + static gcry_err_code_t +-salsa20_setkey (void *context, const byte *key, unsigned int keylen) ++salsa20_setkey (void *context, const byte *key, unsigned int keylen, ++ gcry_cipher_hd_t hd) + { + SALSA20_context_t *ctx = (SALSA20_context_t *)context; + gcry_err_code_t rc = salsa20_do_setkey (ctx, key, keylen); ++ (void)hd; + _gcry_burn_stack (4 + sizeof (void *) + 4 * sizeof (void *)); + return rc; + } +@@ -522,7 +524,7 @@ selftest (void) + /* 16-byte alignment required for amd64 implementation. */ + ctx = (SALSA20_context_t *)((uintptr_t)(ctxbuf + 15) & ~(uintptr_t)15); + +- salsa20_setkey (ctx, key_1, sizeof key_1); ++ salsa20_setkey (ctx, key_1, sizeof key_1, NULL); + salsa20_setiv (ctx, nonce_1, sizeof nonce_1); + scratch[8] = 0; + salsa20_encrypt_stream (ctx, scratch, plaintext_1, sizeof plaintext_1); +@@ -530,7 +532,7 @@ selftest (void) + return "Salsa20 encryption test 1 failed."; + if (scratch[8]) + return "Salsa20 wrote too much."; +- salsa20_setkey( ctx, key_1, sizeof(key_1)); ++ salsa20_setkey( ctx, key_1, sizeof(key_1), NULL); + 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)) +@@ -538,12 +540,12 @@ selftest (void) + + for (i = 0; i < sizeof buf; i++) + buf[i] = i; +- salsa20_setkey (ctx, key_1, sizeof key_1); ++ salsa20_setkey (ctx, key_1, sizeof key_1, NULL); + 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_setkey (ctx, key_1, sizeof key_1, NULL); + 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); +diff -up libgcrypt-1.8.5/cipher/seed.c.aes-perf libgcrypt-1.8.5/cipher/seed.c +--- libgcrypt-1.8.5/cipher/seed.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/seed.c 2020-04-22 18:29:41.680862038 +0200 +@@ -309,11 +309,12 @@ do_setkey (SEED_context *ctx, const byte + } + + static gcry_err_code_t +-seed_setkey (void *context, const byte *key, const unsigned keylen) ++seed_setkey (void *context, const byte *key, const unsigned keylen, ++ gcry_cipher_hd_t hd) + { + SEED_context *ctx = context; +- + int rc = do_setkey (ctx, key, keylen); ++ (void)hd; + _gcry_burn_stack (4*6 + sizeof(void*)*2 + sizeof(int)*2); + return rc; + } +@@ -446,7 +447,7 @@ selftest (void) + 0x22, 0x6B, 0xC3, 0x14, 0x2C, 0xD4, 0x0D, 0x4A, + }; + +- seed_setkey (&ctx, key, sizeof(key)); ++ seed_setkey (&ctx, key, sizeof(key), NULL); + seed_encrypt (&ctx, scratch, plaintext); + if (memcmp (scratch, ciphertext, sizeof (ciphertext))) + return "SEED test encryption failed."; +diff -up libgcrypt-1.8.5/cipher/serpent.c.aes-perf libgcrypt-1.8.5/cipher/serpent.c +--- libgcrypt-1.8.5/cipher/serpent.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/serpent.c 2020-04-22 18:29:41.680862038 +0200 +@@ -748,13 +748,16 @@ serpent_setkey_internal (serpent_context + /* Initialize CTX with the key KEY of KEY_LENGTH bytes. */ + static gcry_err_code_t + serpent_setkey (void *ctx, +- const byte *key, unsigned int key_length) ++ const byte *key, unsigned int key_length, ++ gcry_cipher_hd_t hd) + { + serpent_context_t *context = ctx; + static const char *serpent_test_ret; + static int serpent_init_done; + gcry_err_code_t ret = GPG_ERR_NO_ERROR; + ++ (void)hd; ++ + if (! serpent_init_done) + { + /* Execute a self-test the first time, Serpent is used. */ +@@ -999,7 +1002,7 @@ _gcry_serpent_ctr_enc(void *context, uns + /* 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)); ++ cipher_block_xor(outbuf, tmpbuf, inbuf, sizeof(serpent_block_t)); + outbuf += sizeof(serpent_block_t); + inbuf += sizeof(serpent_block_t); + /* Increment the counter. */ +@@ -1114,7 +1117,8 @@ _gcry_serpent_cbc_dec(void *context, uns + the intermediate result to SAVEBUF. */ + serpent_decrypt_internal (ctx, inbuf, savebuf); + +- buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, sizeof(serpent_block_t)); ++ cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, ++ sizeof(serpent_block_t)); + inbuf += sizeof(serpent_block_t); + outbuf += sizeof(serpent_block_t); + } +@@ -1218,7 +1222,7 @@ _gcry_serpent_cfb_dec(void *context, uns + for ( ;nblocks; nblocks-- ) + { + serpent_encrypt_internal(ctx, iv, iv); +- buf_xor_n_copy(outbuf, iv, inbuf, sizeof(serpent_block_t)); ++ cipher_block_xor_n_copy(outbuf, iv, inbuf, sizeof(serpent_block_t)); + outbuf += sizeof(serpent_block_t); + inbuf += sizeof(serpent_block_t); + } +diff -up libgcrypt-1.8.5/cipher/twofish.c.aes-perf libgcrypt-1.8.5/cipher/twofish.c +--- libgcrypt-1.8.5/cipher/twofish.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/twofish.c 2020-04-22 18:29:41.680862038 +0200 +@@ -734,12 +734,15 @@ do_twofish_setkey (TWOFISH_context *ctx, + } + + static gcry_err_code_t +-twofish_setkey (void *context, const byte *key, unsigned int keylen) ++twofish_setkey (void *context, const byte *key, unsigned int keylen, ++ gcry_cipher_hd_t hd) + { + TWOFISH_context *ctx = context; + unsigned int hwfeatures = _gcry_get_hw_features (); + int rc; + ++ (void)hd; ++ + rc = do_twofish_setkey (ctx, key, keylen); + + #ifdef USE_AVX2 +@@ -1245,7 +1248,7 @@ _gcry_twofish_ctr_enc(void *context, uns + burn_stack_depth = burn; + + /* XOR the input with the encrypted counter and store in output. */ +- buf_xor(outbuf, tmpbuf, inbuf, TWOFISH_BLOCKSIZE); ++ cipher_block_xor(outbuf, tmpbuf, inbuf, TWOFISH_BLOCKSIZE); + outbuf += TWOFISH_BLOCKSIZE; + inbuf += TWOFISH_BLOCKSIZE; + /* Increment the counter. */ +@@ -1327,7 +1330,7 @@ _gcry_twofish_cbc_dec(void *context, uns + if (burn > burn_stack_depth) + burn_stack_depth = burn; + +- buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, TWOFISH_BLOCKSIZE); ++ cipher_block_xor_n_copy_2(outbuf, savebuf, iv, inbuf, TWOFISH_BLOCKSIZE); + inbuf += TWOFISH_BLOCKSIZE; + outbuf += TWOFISH_BLOCKSIZE; + } +@@ -1399,7 +1402,7 @@ _gcry_twofish_cfb_dec(void *context, uns + if (burn > burn_stack_depth) + burn_stack_depth = burn; + +- buf_xor_n_copy(outbuf, iv, inbuf, TWOFISH_BLOCKSIZE); ++ cipher_block_xor_n_copy(outbuf, iv, inbuf, TWOFISH_BLOCKSIZE); + outbuf += TWOFISH_BLOCKSIZE; + inbuf += TWOFISH_BLOCKSIZE; + } +@@ -1710,7 +1713,7 @@ selftest (void) + 0x05, 0x93, 0x1C, 0xB6, 0xD4, 0x08, 0xE7, 0xFA + }; + +- twofish_setkey (&ctx, key, sizeof(key)); ++ twofish_setkey (&ctx, key, sizeof(key), NULL); + twofish_encrypt (&ctx, scratch, plaintext); + if (memcmp (scratch, ciphertext, sizeof (ciphertext))) + return "Twofish-128 test encryption failed."; +@@ -1718,7 +1721,7 @@ selftest (void) + if (memcmp (scratch, plaintext, sizeof (plaintext))) + return "Twofish-128 test decryption failed."; + +- twofish_setkey (&ctx, key_256, sizeof(key_256)); ++ twofish_setkey (&ctx, key_256, sizeof(key_256), NULL); + twofish_encrypt (&ctx, scratch, plaintext_256); + if (memcmp (scratch, ciphertext_256, sizeof (ciphertext_256))) + return "Twofish-256 test encryption failed."; +@@ -1800,13 +1803,13 @@ main() + /* Encryption test. */ + for (i = 0; i < 125; i++) + { +- twofish_setkey (&ctx, buffer[0], sizeof (buffer[0])); ++ twofish_setkey (&ctx, buffer[0], sizeof (buffer[0]), NULL); + for (j = 0; j < 1000; j++) + twofish_encrypt (&ctx, buffer[2], buffer[2]); +- twofish_setkey (&ctx, buffer[1], sizeof (buffer[1])); ++ twofish_setkey (&ctx, buffer[1], sizeof (buffer[1]), NULL); + for (j = 0; j < 1000; j++) + twofish_encrypt (&ctx, buffer[3], buffer[3]); +- twofish_setkey (&ctx, buffer[2], sizeof (buffer[2])*2); ++ twofish_setkey (&ctx, buffer[2], sizeof (buffer[2])*2, NULL); + for (j = 0; j < 1000; j++) { + twofish_encrypt (&ctx, buffer[0], buffer[0]); + twofish_encrypt (&ctx, buffer[1], buffer[1]); +@@ -1818,15 +1821,15 @@ main() + /* Decryption test. */ + for (i = 0; i < 125; i++) + { +- twofish_setkey (&ctx, buffer[2], sizeof (buffer[2])*2); ++ twofish_setkey (&ctx, buffer[2], sizeof (buffer[2])*2, NULL); + for (j = 0; j < 1000; j++) { + twofish_decrypt (&ctx, buffer[0], buffer[0]); + twofish_decrypt (&ctx, buffer[1], buffer[1]); + } +- twofish_setkey (&ctx, buffer[1], sizeof (buffer[1])); ++ twofish_setkey (&ctx, buffer[1], sizeof (buffer[1]), NULL); + for (j = 0; j < 1000; j++) + twofish_decrypt (&ctx, buffer[3], buffer[3]); +- twofish_setkey (&ctx, buffer[0], sizeof (buffer[0])); ++ twofish_setkey (&ctx, buffer[0], sizeof (buffer[0]), NULL); + for (j = 0; j < 1000; j++) + twofish_decrypt (&ctx, buffer[2], buffer[2]); + } +diff -up libgcrypt-1.8.5/configure.ac.aes-perf libgcrypt-1.8.5/configure.ac +--- libgcrypt-1.8.5/configure.ac.aes-perf 2020-04-22 18:29:41.655862516 +0200 ++++ libgcrypt-1.8.5/configure.ac 2020-04-22 18:29:41.681862019 +0200 +@@ -649,6 +649,14 @@ AC_ARG_ENABLE(arm-crypto-support, + armcryptosupport=$enableval,armcryptosupport=yes) + AC_MSG_RESULT($armcryptosupport) + ++# Implementation of the --disable-ppc-crypto-support switch. ++AC_MSG_CHECKING([whether PPC crypto support is requested]) ++AC_ARG_ENABLE(ppc-crypto-support, ++ AC_HELP_STRING([--disable-ppc-crypto-support], ++ [Disable support for the PPC crypto instructions introduced in POWER 8 (PowerISA 2.07)]), ++ ppccryptosupport=$enableval,ppccryptosupport=yes) ++AC_MSG_RESULT($ppccryptosupport) ++ + # Implementation of the --disable-O-flag-munging switch. + AC_MSG_CHECKING([whether a -O flag munging is requested]) + AC_ARG_ENABLE([O-flag-munging], +@@ -1196,6 +1204,9 @@ if test "$mpi_cpu_arch" != "arm" ; then + fi + fi + ++if test "$mpi_cpu_arch" != "ppc"; then ++ ppccryptosupport="n/a" ++fi + + ############################################# + #### #### +@@ -1722,6 +1733,113 @@ if test "$gcry_cv_gcc_inline_asm_aarch64 + fi + + ++# ++# Check whether PowerPC AltiVec/VSX intrinsics ++# ++AC_CACHE_CHECK([whether compiler supports PowerPC AltiVec/VSX intrinsics], ++ [gcry_cv_cc_ppc_altivec], ++ [if test "$mpi_cpu_arch" != "ppc" ; then ++ gcry_cv_cc_ppc_altivec="n/a" ++ else ++ gcry_cv_cc_ppc_altivec=no ++ AC_COMPILE_IFELSE([AC_LANG_SOURCE( ++ [[#include ++ typedef vector unsigned char block; ++ block fn(block in) ++ { ++ block t = vec_perm (in, in, vec_vsx_ld (0, (unsigned char*)0)); ++ return vec_cipher_be (t, in); ++ } ++ ]])], ++ [gcry_cv_cc_ppc_altivec=yes]) ++ fi]) ++if test "$gcry_cv_cc_ppc_altivec" = "yes" ; then ++ AC_DEFINE(HAVE_COMPATIBLE_CC_PPC_ALTIVEC,1, ++ [Defined if underlying compiler supports PowerPC AltiVec/VSX/crypto intrinsics]) ++fi ++ ++_gcc_cflags_save=$CFLAGS ++CFLAGS="$CFLAGS -maltivec -mvsx -mcrypto" ++ ++if test "$gcry_cv_cc_ppc_altivec" = "no" && ++ test "$mpi_cpu_arch" = "ppc" ; then ++ AC_CACHE_CHECK([whether compiler supports PowerPC AltiVec/VSX/crypto intrinsics with extra GCC flags], ++ [gcry_cv_cc_ppc_altivec_cflags], ++ [gcry_cv_cc_ppc_altivec_cflags=no ++ AC_COMPILE_IFELSE([AC_LANG_SOURCE( ++ [[#include ++ typedef vector unsigned char block; ++ block fn(block in) ++ { ++ block t = vec_perm (in, in, vec_vsx_ld (0, (unsigned char*)0)); ++ return vec_cipher_be (t, in); ++ }]])], ++ [gcry_cv_cc_ppc_altivec_cflags=yes])]) ++ if test "$gcry_cv_cc_ppc_altivec_cflags" = "yes" ; then ++ AC_DEFINE(HAVE_COMPATIBLE_CC_PPC_ALTIVEC,1, ++ [Defined if underlying compiler supports PowerPC AltiVec/VSX/crypto intrinsics]) ++ AC_DEFINE(HAVE_COMPATIBLE_CC_PPC_ALTIVEC_WITH_CFLAGS,1, ++ [Defined if underlying compiler supports PowerPC AltiVec/VSX/crypto intrinsics with extra GCC flags]) ++ fi ++fi ++ ++AM_CONDITIONAL(ENABLE_PPC_VCRYPTO_EXTRA_CFLAGS, ++ test "$gcry_cv_cc_ppc_altivec_cflags" = "yes") ++ ++# Restore flags. ++CFLAGS=$_gcc_cflags_save; ++ ++ ++# ++# Check whether GCC inline assembler supports PowerPC AltiVec/VSX/crypto instructions ++# ++AC_CACHE_CHECK([whether GCC inline assembler supports PowerPC AltiVec/VSX/crypto instructions], ++ [gcry_cv_gcc_inline_asm_ppc_altivec], ++ [if test "$mpi_cpu_arch" != "ppc" ; then ++ gcry_cv_gcc_inline_asm_ppc_altivec="n/a" ++ else ++ gcry_cv_gcc_inline_asm_ppc_altivec=no ++ AC_COMPILE_IFELSE([AC_LANG_SOURCE( ++ [[__asm__(".globl testfn;\n" ++ "testfn:\n" ++ "stvx %v31,%r12,%r0;\n" ++ "lvx %v20,%r12,%r0;\n" ++ "vcipher %v0, %v1, %v22;\n" ++ "lxvw4x %vs32, %r0, %r1;\n" ++ "vadduwm %v0, %v1, %v22;\n" ++ ); ++ ]])], ++ [gcry_cv_gcc_inline_asm_ppc_altivec=yes]) ++ fi]) ++if test "$gcry_cv_gcc_inline_asm_ppc_altivec" = "yes" ; then ++ AC_DEFINE(HAVE_GCC_INLINE_ASM_PPC_ALTIVEC,1, ++ [Defined if inline assembler supports PowerPC AltiVec/VSX/crypto instructions]) ++fi ++ ++ ++# ++# Check whether GCC inline assembler supports PowerISA 3.00 instructions ++# ++AC_CACHE_CHECK([whether GCC inline assembler supports PowerISA 3.00 instructions], ++ [gcry_cv_gcc_inline_asm_ppc_arch_3_00], ++ [if test "$mpi_cpu_arch" != "ppc" ; then ++ gcry_cv_gcc_inline_asm_ppc_arch_3_00="n/a" ++ else ++ gcry_cv_gcc_inline_asm_ppc_arch_3_00=no ++ AC_COMPILE_IFELSE([AC_LANG_SOURCE( ++ [[__asm__(".globl testfn;\n" ++ "testfn:\n" ++ "stxvb16x %r1,%v12,%v30;\n" ++ ); ++ ]])], ++ [gcry_cv_gcc_inline_asm_ppc_arch_3_00=yes]) ++ fi]) ++if test "$gcry_cv_gcc_inline_asm_ppc_arch_3_00" = "yes" ; then ++ AC_DEFINE(HAVE_GCC_INLINE_ASM_PPC_ARCH_3_00,1, ++ [Defined if inline assembler supports PowerISA 3.00 instructions]) ++fi ++ ++ + ####################################### + #### Checks for library functions. #### + ####################################### +@@ -1999,6 +2117,10 @@ if test x"$armcryptosupport" = xyes ; th + AC_DEFINE(ENABLE_ARM_CRYPTO_SUPPORT,1, + [Enable support for ARMv8 Crypto Extension instructions.]) + fi ++if test x"$ppccryptosupport" = xyes ; then ++ AC_DEFINE(ENABLE_PPC_CRYPTO_SUPPORT,1, ++ [Enable support for POWER 8 (PowerISA 2.07) crypto extension.]) ++fi + if test x"$jentsupport" = xyes ; then + AC_DEFINE(ENABLE_JENT_SUPPORT, 1, + [Enable support for the jitter entropy collector.]) +@@ -2106,6 +2228,21 @@ if test "$found" = "1" ; then + GCRYPT_CIPHERS="$GCRYPT_CIPHERS rijndael-armv8-ce.lo" + GCRYPT_CIPHERS="$GCRYPT_CIPHERS rijndael-armv8-aarch64-ce.lo" + ;; ++ powerpc64le-*-*) ++ # Build with the crypto extension implementation ++ GCRYPT_CIPHERS="$GCRYPT_CIPHERS rijndael-ppc.lo" ++ GCRYPT_CIPHERS="$GCRYPT_CIPHERS rijndael-ppc9le.lo" ++ ;; ++ powerpc64-*-*) ++ # Big-Endian. ++ # Build with the crypto extension implementation ++ GCRYPT_CIPHERS="$GCRYPT_CIPHERS rijndael-ppc.lo" ++ ;; ++ powerpc-*-*) ++ # Big-Endian. ++ # Build with the crypto extension implementation ++ GCRYPT_CIPHERS="$GCRYPT_CIPHERS rijndael-ppc.lo" ++ ;; + esac + + case "$mpi_cpu_arch" in +@@ -2555,6 +2692,7 @@ case "$mpi_cpu_arch" in + ;; + ppc) + AC_DEFINE(HAVE_CPU_ARCH_PPC, 1, [Defined for PPC platforms]) ++ GCRYPT_HWF_MODULES="hwf-ppc.lo" + ;; + arm) + AC_DEFINE(HAVE_CPU_ARCH_ARM, 1, [Defined for ARM platforms]) +@@ -2653,6 +2791,7 @@ GCRY_MSG_SHOW([Try using Intel AVX: + GCRY_MSG_SHOW([Try using Intel AVX2: ],[$avx2support]) + GCRY_MSG_SHOW([Try using ARM NEON: ],[$neonsupport]) + GCRY_MSG_SHOW([Try using ARMv8 crypto: ],[$armcryptosupport]) ++GCRY_MSG_SHOW([Try using PPC crypto: ],[$ppccryptosupport]) + GCRY_MSG_SHOW([],[]) + + if test "x${gpg_config_script_warn}" != x; then +diff -up libgcrypt-1.8.5/src/cipher.h.aes-perf libgcrypt-1.8.5/src/cipher.h +--- libgcrypt-1.8.5/src/cipher.h.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/src/cipher.h 2020-04-22 18:29:41.681862019 +0200 +@@ -158,6 +158,9 @@ size_t _gcry_aes_ocb_crypt (gcry_cipher_ + const void *inbuf_arg, size_t nblocks, int encrypt); + size_t _gcry_aes_ocb_auth (gcry_cipher_hd_t c, const void *abuf_arg, + size_t nblocks); ++void _gcry_aes_xts_crypt (void *context, unsigned char *tweak, ++ void *outbuf_arg, const void *inbuf_arg, ++ size_t nblocks, int encrypt); + + /*-- blowfish.c --*/ + void _gcry_blowfish_cfb_dec (void *context, unsigned char *iv, +diff -up libgcrypt-1.8.5/src/cipher-proto.h.aes-perf libgcrypt-1.8.5/src/cipher-proto.h +--- libgcrypt-1.8.5/src/cipher-proto.h.aes-perf 2020-04-22 18:29:41.643862745 +0200 ++++ libgcrypt-1.8.5/src/cipher-proto.h 2020-04-22 18:29:41.681862019 +0200 +@@ -132,7 +132,8 @@ typedef struct gcry_pk_spec + /* Type for the cipher_setkey function. */ + typedef gcry_err_code_t (*gcry_cipher_setkey_t) (void *c, + const unsigned char *key, +- unsigned keylen); ++ unsigned keylen, ++ gcry_cipher_hd_t hd); + + /* Type for the cipher_encrypt function. */ + typedef unsigned int (*gcry_cipher_encrypt_t) (void *c, +diff -up libgcrypt-1.8.5/src/g10lib.h.aes-perf libgcrypt-1.8.5/src/g10lib.h +--- libgcrypt-1.8.5/src/g10lib.h.aes-perf 2020-04-22 18:29:41.660862420 +0200 ++++ libgcrypt-1.8.5/src/g10lib.h 2020-04-22 18:50:46.990661309 +0200 +@@ -233,7 +233,9 @@ char **_gcry_strtokenize (const char *st + + #define HWF_INTEL_RDTSC (1 << 20) + +- ++#define HWF_PPC_VCRYPTO (1 << 22) ++#define HWF_PPC_ARCH_3_00 (1 << 23) ++#define HWF_PPC_ARCH_2_07 (1 << 24) + + gpg_err_code_t _gcry_disable_hw_feature (const char *name); + void _gcry_detect_hw_features (void); +diff -up libgcrypt-1.8.5/src/hwf-common.h.aes-perf libgcrypt-1.8.5/src/hwf-common.h +--- libgcrypt-1.8.5/src/hwf-common.h.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/src/hwf-common.h 2020-04-22 18:29:41.682862000 +0200 +@@ -22,6 +22,6 @@ + + unsigned int _gcry_hwf_detect_x86 (void); + unsigned int _gcry_hwf_detect_arm (void); +- ++unsigned int _gcry_hwf_detect_ppc (void); + + #endif /*HWF_COMMON_H*/ +diff -up libgcrypt-1.8.5/src/hwfeatures.c.aes-perf libgcrypt-1.8.5/src/hwfeatures.c +--- libgcrypt-1.8.5/src/hwfeatures.c.aes-perf 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/src/hwfeatures.c 2020-04-22 18:51:48.326487879 +0200 +@@ -42,6 +42,7 @@ static struct + const char *desc; + } hwflist[] = + { ++#if defined(HAVE_CPU_ARCH_X86) + { HWF_PADLOCK_RNG, "padlock-rng" }, + { HWF_PADLOCK_AES, "padlock-aes" }, + { HWF_PADLOCK_SHA, "padlock-sha" }, +@@ -58,11 +59,17 @@ static struct + { HWF_INTEL_AVX2, "intel-avx2" }, + { HWF_INTEL_FAST_VPGATHER, "intel-fast-vpgather" }, + { HWF_INTEL_RDTSC, "intel-rdtsc" }, ++#elif defined(HAVE_CPU_ARCH_ARM) + { HWF_ARM_NEON, "arm-neon" }, + { HWF_ARM_AES, "arm-aes" }, + { HWF_ARM_SHA1, "arm-sha1" }, + { HWF_ARM_SHA2, "arm-sha2" }, +- { HWF_ARM_PMULL, "arm-pmull" } ++ { HWF_ARM_PMULL, "arm-pmull" }, ++#elif defined(HAVE_CPU_ARCH_PPC) ++ { HWF_PPC_VCRYPTO, "ppc-vcrypto" }, ++ { HWF_PPC_ARCH_3_00, "ppc-arch_3_00" }, ++ { HWF_PPC_ARCH_2_07, "ppc-arch_2_07" }, ++#endif + }; + + /* A bit vector with the hardware features which shall not be used. +@@ -207,12 +214,14 @@ _gcry_detect_hw_features (void) + { + hw_features = _gcry_hwf_detect_x86 (); + } +-#endif /* HAVE_CPU_ARCH_X86 */ +-#if defined (HAVE_CPU_ARCH_ARM) ++#elif defined (HAVE_CPU_ARCH_ARM) + { + hw_features = _gcry_hwf_detect_arm (); + } +-#endif /* HAVE_CPU_ARCH_ARM */ +- ++#elif defined (HAVE_CPU_ARCH_PPC) ++ { ++ hw_features = _gcry_hwf_detect_ppc (); ++ } ++#endif + hw_features &= ~disabled_hw_features; + } +diff -up libgcrypt-1.8.5/src/hwf-ppc.c.aes-perf libgcrypt-1.8.5/src/hwf-ppc.c +--- libgcrypt-1.8.5/src/hwf-ppc.c.aes-perf 2020-04-22 18:29:41.682862000 +0200 ++++ libgcrypt-1.8.5/src/hwf-ppc.c 2020-04-22 18:50:21.396150974 +0200 +@@ -0,0 +1,243 @@ ++/* hwf-ppc.c - Detect hardware features - PPC part ++ * Copyright (C) 2013,2019 Jussi Kivilinna ++ * Copyright (C) 2019 Shawn Landden ++ * ++ * 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 . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if defined(HAVE_SYS_AUXV_H) && (defined(HAVE_GETAUXVAL) || \ ++ defined(HAVE_ELF_AUX_INFO)) ++#include ++#endif ++ ++#include "g10lib.h" ++#include "hwf-common.h" ++ ++#if !defined (__powerpc__) && !defined (__powerpc64__) ++# error Module build for wrong CPU. ++#endif ++ ++ ++#if defined(HAVE_SYS_AUXV_H) && defined(HAVE_ELF_AUX_INFO) && \ ++ !defined(HAVE_GETAUXVAL) && defined(AT_HWCAP) ++#define HAVE_GETAUXVAL ++static unsigned long getauxval(unsigned long type) ++{ ++ unsigned long auxval = 0; ++ int err; ++ ++ /* FreeBSD provides 'elf_aux_info' function that does the same as ++ * 'getauxval' on Linux. */ ++ ++ err = elf_aux_info (type, &auxval, sizeof(auxval)); ++ if (err) ++ { ++ errno = err; ++ auxval = 0; ++ } ++ ++ return auxval; ++} ++#endif ++ ++ ++#undef HAS_SYS_AT_HWCAP ++#if defined(__linux__) || \ ++ (defined(HAVE_SYS_AUXV_H) && defined(HAVE_GETAUXVAL)) ++#define HAS_SYS_AT_HWCAP 1 ++ ++struct feature_map_s ++ { ++ unsigned int hwcap_flag; ++ unsigned int hwcap2_flag; ++ unsigned int hwf_flag; ++ }; ++ ++#if defined(__powerpc__) || defined(__powerpc64__) ++ ++/* Note: These macros have same values on Linux and FreeBSD. */ ++#ifndef AT_HWCAP ++# define AT_HWCAP 16 ++#endif ++#ifndef AT_HWCAP2 ++# define AT_HWCAP2 26 ++#endif ++ ++#ifndef PPC_FEATURE2_ARCH_2_07 ++# define PPC_FEATURE2_ARCH_2_07 0x80000000 ++#endif ++#ifndef PPC_FEATURE2_VEC_CRYPTO ++# define PPC_FEATURE2_VEC_CRYPTO 0x02000000 ++#endif ++#ifndef PPC_FEATURE2_ARCH_3_00 ++# define PPC_FEATURE2_ARCH_3_00 0x00800000 ++#endif ++ ++static const struct feature_map_s ppc_features[] = ++ { ++ { 0, PPC_FEATURE2_ARCH_2_07, HWF_PPC_ARCH_2_07 }, ++#ifdef ENABLE_PPC_CRYPTO_SUPPORT ++ { 0, PPC_FEATURE2_VEC_CRYPTO, HWF_PPC_VCRYPTO }, ++#endif ++ { 0, PPC_FEATURE2_ARCH_3_00, HWF_PPC_ARCH_3_00 }, ++ }; ++#endif ++ ++static int ++get_hwcap(unsigned int *hwcap, unsigned int *hwcap2) ++{ ++ struct { unsigned long a_type; unsigned long a_val; } auxv; ++ FILE *f; ++ int err = -1; ++ static int hwcap_initialized = 0; ++ static unsigned int stored_hwcap = 0; ++ static unsigned int stored_hwcap2 = 0; ++ ++ if (hwcap_initialized) ++ { ++ *hwcap = stored_hwcap; ++ *hwcap2 = stored_hwcap2; ++ return 0; ++ } ++ ++#if 0 // TODO: configure.ac detection for __builtin_cpu_supports ++ // TODO: move to 'detect_ppc_builtin_cpu_supports' ++#if defined(__GLIBC__) && defined(__GNUC__) && __GNUC__ >= 6 ++ /* __builtin_cpu_supports returns 0 if glibc support doesn't exist, so ++ * we can only trust positive results. */ ++#ifdef ENABLE_PPC_CRYPTO_SUPPORT ++ if (__builtin_cpu_supports("vcrypto")) /* TODO: Configure.ac */ ++ { ++ stored_hwcap2 |= PPC_FEATURE2_VEC_CRYPTO; ++ hwcap_initialized = 1; ++ } ++#endif ++ ++ if (__builtin_cpu_supports("arch_3_00")) /* TODO: Configure.ac */ ++ { ++ stored_hwcap2 |= PPC_FEATURE2_ARCH_3_00; ++ hwcap_initialized = 1; ++ } ++#endif ++#endif ++ ++#if defined(HAVE_SYS_AUXV_H) && defined(HAVE_GETAUXVAL) ++ errno = 0; ++ auxv.a_val = getauxval (AT_HWCAP); ++ if (errno == 0) ++ { ++ stored_hwcap |= auxv.a_val; ++ hwcap_initialized = 1; ++ } ++ ++ if (AT_HWCAP2 >= 0) ++ { ++ errno = 0; ++ auxv.a_val = getauxval (AT_HWCAP2); ++ if (errno == 0) ++ { ++ stored_hwcap2 |= auxv.a_val; ++ hwcap_initialized = 1; ++ } ++ } ++ ++ if (hwcap_initialized && (stored_hwcap || stored_hwcap2)) ++ { ++ *hwcap = stored_hwcap; ++ *hwcap2 = stored_hwcap2; ++ return 0; ++ } ++#endif ++ ++ f = fopen("/proc/self/auxv", "r"); ++ if (!f) ++ { ++ *hwcap = stored_hwcap; ++ *hwcap2 = stored_hwcap2; ++ return -1; ++ } ++ ++ while (fread(&auxv, sizeof(auxv), 1, f) > 0) ++ { ++ if (auxv.a_type == AT_HWCAP) ++ { ++ stored_hwcap |= auxv.a_val; ++ hwcap_initialized = 1; ++ } ++ ++ if (auxv.a_type == AT_HWCAP2) ++ { ++ stored_hwcap2 |= auxv.a_val; ++ hwcap_initialized = 1; ++ } ++ } ++ ++ if (hwcap_initialized) ++ err = 0; ++ ++ fclose(f); ++ ++ *hwcap = stored_hwcap; ++ *hwcap2 = stored_hwcap2; ++ return err; ++} ++ ++static unsigned int ++detect_ppc_at_hwcap(void) ++{ ++ unsigned int hwcap; ++ unsigned int hwcap2; ++ unsigned int features = 0; ++ unsigned int i; ++ ++ if (get_hwcap(&hwcap, &hwcap2) < 0) ++ return features; ++ ++ for (i = 0; i < DIM(ppc_features); i++) ++ { ++ if (hwcap & ppc_features[i].hwcap_flag) ++ features |= ppc_features[i].hwf_flag; ++ ++ if (hwcap2 & ppc_features[i].hwcap2_flag) ++ features |= ppc_features[i].hwf_flag; ++ } ++ ++ return features; ++} ++ ++#endif ++ ++unsigned int ++_gcry_hwf_detect_ppc (void) ++{ ++ unsigned int ret = 0; ++ unsigned int broken_hwfs = 0; ++ ++#if defined (HAS_SYS_AT_HWCAP) ++ ret |= detect_ppc_at_hwcap (); ++#endif ++ ++ ret &= ~broken_hwfs; ++ ++ return ret; ++} +diff -up libgcrypt-1.8.5/src/Makefile.am.aes-perf libgcrypt-1.8.5/src/Makefile.am +--- libgcrypt-1.8.5/src/Makefile.am.aes-perf 2018-11-14 14:16:40.000000000 +0100 ++++ libgcrypt-1.8.5/src/Makefile.am 2020-04-22 18:29:41.683861981 +0200 +@@ -66,7 +66,7 @@ libgcrypt_la_SOURCES = \ + hmac256.c hmac256.h context.c context.h \ + ec-context.h + +-EXTRA_libgcrypt_la_SOURCES = hwf-x86.c hwf-arm.c ++EXTRA_libgcrypt_la_SOURCES = hwf-x86.c hwf-arm.c hwf-ppc.c + gcrypt_hwf_modules = @GCRYPT_HWF_MODULES@ + + diff --git a/libgcrypt-1.8.5-fips-module.patch b/libgcrypt-1.8.5-fips-module.patch new file mode 100644 index 0000000..60b9ce2 --- /dev/null +++ b/libgcrypt-1.8.5-fips-module.patch @@ -0,0 +1,139 @@ +diff -up libgcrypt-1.8.5/src/fips.c.fips-module libgcrypt-1.8.5/src/fips.c +--- libgcrypt-1.8.5/src/fips.c.fips-module 2020-04-20 19:07:45.924919645 +0200 ++++ libgcrypt-1.8.5/src/fips.c 2020-04-20 19:10:33.690722470 +0200 +@@ -35,10 +35,6 @@ + #include "hmac256.h" + + +-/* The name of the file used to force libgcrypt into fips mode. */ +-#define FIPS_FORCE_FILE "/etc/gcrypt/fips_enabled" +- +- + /* The states of the finite state machine used in fips mode. */ + enum module_states + { +@@ -122,54 +118,6 @@ _gcry_initialize_fips_mode (int force) + goto leave; + } + +- /* For testing the system it is useful to override the system +- provided detection of the FIPS mode and force FIPS mode using a +- file. The filename is hardwired so that there won't be any +- confusion on whether /etc/gcrypt/ or /usr/local/etc/gcrypt/ is +- actually used. The file itself may be empty. */ +- if ( !access (FIPS_FORCE_FILE, F_OK) ) +- { +- gcry_assert (!no_fips_mode_required); +- goto leave; +- } +- +- /* Checking based on /proc file properties. */ +- { +- static const char procfname[] = "/proc/sys/crypto/fips_enabled"; +- FILE *fp; +- int saved_errno; +- +- fp = fopen (procfname, "r"); +- if (fp) +- { +- char line[256]; +- +- if (fgets (line, sizeof line, fp) && atoi (line)) +- { +- /* System is in fips mode. */ +- fclose (fp); +- gcry_assert (!no_fips_mode_required); +- goto leave; +- } +- fclose (fp); +- } +- else if ((saved_errno = errno) != ENOENT +- && saved_errno != EACCES +- && !access ("/proc/version", F_OK) ) +- { +- /* Problem reading the fips file despite that we have the proc +- file system. We better stop right away. */ +- log_info ("FATAL: error reading `%s' in libgcrypt: %s\n", +- procfname, strerror (saved_errno)); +-#ifdef HAVE_SYSLOG +- syslog (LOG_USER|LOG_ERR, "Libgcrypt error: " +- "reading `%s' failed: %s - abort", +- procfname, strerror (saved_errno)); +-#endif /*HAVE_SYSLOG*/ +- abort (); +- } +- } +- + /* Fips not not requested, set flag. */ + no_fips_mode_required = 1; + +diff -up libgcrypt-1.8.5/src/g10lib.h.fips-module libgcrypt-1.8.5/src/g10lib.h +--- libgcrypt-1.8.5/src/g10lib.h.fips-module 2020-04-20 19:07:45.918919759 +0200 ++++ libgcrypt-1.8.5/src/g10lib.h 2020-04-20 19:11:05.003125740 +0200 +@@ -422,6 +422,9 @@ gpg_err_code_t _gcry_sexp_vextract_param + + /*-- fips.c --*/ + ++/* The name of the file used to force libgcrypt into fips mode. */ ++#define FIPS_FORCE_FILE "/etc/gcrypt/fips_enabled" ++ + void _gcry_initialize_fips_mode (int force); + + int _gcry_fips_mode (void); +diff -up libgcrypt-1.8.5/src/global.c.fips-module libgcrypt-1.8.5/src/global.c +--- libgcrypt-1.8.5/src/global.c.fips-module 2020-04-20 19:07:45.919919741 +0200 ++++ libgcrypt-1.8.5/src/global.c 2020-04-20 19:07:45.950919149 +0200 +@@ -160,6 +160,53 @@ void __attribute__ ((constructor)) _gcry + rv = access (FIPS_MODULE_PATH, F_OK); + if (rv < 0 && errno != ENOENT) + rv = 0; ++ ++ /* For testing the system it is useful to override the system ++ provided detection of the FIPS mode and force FIPS mode using a ++ file. The filename is hardwired so that there won't be any ++ confusion on whether /etc/gcrypt/ or /usr/local/etc/gcrypt/ is ++ actually used. The file itself may be empty. */ ++ if ( !access (FIPS_FORCE_FILE, F_OK) ) ++ { ++ rv = 0; ++ force_fips_mode = 1; ++ } ++ ++ /* Checking based on /proc file properties. */ ++ { ++ static const char procfname[] = "/proc/sys/crypto/fips_enabled"; ++ FILE *fp; ++ int saved_errno; ++ ++ fp = fopen (procfname, "r"); ++ if (fp) ++ { ++ char line[256]; ++ ++ if (fgets (line, sizeof line, fp) && atoi (line)) ++ { ++ /* System is in fips mode. */ ++ rv = 0; ++ force_fips_mode = 1; ++ } ++ fclose (fp); ++ } ++ else if ((saved_errno = errno) != ENOENT ++ && saved_errno != EACCES ++ && !access ("/proc/version", F_OK) ) ++ { ++ /* Problem reading the fips file despite that we have the proc ++ file system. We better stop right away. */ ++ log_info ("FATAL: error reading `%s' in libgcrypt: %s\n", ++ procfname, strerror (saved_errno)); ++#ifdef HAVE_SYSLOG ++ syslog (LOG_USER|LOG_ERR, "Libgcrypt error: " ++ "reading `%s' failed: %s - abort", ++ procfname, strerror (saved_errno)); ++#endif /*HAVE_SYSLOG*/ ++ abort (); ++ } ++ } + + if (!rv) + { diff --git a/libgcrypt-1.8.5-getrandom.patch b/libgcrypt-1.8.5-getrandom.patch new file mode 100644 index 0000000..ff2ef3b --- /dev/null +++ b/libgcrypt-1.8.5-getrandom.patch @@ -0,0 +1,285 @@ +diff -up libgcrypt-1.8.5/random/rand-internal.h.getrandom libgcrypt-1.8.5/random/rand-internal.h +--- libgcrypt-1.8.5/random/rand-internal.h.getrandom 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/random/rand-internal.h 2020-04-20 14:55:34.875949624 +0200 +@@ -47,6 +47,7 @@ void _gcry_random_progress (const char * + + /*-- random-csprng.c --*/ + void _gcry_rngcsprng_initialize (int full); ++void _gcry_rngcsprng_deinit (void); + void _gcry_rngcsprng_close_fds (void); + void _gcry_rngcsprng_dump_stats (void); + void _gcry_rngcsprng_secure_alloc (void); +@@ -68,6 +69,7 @@ void _gcry_rngcsprng_fast_poll (void); + + /*-- random-drbg.c --*/ + void _gcry_rngdrbg_inititialize (int full); ++void _gcry_rngdrbg_deinit (void); + void _gcry_rngdrbg_close_fds (void); + void _gcry_rngdrbg_dump_stats (void); + int _gcry_rngdrbg_is_faked (void); +diff -up libgcrypt-1.8.5/random/random.c.getrandom libgcrypt-1.8.5/random/random.c +--- libgcrypt-1.8.5/random/random.c.getrandom 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/random/random.c 2020-04-20 14:55:34.876949605 +0200 +@@ -110,8 +110,8 @@ _gcry_random_read_conf (void) + unsigned int result = 0; + + fp = fopen (fname, "r"); +- if (!fp) +- return result; ++ if (!fp) /* We make only_urandom the default. */ ++ return RANDOM_CONF_ONLY_URANDOM; + + for (;;) + { +@@ -228,6 +228,22 @@ _gcry_random_initialize (int full) + } + + ++/* Deinitialize this random subsystem. */ ++void ++_gcry_random_deinit (void) ++{ ++ if (fips_mode ()) ++ _gcry_rngdrbg_deinit (); ++ else if (rng_types.standard) ++ _gcry_rngcsprng_deinit (); ++ else if (rng_types.fips) ++ _gcry_rngdrbg_deinit (); ++ else ++ _gcry_rngcsprng_deinit (); ++ /* not needed for system */ ++} ++ ++ + /* If possible close file descriptors used by the RNG. */ + void + _gcry_random_close_fds (void) +diff -up libgcrypt-1.8.5/random/random-csprng.c.getrandom libgcrypt-1.8.5/random/random-csprng.c +--- libgcrypt-1.8.5/random/random-csprng.c.getrandom 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/random/random-csprng.c 2020-04-20 15:04:27.182877975 +0200 +@@ -55,6 +55,10 @@ + #ifdef __MINGW32__ + #include + #endif ++#if defined(__linux__) && defined(HAVE_SYSCALL) ++# include ++# include ++#endif + #include "g10lib.h" + #include "random.h" + #include "rand-internal.h" +@@ -343,6 +347,21 @@ _gcry_rngcsprng_initialize (int full) + } + + ++void ++_gcry_rngcsprng_deinit (void) ++{ ++ lock_pool(); ++ pool_writepos = 0; ++ pool_readpos = 0; ++ pool_filled = 0; ++ pool_filled_counter = 0; ++ did_initial_extra_seeding = 0; ++ pool_balance = 0; ++ just_mixed = 0; ++ unlock_pool(); ++} ++ ++ + /* Try to close the FDs of the random gather module. This is + currently only implemented for rndlinux. */ + void +@@ -1116,6 +1135,22 @@ getfnc_gather_random (void))(void (*)(co + enum random_origins, size_t, int); + + #if USE_RNDLINUX ++#if defined(__linux__) && defined(HAVE_SYSCALL) && defined(__NR_getrandom) ++ long ret; ++ char buffer[1]; ++ ++ _gcry_pre_syscall (); ++ ret = syscall (__NR_getrandom, ++ (void*)buffer, (size_t)1, (unsigned int)GRND_NONBLOCK); ++ _gcry_post_syscall (); ++ if (ret != -1 || errno != ENOSYS) ++ { ++ fnc = _gcry_rndlinux_gather_random; ++ return fnc; ++ } ++ else ++ /* The syscall is not supported - fallback to /dev/urandom. */ ++#endif + if ( !access (NAME_OF_DEV_RANDOM, R_OK) + && !access (NAME_OF_DEV_URANDOM, R_OK)) + { +diff -up libgcrypt-1.8.5/random/random-drbg.c.getrandom libgcrypt-1.8.5/random/random-drbg.c +--- libgcrypt-1.8.5/random/random-drbg.c.getrandom 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/random/random-drbg.c 2020-04-20 15:02:37.782947902 +0200 +@@ -1811,6 +1811,22 @@ _gcry_rngdrbg_inititialize (int full) + } + + /* ++ * Deinitialize the DRBG invoked by the libgcrypt API ++ * It will be automatically re-initialized on next call ++ */ ++void ++_gcry_rngdrbg_deinit (void) ++{ ++ drbg_lock (); ++ if (drbg_state) ++ { ++ drbg_uninstantiate (drbg_state); ++ drbg_state = NULL; ++ } ++ drbg_unlock (); ++} ++ ++/* + * Backend handler function for GCRYCTL_DRBG_REINIT + * + * Select a different DRBG type and initialize it. +diff -up libgcrypt-1.8.5/random/random.h.getrandom libgcrypt-1.8.5/random/random.h +--- libgcrypt-1.8.5/random/random.h.getrandom 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/random/random.h 2020-04-20 14:55:34.877949586 +0200 +@@ -29,6 +29,7 @@ void _gcry_register_random_progress (voi + + void _gcry_set_preferred_rng_type (int type); + void _gcry_random_initialize (int full); ++void _gcry_random_deinit (void); + void _gcry_random_close_fds (void); + int _gcry_get_rng_type (int ignore_fips_mode); + void _gcry_random_dump_stats(void); +diff -up libgcrypt-1.8.5/random/rndlinux.c.getrandom libgcrypt-1.8.5/random/rndlinux.c +--- libgcrypt-1.8.5/random/rndlinux.c.getrandom 2020-04-20 15:01:50.159848963 +0200 ++++ libgcrypt-1.8.5/random/rndlinux.c 2020-04-20 16:14:21.901610921 +0200 +@@ -35,6 +35,7 @@ + #include + #if defined(__linux__) && defined(HAVE_SYSCALL) + # include ++# include + #endif + + #include "types.h" +@@ -147,12 +148,12 @@ _gcry_rndlinux_gather_random (void (*add + if (!add) + { + /* Special mode to close the descriptors. */ +- if (fd_random != -1) ++ if (fd_random >= 0) + { + close (fd_random); + fd_random = -1; + } +- if (fd_urandom != -1) ++ if (fd_urandom >= 0) + { + close (fd_urandom); + fd_urandom = -1; +@@ -166,12 +167,12 @@ _gcry_rndlinux_gather_random (void (*add + apid = getpid (); + if (my_pid != apid) + { +- if (fd_random != -1) ++ if (fd_random >= 0) + { + close (fd_random); + fd_random = -1; + } +- if (fd_urandom != -1) ++ if (fd_urandom >= 0) + { + close (fd_urandom); + fd_urandom = -1; +@@ -216,7 +217,23 @@ _gcry_rndlinux_gather_random (void (*add + that we always require the device to be existent but want a more + graceful behaviour if the rarely needed close operation has been + used and the device needs to be re-opened later. */ +- if (level >= GCRY_VERY_STRONG_RANDOM && !only_urandom) ++#if defined(__linux__) && defined(HAVE_SYSCALL) && defined(__NR_getrandom) ++ if (fd_urandom != -2 && !_gcry_in_constructor ()) ++ { ++ long ret; ++ ++ _gcry_pre_syscall (); ++ ret = syscall (__NR_getrandom, ++ (void*)buffer, (size_t)1, (unsigned int)GRND_NONBLOCK); ++ _gcry_post_syscall (); ++ if (ret > -1 || errno == EAGAIN || errno == EINTR) ++ { ++ fd_urandom = -2; ++ fd_random = -2; ++ } ++ } ++#endif ++ if (level >= GCRY_VERY_STRONG_RANDOM && !only_urandom && !_gcry_in_constructor ()) + { + if (fd_random == -1) + { +@@ -255,6 +272,7 @@ _gcry_rndlinux_gather_random (void (*add + * syscall and not a new device and thus we are not able to use + * select(2) to have a timeout. */ + #if defined(__linux__) && defined(HAVE_SYSCALL) && defined(__NR_getrandom) ++ if (fd == -2) + { + long ret; + size_t nbytes; +@@ -270,9 +288,7 @@ _gcry_rndlinux_gather_random (void (*add + _gcry_post_syscall (); + } + while (ret == -1 && errno == EINTR); +- if (ret == -1 && errno == ENOSYS) +- ; /* The syscall is not supported - fallback to pulling from fd. */ +- else ++ if (1) + { /* The syscall is supported. Some sanity checks. */ + if (ret == -1) + log_fatal ("unexpected error from getrandom: %s\n", +diff -up libgcrypt-1.8.5/src/g10lib.h.getrandom libgcrypt-1.8.5/src/g10lib.h +--- libgcrypt-1.8.5/src/g10lib.h.getrandom 2020-04-20 15:08:16.528538580 +0200 ++++ libgcrypt-1.8.5/src/g10lib.h 2020-04-20 15:08:28.641309399 +0200 +@@ -464,6 +464,6 @@ gpg_err_code_t _gcry_fips_run_selftests + void _gcry_fips_noreturn (void); + #define fips_noreturn() (_gcry_fips_noreturn ()) + +- ++int _gcry_in_constructor (void); + + #endif /* G10LIB_H */ +diff -up libgcrypt-1.8.5/src/global.c.getrandom libgcrypt-1.8.5/src/global.c +--- libgcrypt-1.8.5/src/global.c.getrandom 2020-04-20 15:06:21.891707597 +0200 ++++ libgcrypt-1.8.5/src/global.c 2020-04-20 15:07:29.018437509 +0200 +@@ -145,10 +145,18 @@ global_init (void) + #define FIPS_MODULE_PATH "/etc/system-fips" + #endif + ++static int in_constructor = 0; ++ ++int _gcry_in_constructor(void) ++{ ++ return in_constructor; ++} ++ + void __attribute__ ((constructor)) _gcry_global_constructor (void) + { + int rv; + ++ in_constructor = 1; + rv = access (FIPS_MODULE_PATH, F_OK); + if (rv < 0 && errno != ENOENT) + rv = 0; +@@ -163,10 +171,12 @@ void __attribute__ ((constructor)) _gcry + /* force selftests */ + global_init(); + _gcry_fips_run_selftests (0); +- if (!fips_mode()) +- _gcry_random_close_fds (); ++ _gcry_random_close_fds (); ++ _gcry_random_deinit (); + no_secure_memory = no_secmem_save; + } ++ ++ in_constructor = 0; + } + + /* This function is called by the macro fips_is_operational and makes diff --git a/libgcrypt-1.8.5-intel-cet.patch b/libgcrypt-1.8.5-intel-cet.patch new file mode 100644 index 0000000..f58084e --- /dev/null +++ b/libgcrypt-1.8.5-intel-cet.patch @@ -0,0 +1,348 @@ +diff -up libgcrypt-1.8.5/cipher/camellia-aesni-avx2-amd64.S.intel-cet libgcrypt-1.8.5/cipher/camellia-aesni-avx2-amd64.S +--- libgcrypt-1.8.5/cipher/camellia-aesni-avx2-amd64.S.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/camellia-aesni-avx2-amd64.S 2020-01-23 15:36:44.148972045 +0100 +@@ -18,8 +18,9 @@ + * License along with this program; if not, see . + */ + +-#ifdef __x86_64 + #include ++ ++#ifdef __x86_64 + #if (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) && \ + defined(ENABLE_AESNI_SUPPORT) && defined(ENABLE_AVX2_SUPPORT) +diff -up libgcrypt-1.8.5/cipher/camellia-aesni-avx-amd64.S.intel-cet libgcrypt-1.8.5/cipher/camellia-aesni-avx-amd64.S +--- libgcrypt-1.8.5/cipher/camellia-aesni-avx-amd64.S.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/camellia-aesni-avx-amd64.S 2020-01-23 15:36:44.145972088 +0100 +@@ -18,8 +18,9 @@ + * License along with this program; if not, see . + */ + +-#ifdef __x86_64 + #include ++ ++#ifdef __x86_64 + #if (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) && \ + defined(ENABLE_AESNI_SUPPORT) && defined(ENABLE_AVX_SUPPORT) +diff -up libgcrypt-1.8.5/cipher/chacha20-avx2-amd64.S.intel-cet libgcrypt-1.8.5/cipher/chacha20-avx2-amd64.S +--- libgcrypt-1.8.5/cipher/chacha20-avx2-amd64.S.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/chacha20-avx2-amd64.S 2020-01-23 15:36:16.780250066 +0100 +@@ -48,6 +48,9 @@ + .globl _gcry_chacha20_amd64_avx2_blocks + ELF(.type _gcry_chacha20_amd64_avx2_blocks,@function;) + _gcry_chacha20_amd64_avx2_blocks: ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + .Lchacha_blocks_avx2_local: + vzeroupper + pushq %rbx +diff -up libgcrypt-1.8.5/cipher/chacha20-sse2-amd64.S.intel-cet libgcrypt-1.8.5/cipher/chacha20-sse2-amd64.S +--- libgcrypt-1.8.5/cipher/chacha20-sse2-amd64.S.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/chacha20-sse2-amd64.S 2020-01-23 15:36:16.783250095 +0100 +@@ -41,6 +41,9 @@ + .globl _gcry_chacha20_amd64_sse2_blocks + ELF(.type _gcry_chacha20_amd64_sse2_blocks,@function;) + _gcry_chacha20_amd64_sse2_blocks: ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + .Lchacha_blocks_sse2_local: + pushq %rbx + pushq %rbp +diff -up libgcrypt-1.8.5/cipher/poly1305-avx2-amd64.S.intel-cet libgcrypt-1.8.5/cipher/poly1305-avx2-amd64.S +--- libgcrypt-1.8.5/cipher/poly1305-avx2-amd64.S.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/poly1305-avx2-amd64.S 2020-01-23 15:36:16.784250105 +0100 +@@ -43,6 +43,9 @@ + .globl _gcry_poly1305_amd64_avx2_init_ext + ELF(.type _gcry_poly1305_amd64_avx2_init_ext,@function;) + _gcry_poly1305_amd64_avx2_init_ext: ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + .Lpoly1305_init_ext_avx2_local: + xor %edx, %edx + vzeroupper +@@ -406,6 +409,9 @@ ELF(.size _gcry_poly1305_amd64_avx2_init + .globl _gcry_poly1305_amd64_avx2_blocks + ELF(.type _gcry_poly1305_amd64_avx2_blocks,@function;) + _gcry_poly1305_amd64_avx2_blocks: ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + .Lpoly1305_blocks_avx2_local: + vzeroupper + pushq %rbp +@@ -732,6 +738,9 @@ ELF(.size _gcry_poly1305_amd64_avx2_bloc + .globl _gcry_poly1305_amd64_avx2_finish_ext + ELF(.type _gcry_poly1305_amd64_avx2_finish_ext,@function;) + _gcry_poly1305_amd64_avx2_finish_ext: ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + .Lpoly1305_finish_ext_avx2_local: + vzeroupper + pushq %rbp +diff -up libgcrypt-1.8.5/cipher/poly1305-sse2-amd64.S.intel-cet libgcrypt-1.8.5/cipher/poly1305-sse2-amd64.S +--- libgcrypt-1.8.5/cipher/poly1305-sse2-amd64.S.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/poly1305-sse2-amd64.S 2020-01-23 15:36:16.787250134 +0100 +@@ -42,6 +42,9 @@ + .globl _gcry_poly1305_amd64_sse2_init_ext + ELF(.type _gcry_poly1305_amd64_sse2_init_ext,@function;) + _gcry_poly1305_amd64_sse2_init_ext: ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + .Lpoly1305_init_ext_x86_local: + xor %edx, %edx + pushq %r12 +@@ -288,6 +291,9 @@ ELF(.size _gcry_poly1305_amd64_sse2_init + .globl _gcry_poly1305_amd64_sse2_finish_ext + ELF(.type _gcry_poly1305_amd64_sse2_finish_ext,@function;) + _gcry_poly1305_amd64_sse2_finish_ext: ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + .Lpoly1305_finish_ext_x86_local: + pushq %rbp + movq %rsp, %rbp +@@ -439,6 +445,9 @@ ELF(.size _gcry_poly1305_amd64_sse2_fini + .globl _gcry_poly1305_amd64_sse2_blocks + ELF(.type _gcry_poly1305_amd64_sse2_blocks,@function;) + _gcry_poly1305_amd64_sse2_blocks: ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + .Lpoly1305_blocks_x86_local: + pushq %rbp + movq %rsp, %rbp +diff -up libgcrypt-1.8.5/cipher/serpent-avx2-amd64.S.intel-cet libgcrypt-1.8.5/cipher/serpent-avx2-amd64.S +--- libgcrypt-1.8.5/cipher/serpent-avx2-amd64.S.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/cipher/serpent-avx2-amd64.S 2020-01-23 15:36:44.151972003 +0100 +@@ -18,8 +18,9 @@ + * License along with this program; if not, see . + */ + +-#ifdef __x86_64 + #include ++ ++#ifdef __x86_64 + #if (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \ + defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) && defined(USE_SERPENT) && \ + defined(ENABLE_AVX2_SUPPORT) +diff -up libgcrypt-1.8.5/configure.ac.intel-cet libgcrypt-1.8.5/configure.ac +--- libgcrypt-1.8.5/configure.ac.intel-cet 2019-08-29 15:00:08.000000000 +0200 ++++ libgcrypt-1.8.5/configure.ac 2020-01-23 15:35:28.147774463 +0100 +@@ -95,6 +95,12 @@ AH_TOP([ + AH_BOTTOM([ + #define _GCRYPT_IN_LIBGCRYPT 1 + ++/* Add .note.gnu.property section for Intel CET in assembler sources ++ when CET is enabled. */ ++#if defined(__ASSEMBLER__) && defined(__CET__) ++# include ++#endif ++ + /* If the configure check for endianness has been disabled, get it from + OS macros. This is intended for making fat binary builds on OS X. */ + #ifdef DISABLED_ENDIAN_CHECK +diff -up libgcrypt-1.8.5/mpi/config.links.intel-cet libgcrypt-1.8.5/mpi/config.links +--- libgcrypt-1.8.5/mpi/config.links.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/mpi/config.links 2020-01-23 15:35:46.398952954 +0100 +@@ -382,6 +382,16 @@ if test x"$mpi_cpu_arch" = x ; then + mpi_cpu_arch="unknown" + fi + ++# Add .note.gnu.property section for Intel CET in assembler sources ++# when CET is enabled. */ ++if test x"$mpi_cpu_arch" = xx86 ; then ++ cat <> ./mpi/asm-syntax.h ++ ++#if defined(__ASSEMBLER__) && defined(__CET__) ++# include ++#endif ++EOF ++fi + + # Make sysdep.h + echo '/* created by config.links - do not edit */' >./mpi/sysdep.h +diff -up libgcrypt-1.8.5/mpi/i386/mpih-add1.S.intel-cet libgcrypt-1.8.5/mpi/i386/mpih-add1.S +--- libgcrypt-1.8.5/mpi/i386/mpih-add1.S.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/mpi/i386/mpih-add1.S 2020-01-23 15:37:40.470175379 +0100 +@@ -52,6 +52,10 @@ C_SYMBOL_NAME(_gcry_mpih_add_n:) + movl 20(%esp),%edx /* s2_ptr */ + movl 24(%esp),%ecx /* size */ + ++#if defined __CET__ && (__CET__ & 1) != 0 ++ pushl %ebx ++#endif ++ + movl %ecx,%eax + shrl $3,%ecx /* compute count for unrolled loop */ + negl %eax +@@ -63,6 +67,9 @@ C_SYMBOL_NAME(_gcry_mpih_add_n:) + subl %eax,%esi /* ... by a constant when we ... */ + subl %eax,%edx /* ... enter the loop */ + shrl $2,%eax /* restore previous value */ ++#if defined __CET__ && (__CET__ & 1) != 0 ++ leal -4(,%eax,4),%ebx /* Count for 4-byte endbr32 */ ++#endif + #ifdef PIC + /* Calculate start address in loop for PIC. Due to limitations in some + assemblers, Loop-L0-3 cannot be put into the leal */ +@@ -75,29 +82,53 @@ L0: leal (%eax,%eax,8),%eax + /* Calculate start address in loop for non-PIC. */ + leal (Loop - 3)(%eax,%eax,8),%eax + #endif ++#if defined __CET__ && (__CET__ & 1) != 0 ++ addl %ebx,%eax /* Adjust for endbr32 */ ++#endif + jmp *%eax /* jump into loop */ + ALIGN (3) + Loop: movl (%esi),%eax + adcl (%edx),%eax + movl %eax,(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 4(%esi),%eax + adcl 4(%edx),%eax + movl %eax,4(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 8(%esi),%eax + adcl 8(%edx),%eax + movl %eax,8(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 12(%esi),%eax + adcl 12(%edx),%eax + movl %eax,12(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 16(%esi),%eax + adcl 16(%edx),%eax + movl %eax,16(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 20(%esi),%eax + adcl 20(%edx),%eax + movl %eax,20(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 24(%esi),%eax + adcl 24(%edx),%eax + movl %eax,24(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 28(%esi),%eax + adcl 28(%edx),%eax + movl %eax,28(%edi) +@@ -110,6 +141,10 @@ Loop: movl (%esi),%eax + sbbl %eax,%eax + negl %eax + ++#if defined __CET__ && (__CET__ & 1) != 0 ++ popl %ebx ++#endif ++ + popl %esi + popl %edi + ret +diff -up libgcrypt-1.8.5/mpi/i386/mpih-sub1.S.intel-cet libgcrypt-1.8.5/mpi/i386/mpih-sub1.S +--- libgcrypt-1.8.5/mpi/i386/mpih-sub1.S.intel-cet 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/mpi/i386/mpih-sub1.S 2020-01-23 15:37:40.472175351 +0100 +@@ -53,6 +53,10 @@ C_SYMBOL_NAME(_gcry_mpih_sub_n:) + movl 20(%esp),%edx /* s2_ptr */ + movl 24(%esp),%ecx /* size */ + ++#if defined __CET__ && (__CET__ & 1) != 0 ++ pushl %ebx ++#endif ++ + movl %ecx,%eax + shrl $3,%ecx /* compute count for unrolled loop */ + negl %eax +@@ -64,6 +68,9 @@ C_SYMBOL_NAME(_gcry_mpih_sub_n:) + subl %eax,%esi /* ... by a constant when we ... */ + subl %eax,%edx /* ... enter the loop */ + shrl $2,%eax /* restore previous value */ ++#if defined __CET__ && (__CET__ & 1) != 0 ++ leal -4(,%eax,4),%ebx /* Count for 4-byte endbr32 */ ++#endif + #ifdef PIC + /* Calculate start address in loop for PIC. Due to limitations in some + assemblers, Loop-L0-3 cannot be put into the leal */ +@@ -76,29 +83,53 @@ L0: leal (%eax,%eax,8),%eax + /* Calculate start address in loop for non-PIC. */ + leal (Loop - 3)(%eax,%eax,8),%eax + #endif ++#if defined __CET__ && (__CET__ & 1) != 0 ++ addl %ebx,%eax /* Adjust for endbr32 */ ++#endif + jmp *%eax /* jump into loop */ + ALIGN (3) + Loop: movl (%esi),%eax + sbbl (%edx),%eax + movl %eax,(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 4(%esi),%eax + sbbl 4(%edx),%eax + movl %eax,4(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 8(%esi),%eax + sbbl 8(%edx),%eax + movl %eax,8(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 12(%esi),%eax + sbbl 12(%edx),%eax + movl %eax,12(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 16(%esi),%eax + sbbl 16(%edx),%eax + movl %eax,16(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 20(%esi),%eax + sbbl 20(%edx),%eax + movl %eax,20(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 24(%esi),%eax + sbbl 24(%edx),%eax + movl %eax,24(%edi) ++#ifdef _CET_ENDBR ++ _CET_ENDBR ++#endif + movl 28(%esi),%eax + sbbl 28(%edx),%eax + movl %eax,28(%edi) +@@ -111,6 +142,10 @@ Loop: movl (%esi),%eax + sbbl %eax,%eax + negl %eax + ++#if defined __CET__ && (__CET__ & 1) != 0 ++ popl %ebx ++#endif ++ + popl %esi + popl %edi + ret diff --git a/libgcrypt-1.8.5-use-fipscheck.patch b/libgcrypt-1.8.5-use-fipscheck.patch new file mode 100644 index 0000000..298ec4c --- /dev/null +++ b/libgcrypt-1.8.5-use-fipscheck.patch @@ -0,0 +1,89 @@ +diff -up libgcrypt-1.8.5/src/fips.c.use-fipscheck libgcrypt-1.8.5/src/fips.c +--- libgcrypt-1.8.5/src/fips.c.use-fipscheck 2017-11-23 19:16:58.000000000 +0100 ++++ libgcrypt-1.8.5/src/fips.c 2020-04-23 10:18:36.235764741 +0200 +@@ -581,23 +581,50 @@ run_random_selftests (void) + return !!err; + } + ++#ifdef ENABLE_HMAC_BINARY_CHECK ++static int ++get_library_path(const char *libname, const char *symbolname, char *path, size_t pathlen) ++{ ++ Dl_info info; ++ void *dl, *sym; ++ int rv = -1; ++ ++ dl = dlopen(libname, RTLD_LAZY); ++ if (dl == NULL) { ++ return -1; ++ } ++ ++ sym = dlsym(dl, symbolname); ++ ++ if (sym != NULL && dladdr(sym, &info)) { ++ strncpy(path, info.dli_fname, pathlen-1); ++ path[pathlen-1] = '\0'; ++ rv = 0; ++ } ++ ++ dlclose(dl); ++ ++ return rv; ++} ++#endif ++ + /* Run an integrity check on the binary. Returns 0 on success. */ + static int + check_binary_integrity (void) + { + #ifdef ENABLE_HMAC_BINARY_CHECK + gpg_error_t err; +- Dl_info info; ++ char libpath[4096]; + unsigned char digest[32]; + int dlen; + char *fname = NULL; +- const char key[] = "What am I, a doctor or a moonshuttle conductor?"; +- +- if (!dladdr ("gcry_check_version", &info)) ++ const char key[] = "orboDeJITITejsirpADONivirpUkvarP"; ++ ++ if (get_library_path ("libgcrypt.so.20", "gcry_check_version", libpath, sizeof(libpath))) + err = gpg_error_from_syserror (); + else + { +- dlen = _gcry_hmac256_file (digest, sizeof digest, info.dli_fname, ++ dlen = _gcry_hmac256_file (digest, sizeof digest, libpath, + key, strlen (key)); + if (dlen < 0) + err = gpg_error_from_syserror (); +@@ -605,7 +632,7 @@ check_binary_integrity (void) + err = gpg_error (GPG_ERR_INTERNAL); + else + { +- fname = xtrymalloc (strlen (info.dli_fname) + 1 + 5 + 1 ); ++ fname = xtrymalloc (strlen (libpath) + 1 + 5 + 1 ); + if (!fname) + err = gpg_error_from_syserror (); + else +@@ -614,7 +641,7 @@ check_binary_integrity (void) + char *p; + + /* Prefix the basename with a dot. */ +- strcpy (fname, info.dli_fname); ++ strcpy (fname, libpath); + p = strrchr (fname, '/'); + if (p) + p++; +diff -up libgcrypt-1.8.5/src/Makefile.am.use-fipscheck libgcrypt-1.8.5/src/Makefile.am +--- libgcrypt-1.8.5/src/Makefile.am.use-fipscheck 2020-04-23 10:18:36.237764702 +0200 ++++ libgcrypt-1.8.5/src/Makefile.am 2020-04-23 10:19:03.186247455 +0200 +@@ -125,7 +125,7 @@ libgcrypt_la_LIBADD = $(gcrypt_res) \ + ../cipher/libcipher.la \ + ../random/librandom.la \ + ../mpi/libmpi.la \ +- ../compat/libcompat.la $(GPG_ERROR_LIBS) ++ ../compat/libcompat.la $(GPG_ERROR_LIBS) -ldl + + + dumpsexp_SOURCES = dumpsexp.c diff --git a/libgcrypt.spec b/libgcrypt.spec new file mode 100644 index 0000000..89f5ef1 --- /dev/null +++ b/libgcrypt.spec @@ -0,0 +1,637 @@ +Name: libgcrypt +Version: 1.8.6 +Release: 4%{?dist} +URL: http://www.gnupg.org/ +Source0: libgcrypt-%{version}-hobbled.tar.xz +# The original libgcrypt sources now contain potentially patented ECC +# cipher support. We have to remove it in the tarball we ship with +# the hobble-libgcrypt script. +# (We replace it with RH approved ECC in Source4-5) +#Source0: ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-{version}.tar.bz2 +#Source1: ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-{version}.tar.bz2.sig +Source2: wk@g10code.com +Source3: hobble-libgcrypt +# Approved ECC support +Source4: ecc-curves.c +Source5: curves.c +Source6: t-mpi-point.c +Source7: random.conf +# make FIPS hmac compatible with fipscheck - non upstreamable +# update on soname bump +Patch2: libgcrypt-1.8.5-use-fipscheck.patch +# modify FIPS RSA and DSA keygen to comply with requirements +Patch5: libgcrypt-1.8.4-fips-keygen.patch +# fix the tests to work correctly in the FIPS mode +Patch6: libgcrypt-1.8.4-tests-fipsmode.patch +# update the CAVS tests +Patch7: libgcrypt-1.7.3-fips-cavs.patch +# use poll instead of select when gathering randomness +Patch11: libgcrypt-1.8.4-use-poll.patch +# slight optimalization of mpicoder.c to silence Valgrind (#968288) +Patch13: libgcrypt-1.6.1-mpicoder-gccopt.patch +# fix tests to work with approved ECC +Patch14: libgcrypt-1.7.3-ecc-test-fix.patch +# Run the FIPS mode initialization in the shared library constructor +Patch18: libgcrypt-1.8.3-fips-ctor.patch +# Block some operations if in FIPS non-operational state +Patch22: libgcrypt-1.7.3-fips-reqs.patch +# Do not try to open /dev/urandom if getrandom() works +Patch24: libgcrypt-1.8.5-getrandom.patch +# CMAC selftest for FIPS POST +Patch25: libgcrypt-1.8.3-cmac-selftest.patch +# Continuous FIPS entropy test +Patch26: libgcrypt-1.8.3-fips-enttest.patch +# Disable non-approved FIPS hashes in the enforced FIPS mode +Patch27: libgcrypt-1.8.3-md-fips-enforce.patch +# Intel CET support, in upstream master +Patch28: libgcrypt-1.8.5-intel-cet.patch +# FIPS module is redefined a little bit (implicit by kernel FIPS mode) +Patch30: libgcrypt-1.8.5-fips-module.patch +# Backported AES performance improvements +Patch31: libgcrypt-1.8.5-aes-perf.patch + +%global gcrylibdir %{_libdir} +%global gcrysoname libgcrypt.so.20 +%global hmackey orboDeJITITejsirpADONivirpUkvarP + +# Technically LGPLv2.1+, but Fedora's table doesn't draw a distinction. +# Documentation and some utilities are GPLv2+ licensed. These files +# are in the devel subpackage. +License: LGPLv2+ +Summary: A general-purpose cryptography library +BuildRequires: gcc +BuildRequires: gawk, libgpg-error-devel >= 1.11, pkgconfig +# This is needed only when patching the .texi doc. +BuildRequires: texinfo +BuildRequires: autoconf, automake, libtool + +%package devel +Summary: Development files for the %{name} package +License: LGPLv2+ and GPLv2+ +Requires: libgpg-error-devel +Requires: %{name} = %{version}-%{release} +Requires: pkgconfig + +%description +Libgcrypt is a general purpose crypto library based on the code used +in GNU Privacy Guard. This is a development version. + +%description devel +Libgcrypt is a general purpose crypto library based on the code used +in GNU Privacy Guard. This package contains files needed to develop +applications using libgcrypt. + +%prep +%setup -q +%{SOURCE3} +%patch2 -p1 -b .use-fipscheck +%patch5 -p1 -b .fips-keygen +%patch6 -p1 -b .tests-fipsmode +%patch7 -p1 -b .cavs +%patch11 -p1 -b .use-poll +%patch13 -p1 -b .gccopt +%patch14 -p1 -b .eccfix +%patch18 -p1 -b .fips-ctor +%patch22 -p1 -b .fips-reqs +%patch24 -p1 -b .getrandom +%patch25 -p1 -b .cmac-selftest +%patch26 -p1 -b .fips-enttest +%patch27 -p1 -b .fips-enforce +%patch28 -p1 -b .intel-cet +%patch30 -p1 -b .fips-module +%patch31 -p1 -b .aes-perf + +cp %{SOURCE4} cipher/ +cp %{SOURCE5} %{SOURCE6} tests/ + +%build +# This package has a configure test which uses ASMs, but does not link the +# resultant .o files. As such the ASM test is always successful, even on +# architectures were the ASM is not valid when compiling with LTO. +# +# -ffat-lto-objects is sufficient to address this issue. It is the default +# for F33, but is expected to only be enabled for packages that need it in +# F34, so we use it here explicitly +%define _lto_cflags -flto=auto -ffat-lto-objects + +autoreconf -f +%configure --disable-static \ +%ifarch sparc64 + --disable-asm \ +%endif + --enable-noexecstack \ + --enable-hmac-binary-check \ + --enable-pubkey-ciphers='dsa elgamal rsa ecc' \ + --disable-O-flag-munging +sed -i -e '/^sys_lib_dlsearch_path_spec/s,/lib /usr/lib,/usr/lib /lib64 /usr/lib64 /lib,g' libtool +%make_build + +%check +src/hmac256 %{hmackey} src/.libs/%{gcrysoname} | cut -f1 -d ' ' >src/.libs/.%{gcrysoname}.hmac + +make check + +# Add generation of HMAC checksums of the final stripped binaries +%define __spec_install_post \ + %{?__debug_package:%{__debug_install_post}} \ + %{__arch_install_post} \ + %{__os_install_post} \ + src/hmac256 %{hmackey} $RPM_BUILD_ROOT%{gcrylibdir}/%{gcrysoname} | cut -f1 -d ' ' >$RPM_BUILD_ROOT%{gcrylibdir}/.%{gcrysoname}.hmac \ +%{nil} + +%install +%make_install + +# Change /usr/lib64 back to /usr/lib. This saves us from having to patch the +# script to "know" that -L/usr/lib64 should be suppressed, and also removes +# a file conflict between 32- and 64-bit versions of this package. +# Also replace my_host with none. +sed -i -e 's,^libdir="/usr/lib.*"$,libdir="/usr/lib",g' $RPM_BUILD_ROOT/%{_bindir}/libgcrypt-config +sed -i -e 's,^my_host=".*"$,my_host="none",g' $RPM_BUILD_ROOT/%{_bindir}/libgcrypt-config + +rm -f ${RPM_BUILD_ROOT}/%{_infodir}/dir ${RPM_BUILD_ROOT}/%{_libdir}/*.la +/sbin/ldconfig -n $RPM_BUILD_ROOT/%{_libdir} + +%if "%{gcrylibdir}" != "%{_libdir}" +# Relocate the shared libraries to %{gcrylibdir}. +mkdir -p $RPM_BUILD_ROOT%{gcrylibdir} +for shlib in $RPM_BUILD_ROOT%{_libdir}/*.so* ; do + if test -L "$shlib" ; then + rm "$shlib" + else + mv "$shlib" $RPM_BUILD_ROOT%{gcrylibdir}/ + fi +done + +# Add soname symlink. +/sbin/ldconfig -n $RPM_BUILD_ROOT/%{_lib}/ +%endif + +# Overwrite development symlinks. +pushd $RPM_BUILD_ROOT/%{gcrylibdir} +for shlib in lib*.so.?? ; do + target=$RPM_BUILD_ROOT/%{_libdir}/`echo "$shlib" | sed -e 's,\.so.*,,g'`.so +%if "%{gcrylibdir}" != "%{_libdir}" + shlib=%{gcrylibdir}/$shlib +%endif + ln -sf $shlib $target +done +popd + +# Create /etc/gcrypt (hardwired, not dependent on the configure invocation) so +# that _someone_ owns it. +mkdir -p -m 755 $RPM_BUILD_ROOT/etc/gcrypt +install -m644 %{SOURCE7} $RPM_BUILD_ROOT/etc/gcrypt/random.conf + +%ldconfig_scriptlets + +%files +%dir /etc/gcrypt +%config(noreplace) /etc/gcrypt/random.conf +%{gcrylibdir}/libgcrypt.so.*.* +%{gcrylibdir}/%{gcrysoname} +%{gcrylibdir}/.%{gcrysoname}.hmac +%{!?_licensedir:%global license %%doc} +%license COPYING.LIB +%doc AUTHORS NEWS THANKS + +%files devel +%{_bindir}/%{name}-config +%{_bindir}/dumpsexp +%{_bindir}/hmac256 +%{_bindir}/mpicalc +%{_includedir}/* +%{_libdir}/*.so +%{_libdir}/pkgconfig/libgcrypt.pc +%{_datadir}/aclocal/* +%{_mandir}/man1/* + +%{_infodir}/gcrypt.info* +%{!?_licensedir:%global license %%doc} +%license COPYING + +%changelog +* Fri Aug 21 2020 Jeff Law - 1.8.6-4 +- Re-enable LTO + +* Tue Jul 28 2020 Fedora Release Engineering - 1.8.6-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Tue Jul 21 2020 Tom Stellard - 1.8.6-2 +- Use make macros +- https://fedoraproject.org/wiki/Changes/UseMakeBuildInstallMacro + +* Mon Jul 20 2020 Tomáš Mráz 1.8.6-1 +- new upstream version 1.8.6 + +* Wed Jul 1 2020 Tomáš Mráz 1.8.5-7 +- use the hmac256 tool to calculate the library hmac + +* Tue Jun 30 2020 Jeff Law +- Disable LTO + +* Thu Apr 23 2020 Tomáš Mráz 1.8.5-6 +- Fix regression - missing -ldl linkage + +* Wed Apr 22 2020 Tomáš Mráz 1.8.5-5 +- AES performance improvements backported from master branch + +* Mon Apr 20 2020 Tomáš Mráz 1.8.5-4 +- FIPS selftest is run directly from the constructor +- FIPS module is implicit with kernel FIPS flag + +* Thu Jan 30 2020 Tomáš Mráz 1.8.5-3 +- fix the build on ARMv7 + +* Thu Jan 23 2020 Tomáš Mráz 1.8.5-2 +- Intel CET support by H. J. Lu + +* Tue Sep 3 2019 Tomáš Mráz 1.8.5-1 +- new upstream version 1.8.5 +- add CMAC selftest for FIPS POST +- add continuous FIPS entropy test +- disable non-approved FIPS hashes in the enforced FIPS mode + +* Thu Jul 25 2019 Fedora Release Engineering - 1.8.4-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + +* Tue Feb 12 2019 Tomáš Mráz 1.8.4-3 +- fix the build tests to pass in the FIPS mode + +* Fri Feb 01 2019 Fedora Release Engineering - 1.8.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Tue Nov 20 2018 Tomáš Mráz 1.8.4-1 +- new upstream version 1.8.4 + +* Fri Jul 13 2018 Fedora Release Engineering - 1.8.3-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Thu Jul 12 2018 Tomáš Mráz 1.8.3-2 +- make only_urandom a default in non-presence of configuration file +- run the full FIPS selftests only when the library is called from + application + +* Thu Jun 14 2018 Tomáš Mráz 1.8.3-1 +- new upstream version 1.8.3 + +* Tue Feb 6 2018 Tomáš Mráz 1.8.2-2 +- fix behavior when getrandom syscall is not present (#1542453) + +* Thu Dec 21 2017 Tomáš Mráz 1.8.2-1 +- new upstream version 1.8.2 + +* Tue Dec 5 2017 Tomáš Mráz 1.8.1-3 +- do not try to access() /dev/urandom either if getrandom() works + +* Mon Dec 4 2017 Tomáš Mráz 1.8.1-2 +- do not try to open /dev/urandom if getrandom() works (#1380866) + +* Tue Sep 5 2017 Tomáš Mráz 1.8.1-1 +- new upstream version 1.8.1 + +* Wed Aug 16 2017 Tomáš Mráz 1.8.0-1 +- new upstream version 1.8.0 + +* Thu Aug 03 2017 Fedora Release Engineering - 1.7.8-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 1.7.8-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Thu Jun 29 2017 Tomáš Mráz 1.7.8-1 +- new upstream version 1.7.8 + +* Fri Jun 2 2017 Tomáš Mráz 1.7.7-1 +- new upstream version 1.7.7 +- GOST is now enabled + +* Fri Feb 10 2017 Fedora Release Engineering - 1.7.6-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Mon Jan 30 2017 Tomáš Mráz 1.7.6-1 +- new upstream version 1.7.6 + +* Fri Dec 16 2016 Tomáš Mráz 1.7.5-1 +- new upstream version 1.7.5 + +* Wed Nov 23 2016 Tomáš Mráz 1.7.3-1 +- new upstream version 1.7.3 + +* Wed Aug 17 2016 Tomáš Mráz 1.6.6-1 +- new upstream version with important security fix (CVE-2016-6316) + +* Thu Jul 21 2016 Tomáš Mráz 1.6.5-1 +- new upstream version fixing low impact issue CVE-2015-7511 + +* Thu Feb 04 2016 Fedora Release Engineering - 1.6.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Wed Sep 9 2015 Tomáš Mráz 1.6.4-1 +- new upstream version + +* Wed Jun 17 2015 Fedora Release Engineering - 1.6.3-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Fri Apr 3 2015 Tomáš Mráz 1.6.3-4 +- deinitialize the RNG after the selftest is run + +* Tue Mar 24 2015 Tomáš Mráz 1.6.3-3 +- touch only urandom in the selftest and when /dev/random is + unavailable for example by SELinux confinement +- fix the RSA selftest key (p q swap) (#1204517) + +* Fri Mar 13 2015 Tomáš Mráz 1.6.3-2 +- do not use strict aliasing for bufhelp functions (#1201219) + +* Fri Mar 6 2015 Tomáš Mráz 1.6.3-1 +- new upstream version + +* Wed Feb 25 2015 Tomáš Mráz 1.6.2-4 +- do not initialize secure memory during the selftest (#1195850) + +* Sat Feb 21 2015 Till Maas - 1.6.2-3 +- Rebuilt for Fedora 23 Change + https://fedoraproject.org/wiki/Changes/Harden_all_packages_with_position-independent_code + +* Wed Jan 14 2015 Tomáš Mráz 1.6.2-2 +- fix buildability of programs using gcrypt.h with -ansi (#1182200) + +* Mon Dec 8 2014 Tomáš Mráz 1.6.2-1 +- new upstream version + +* Sun Aug 17 2014 Fedora Release Engineering - 1.6.1-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Thu Jul 17 2014 Tom Callaway - 1.6.1-6 +- fix license handling + +* Sat Jun 07 2014 Fedora Release Engineering - 1.6.1-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Tue May 20 2014 Kyle McMartin 1.6.1-4 +- Re-enable below algos, apply patch from upstream list to make + that code -fPIC friendly. (rhbz#1069792) + +* Mon May 19 2014 Kyle McMartin 1.6.1-3 +- Disable rijndael, cast5, camellia ARM assembly, as it's non-PIC as + presently written, which results in .text relocations in the shared + library. (rhbz#1069792) + +* Thu Apr 24 2014 Tomáš Mráz 1.6.1-2 +- drop the temporary compat shared library version +- fix the soname version in -use-fipscheck.patch + +* Fri Feb 28 2014 Tomáš Mráz 1.6.1-1 +- new upstream version breaking ABI compatibility +- this release temporarily includes old compatibility .so + +* Tue Jan 21 2014 Tomáš Mráz 1.5.3-3 +- add back the nistp521r1 EC curve +- fix a bug in the Whirlpool hash implementation +- speed up the PBKDF2 computation + +* Sun Oct 20 2013 Tom Callaway - 1.5.3-2 +- add cleared ECC support + +* Fri Jul 26 2013 Tomáš Mráz 1.5.3-1 +- new upstream version fixing cache side-channel attack on RSA private keys + +* Thu Jun 20 2013 Tomáš Mráz 1.5.2-3 +- silence false error detected by valgrind (#968288) + +* Thu Apr 25 2013 Tomáš Mráz 1.5.2-2 +- silence strict aliasing warning in Rijndael +- apply UsrMove +- spec file cleanups + +* Fri Apr 19 2013 Tomáš Mráz 1.5.2-1 +- new upstream version + +* Wed Mar 20 2013 Tomas Mraz 1.5.1-1 +- new upstream version + +* Tue Mar 5 2013 Tomas Mraz 1.5.0-11 +- use poll() instead of select() when gathering randomness (#913773) + +* Thu Feb 14 2013 Fedora Release Engineering - 1.5.0-10 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Thu Jan 3 2013 Tomas Mraz 1.5.0-9 +- allow empty passphrase in PBKDF2 needed for cryptsetup (=891266) + +* Mon Dec 3 2012 Tomas Mraz 1.5.0-8 +- fix multilib conflict in libgcrypt-config +- fix minor memory leaks and other bugs found by Coverity scan + +* Thu Jul 19 2012 Fedora Release Engineering - 1.5.0-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Thu Apr 5 2012 Tomas Mraz 1.5.0-5 +- Correctly rebuild the info documentation + +* Wed Apr 4 2012 Tomas Mraz 1.5.0-4 +- Add GCRYCTL_SET_ENFORCED_FIPS_FLAG command + +* Fri Jan 13 2012 Fedora Release Engineering - 1.5.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Mon Aug 15 2011 Kalev Lember 1.5.0-2 +- Rebuilt for rpm bug #728707 + +* Thu Jul 21 2011 Tomas Mraz 1.5.0-1 +- new upstream version + +* Mon Jun 20 2011 Tomas Mraz 1.4.6-4 +- Always xor seed from /dev/urandom over /etc/gcrypt/rngseed + +* Mon May 30 2011 Tomas Mraz 1.4.6-3 +- Make the FIPS-186-3 DSA implementation CAVS testable +- add configurable source of RNG seed /etc/gcrypt/rngseed + in the FIPS mode (#700388) + +* Fri Feb 11 2011 Tomas Mraz 1.4.6-1 +- new upstream version with minor changes + +* Mon Feb 07 2011 Fedora Release Engineering - 1.4.5-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Fri Feb 4 2011 Tomas Mraz 1.4.5-6 +- fix a bug in the fips-186-3 dsa parameter generation code + +* Tue Feb 1 2011 Tomas Mraz 1.4.5-5 +- use /dev/urandom for seeding in the FIPS mode +- make the tests to pass in the FIPS mode also fixing + the FIPS-186-3 DSA keygen + +* Sun Feb 14 2010 Rex Dieter 1.4.5-4 +- FTBFS libgcrypt-1.4.5-3.fc13: ImplicitDSOLinking (#564973) + +* Wed Feb 3 2010 Tomas Mraz 1.4.5-3 +- drop the S390 build workaround as it is no longer needed +- additional spec file cleanups for merge review (#226008) + +* Mon Dec 21 2009 Tomas Mraz 1.4.5-1 +- workaround for build on S390 (#548825) +- spec file cleanups +- upgrade to new minor upstream release + +* Tue Aug 11 2009 Tomas Mraz 1.4.4-8 +- fix warning when installed with --excludedocs (#515961) + +* Fri Jul 24 2009 Fedora Release Engineering - 1.4.4-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Thu Jun 18 2009 Tomas Mraz 1.4.4-6 +- and now really apply the padlock patch + +* Wed Jun 17 2009 Tomas Mraz 1.4.4-5 +- fix VIA padlock RNG inline assembly call (#505724) + +* Thu Mar 5 2009 Tomas Mraz 1.4.4-4 +- with the integrity verification check the library needs to link to libdl + (#488702) + +* Tue Mar 3 2009 Tomas Mraz 1.4.4-3 +- add hmac FIPS integrity verification check + +* Wed Feb 25 2009 Fedora Release Engineering - 1.4.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Fri Jan 30 2009 Tomas Mraz 1.4.4-1 +- update to 1.4.4 +- do not abort when the fips mode kernel flag is inaccessible + due to permissions (#470219) +- hobble the library to drop the ECC support + +* Mon Oct 20 2008 Dennis Gilmore 1.4.3-2 +- disable asm on sparc64 + +* Thu Sep 18 2008 Nalin Dahyabhai 1.4.3-1 +- update to 1.4.3 +- own /etc/gcrypt + +* Mon Sep 15 2008 Nalin Dahyabhai +- invoke make with %%{?_smp_mflags} to build faster on multi-processor + systems (Steve Grubb) + +* Mon Sep 8 2008 Nalin Dahyabhai 1.4.2-1 +- update to 1.4.2 + +* Tue Apr 29 2008 Nalin Dahyabhai 1.4.1-1 +- update to 1.4.1 +- bump libgpgerror-devel requirement to 1.4, matching the requirement enforced + by the configure script + +* Thu Apr 3 2008 Joe Orton 1.4.0-3 +- add patch from upstream to fix severe performance regression + in entropy gathering + +* Tue Feb 19 2008 Fedora Release Engineering - 1.4.0-2 +- Autorebuild for GCC 4.3 + +* Mon Dec 10 2007 Nalin Dahyabhai - 1.4.0-1 +- update to 1.4.0 + +* Tue Oct 16 2007 Nalin Dahyabhai - 1.2.4-6 +- use ldconfig to build the soname symlink for packaging along with the + shared library (#334731) + +* Wed Aug 22 2007 Nalin Dahyabhai - 1.2.4-5 +- add missing gawk buildrequirement +- switch from explicitly specifying the /dev/random RNG to just verifying + that the non-LGPL ones were disabled by the configure script + +* Thu Aug 16 2007 Nalin Dahyabhai - 1.2.4-4 +- clarify license +- force use of the linux /dev/random RNG, to avoid accidentally falling back + to others which would affect the license of the resulting library + +* Mon Jul 30 2007 Nalin Dahyabhai - 1.2.4-3 +- disable static libraries (part of #249815) + +* Fri Jul 27 2007 Nalin Dahyabhai - 1.2.4-2 +- move libgcrypt shared library to /%%{_lib} (#249815) + +* Tue Feb 6 2007 Nalin Dahyabhai - 1.2.4-1 +- update to 1.2.4 + +* Mon Jan 22 2007 Nalin Dahyabhai - 1.2.3-2 +- make use of install-info more failsafe (Ville Skyttä, #223705) + +* Fri Sep 1 2006 Nalin Dahyabhai - 1.2.3-1 +- update to 1.2.3 + +* Wed Jul 12 2006 Jesse Keating - 1.2.2-3.1 +- rebuild + +* Mon Jun 05 2006 Jesse Keating 1.2.2-3 +- Added missing buildreq pkgconfig + +* Tue May 16 2006 Nalin Dahyabhai 1.2.2-2 +- remove file conflicts in libgcrypt-config by making the 64-bit version + think the libraries are in /usr/lib (which is wrong, but which it also + prunes from the suggest --libs output, so no harm done, hopefully) + +* Fri Feb 10 2006 Jesse Keating - 1.2.2-1.2.1 +- bump again for double-long bug on ppc(64) + +* Tue Feb 07 2006 Jesse Keating - 1.2.2-1.2 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Wed Oct 5 2005 Nalin Dahyabhai 1.2.2-1 +- update to 1.2.2 + +* Wed Mar 16 2005 Nalin Dahyabhai 1.2.1-1 +- update to 1.2.1 + +* Fri Jul 30 2004 Florian La Roche +- another try to package the symlink + +* Tue Jun 15 2004 Elliot Lee +- rebuilt + +* Sun May 2 2004 Bill Nottingham - 1.2.0-1 +- update to official 1.2.0 + +* Fri Apr 16 2004 Bill Nottingham - 1.1.94-1 +- update to 1.1.94 + +* Tue Mar 02 2004 Elliot Lee +- rebuilt + +* Sat Feb 21 2004 Florian La Roche +- add symlinks to shared libs at compile time + +* Fri Feb 13 2004 Elliot Lee +- rebuilt + +* Wed Jun 04 2003 Elliot Lee +- rebuilt + +* Thu Mar 20 2003 Jeff Johnson 1.1.12-1 +- upgrade to 1.1.12 (beta). + +* Fri Jun 21 2002 Tim Powers +- automated rebuild + +* Sun May 26 2002 Tim Powers +- automated rebuild + +* Tue May 21 2002 Jeff Johnson +- update to 1.1.7 +- change license to LGPL. +- include splint annotations patch. +- install info pages. + +* Tue Apr 2 2002 Nalin Dahyabhai 1.1.6-1 +- update to 1.1.6 + +* Thu Jan 10 2002 Nalin Dahyabhai 1.1.5-1 +- fix the Source tag so that it's a real URL + +* Thu Dec 20 2001 Nalin Dahyabhai +- initial package diff --git a/random.conf b/random.conf new file mode 100644 index 0000000..6041bcd --- /dev/null +++ b/random.conf @@ -0,0 +1,4 @@ +# use only /dev/urandom - see https://www.2uo.de/myths-about-urandom/ +only-urandom +# Keep jitter entropy generator enabled (should do no harm) +#disable-jent diff --git a/sources b/sources new file mode 100644 index 0000000..09310c9 --- /dev/null +++ b/sources @@ -0,0 +1 @@ +SHA512 (libgcrypt-1.8.6-hobbled.tar.xz) = b59a3c6544e989033acb1f75a526487075b12aac65f18e38264aa9921fe89306485bfee5f4b0dd75d9ed4a35f23851d302359983c75d6f5a0d6f74007a553743 diff --git a/t-mpi-point.c b/t-mpi-point.c new file mode 100644 index 0000000..2a8c36c --- /dev/null +++ b/t-mpi-point.c @@ -0,0 +1,1213 @@ +/* t-mpi-point.c - Tests for mpi point functions + * 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 . + */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include +#include +#include +#include +#include + +#define PGM "t-mpi-point" +#include "t-common.h" + +static struct +{ + const char *desc; /* Description of the 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. */ + const char *h; /* Cofactor. */ +} test_curve[] = + { + { + "NIST P-224", + "0xffffffffffffffffffffffffffffffff000000000000000000000001", + "0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe", + "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", + "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d" , + + "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", + "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34", + "0x01" + }, + { + "NIST P-256", + "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff", + "0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc", + "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", + "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + + "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", + "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", + "0x01" + }, + { + "NIST P-384", + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe" + "ffffffff0000000000000000ffffffff", + "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe" + "ffffffff0000000000000000fffffffc", + "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875a" + "c656398d8a2ed19d2a85c8edd3ec2aef", + "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf" + "581a0db248b0a77aecec196accc52973", + + "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a38" + "5502f25dbf55296c3a545e3872760ab7", + "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c0" + "0a60b1ce1d7e819d7a431d7c90ea0e5f", + "0x01" + }, + { + "NIST P-521", + "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc", + "0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef10" + "9e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", + "0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "ffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409", + + "0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3d" + "baa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", + "0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e6" + "62c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", + "0x01" + }, + { + "Ed25519", + "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED", + "0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC", + "0x52036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978A3", + "0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED", + "0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A", + "0x6666666666666666666666666666666666666666666666666666666666666658", + "0x08" + }, + { NULL, NULL, NULL, NULL, NULL, NULL } + }; + +/* A sample public key for NIST P-256. */ +static const char sample_p256_q[] = + "04" + "42B927242237639A36CE9221B340DB1A9AB76DF2FE3E171277F6A4023DED146E" + "E86525E38CCECFF3FB8D152CC6334F70D23A525175C1BCBDDE6E023B2228770E"; +static const char sample_p256_q_x[] = + "42B927242237639A36CE9221B340DB1A9AB76DF2FE3E171277F6A4023DED146E"; +static const char sample_p256_q_y[] = + "00E86525E38CCECFF3FB8D152CC6334F70D23A525175C1BCBDDE6E023B2228770E"; + + +/* A sample public key for Ed25519. */ +static const char sample_ed25519_q[] = + "04" + "55d0e09a2b9d34292297e08d60d0f620c513d47253187c24b12786bd777645ce" + "1a5107f7681a02af2523a6daf372e10e3a0764c9d3fe4bd5b70ab18201985ad7"; +static const char sample_ed25519_q_x[] = + "55d0e09a2b9d34292297e08d60d0f620c513d47253187c24b12786bd777645ce"; +static const char sample_ed25519_q_y[] = + "1a5107f7681a02af2523a6daf372e10e3a0764c9d3fe4bd5b70ab18201985ad7"; +static const char sample_ed25519_q_eddsa[] = + "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a"; +static const char sample_ed25519_d[] = + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"; + + +static void +print_mpi_2 (const char *text, const char *text2, gcry_mpi_t a) +{ + gcry_error_t err; + char *buf; + void *bufaddr = &buf; + + err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a); + if (err) + fprintf (stderr, "%s%s: [error printing number: %s]\n", + text, text2? text2:"", gpg_strerror (err)); + else + { + fprintf (stderr, "%s%s: %s\n", text, text2? text2:"", buf); + gcry_free (buf); + } +} + + +static void +print_mpi (const char *text, gcry_mpi_t a) +{ + print_mpi_2 (text, NULL, a); +} + + +static void +print_point (const char *text, gcry_mpi_point_t a) +{ + gcry_mpi_t x, y, z; + + x = gcry_mpi_new (0); + y = gcry_mpi_new (0); + z = gcry_mpi_new (0); + gcry_mpi_point_get (x, y, z, a); + print_mpi_2 (text, ".x", x); + print_mpi_2 (text, ".y", y); + print_mpi_2 (text, ".z", z); + gcry_mpi_release (x); + gcry_mpi_release (y); + gcry_mpi_release (z); +} + + +static void +print_sexp (const char *prefix, gcry_sexp_t a) +{ + char *buf; + size_t size; + + if (prefix) + fputs (prefix, stderr); + size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0); + buf = gcry_xmalloc (size); + + gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size); + fprintf (stderr, "%.*s", (int)size, buf); + gcry_free (buf); +} + + +static gcry_mpi_t +hex2mpi (const char *string) +{ + gpg_error_t err; + gcry_mpi_t val; + + err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL); + if (err) + die ("hex2mpi '%s' failed: %s\n", string, gpg_strerror (err)); + return val; +} + + +/* Convert STRING consisting of hex characters into its binary + representation and return it as an allocated buffer. The valid + length of the buffer is returned at R_LENGTH. The string is + delimited by end of string. The function returns NULL on + error. */ +static void * +hex2buffer (const char *string, size_t *r_length) +{ + const char *s; + unsigned char *buffer; + size_t length; + + buffer = xmalloc (strlen(string)/2+1); + length = 0; + for (s=string; *s; s +=2 ) + { + if (!hexdigitp (s) || !hexdigitp (s+1)) + return NULL; /* Invalid hex digits. */ + ((unsigned char*)buffer)[length++] = xtoi_2 (s); + } + *r_length = length; + return buffer; +} + + +static gcry_mpi_t +hex2mpiopa (const char *string) +{ + char *buffer; + size_t buflen; + gcry_mpi_t val; + + buffer = hex2buffer (string, &buflen); + if (!buffer) + die ("hex2mpiopa '%s' failed: parser error\n", string); + val = gcry_mpi_set_opaque (NULL, buffer, buflen*8); + if (!buffer) + die ("hex2mpiopa '%s' failed: set_opaque error\n", string); + return val; +} + + +/* Compare A to B, where B is given as a hex string. */ +static int +cmp_mpihex (gcry_mpi_t a, const char *b) +{ + gcry_mpi_t bval; + int res; + + if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)) + bval = hex2mpiopa (b); + else + bval = hex2mpi (b); + res = gcry_mpi_cmp (a, bval); + gcry_mpi_release (bval); + return res; +} + + +/* Wrapper to emulate the libgcrypt internal EC context allocation + function. */ +static gpg_error_t +ec_p_new (gcry_ctx_t *r_ctx, gcry_mpi_t p, gcry_mpi_t a) +{ + gpg_error_t err; + gcry_sexp_t sexp; + + if (p && a) + err = gcry_sexp_build (&sexp, NULL, "(ecdsa (p %m)(a %m))", p, a); + else if (p) + err = gcry_sexp_build (&sexp, NULL, "(ecdsa (p %m))", p); + else if (a) + err = gcry_sexp_build (&sexp, NULL, "(ecdsa (a %m))", a); + else + err = gcry_sexp_build (&sexp, NULL, "(ecdsa)"); + if (err) + return err; + err = gcry_mpi_ec_new (r_ctx, sexp, NULL); + gcry_sexp_release (sexp); + return err; +} + + + +static void +set_get_point (void) +{ + gcry_mpi_point_t point, point2; + gcry_mpi_t x, y, z; + + wherestr = "set_get_point"; + info ("checking point setting functions\n"); + + point = gcry_mpi_point_new (0); + x = gcry_mpi_set_ui (NULL, 17); + y = gcry_mpi_set_ui (NULL, 42); + z = gcry_mpi_set_ui (NULL, 11371); + gcry_mpi_point_get (x, y, z, point); + if (gcry_mpi_cmp_ui (x, 0) + || gcry_mpi_cmp_ui (y, 0) || gcry_mpi_cmp_ui (z, 0)) + fail ("new point not initialized to (0,0,0)\n"); + gcry_mpi_point_snatch_get (x, y, z, point); + point = NULL; + if (gcry_mpi_cmp_ui (x, 0) + || gcry_mpi_cmp_ui (y, 0) || gcry_mpi_cmp_ui (z, 0)) + fail ("snatch_get failed\n"); + gcry_mpi_release (x); + gcry_mpi_release (y); + gcry_mpi_release (z); + + point = gcry_mpi_point_new (0); + x = gcry_mpi_set_ui (NULL, 17); + y = gcry_mpi_set_ui (NULL, 42); + z = gcry_mpi_set_ui (NULL, 11371); + gcry_mpi_point_set (point, x, y, z); + gcry_mpi_set_ui (x, 23); + gcry_mpi_set_ui (y, 24); + gcry_mpi_set_ui (z, 25); + gcry_mpi_point_get (x, y, z, point); + if (gcry_mpi_cmp_ui (x, 17) + || gcry_mpi_cmp_ui (y, 42) || gcry_mpi_cmp_ui (z, 11371)) + fail ("point_set/point_get failed\n"); + gcry_mpi_point_snatch_set (point, x, y, z); + x = gcry_mpi_new (0); + y = gcry_mpi_new (0); + z = gcry_mpi_new (0); + gcry_mpi_point_get (x, y, z, point); + if (gcry_mpi_cmp_ui (x, 17) + || gcry_mpi_cmp_ui (y, 42) || gcry_mpi_cmp_ui (z, 11371)) + fail ("point_snatch_set/point_get failed\n"); + + point2 = gcry_mpi_point_copy (point); + + gcry_mpi_point_get (x, y, z, point2); + if (gcry_mpi_cmp_ui (x, 17) + || gcry_mpi_cmp_ui (y, 42) || gcry_mpi_cmp_ui (z, 11371)) + fail ("point_copy failed (1)\n"); + + gcry_mpi_point_release (point); + + gcry_mpi_point_get (x, y, z, point2); + if (gcry_mpi_cmp_ui (x, 17) + || gcry_mpi_cmp_ui (y, 42) || gcry_mpi_cmp_ui (z, 11371)) + fail ("point_copy failed (2)\n"); + + gcry_mpi_point_release (point2); + + gcry_mpi_release (x); + gcry_mpi_release (y); + gcry_mpi_release (z); +} + + +static void +context_alloc (void) +{ + gpg_error_t err; + gcry_ctx_t ctx; + gcry_mpi_t p, a; + + wherestr = "context_alloc"; + info ("checking context functions\n"); + + p = gcry_mpi_set_ui (NULL, 1); + a = gcry_mpi_set_ui (NULL, 1); + err = ec_p_new (&ctx, p, a); + if (err) + die ("ec_p_new returned an error: %s\n", gpg_strerror (err)); + gcry_mpi_release (p); + gcry_mpi_release (a); + gcry_ctx_release (ctx); + + p = NULL; + a = gcry_mpi_set_ui (NULL, 0); + + err = ec_p_new (&ctx, p, a); + if (!err || gpg_err_code (err) != GPG_ERR_EINVAL) + fail ("ec_p_new: bad parameter detection failed (1)\n"); + + gcry_mpi_release (a); + a = NULL; + err = ec_p_new (&ctx, p, a); + if (!err || gpg_err_code (err) != GPG_ERR_EINVAL) + fail ("ec_p_new: bad parameter detection failed (2)\n"); + +} + + +static int +get_and_cmp_mpi (const char *name, const char *mpistring, const char *desc, + gcry_ctx_t ctx) +{ + gcry_mpi_t mpi; + + mpi = gcry_mpi_ec_get_mpi (name, ctx, 1); + if (!mpi) + { + fail ("error getting parameter '%s' of curve '%s'\n", name, desc); + return 1; + } + if (debug) + print_mpi (name, mpi); + if (cmp_mpihex (mpi, mpistring)) + { + fail ("parameter '%s' of curve '%s' does not match\n", name, desc); + gcry_mpi_release (mpi); + return 1; + } + gcry_mpi_release (mpi); + return 0; +} + + +static int +get_and_cmp_point (const char *name, + const char *mpi_x_string, const char *mpi_y_string, + const char *desc, gcry_ctx_t ctx) +{ + gcry_mpi_point_t point; + gcry_mpi_t x, y, z; + int result = 0; + + point = gcry_mpi_ec_get_point (name, ctx, 1); + if (!point) + { + fail ("error getting point parameter '%s' of curve '%s'\n", name, desc); + return 1; + } + if (debug) + print_point (name, point); + + x = gcry_mpi_new (0); + y = gcry_mpi_new (0); + z = gcry_mpi_new (0); + gcry_mpi_point_snatch_get (x, y, z, point); + if (cmp_mpihex (x, mpi_x_string)) + { + fail ("x coordinate of '%s' of curve '%s' does not match\n", name, desc); + result = 1; + } + if (cmp_mpihex (y, mpi_y_string)) + { + fail ("y coordinate of '%s' of curve '%s' does not match\n", name, desc); + result = 1; + } + if (cmp_mpihex (z, "01")) + { + fail ("z coordinate of '%s' of curve '%s' is not 1\n", name, desc); + result = 1; + } + gcry_mpi_release (x); + gcry_mpi_release (y); + gcry_mpi_release (z); + return result; +} + + +static void +context_param (void) +{ + gpg_error_t err; + int idx; + gcry_ctx_t ctx = NULL; + gcry_mpi_t q, d; + gcry_sexp_t keyparam; + + wherestr = "context_param"; + + info ("checking standard curves\n"); + for (idx=0; test_curve[idx].desc; idx++) + { + /* P-192 and Ed25519 are not supported in fips mode */ + if (gcry_fips_mode_active()) + { + if (!strcmp(test_curve[idx].desc, "NIST P-192") + || !strcmp(test_curve[idx].desc, "Ed25519")) + { + info ("skipping %s in fips mode\n", test_curve[idx].desc ); + continue; + } + } + + gcry_ctx_release (ctx); + err = gcry_mpi_ec_new (&ctx, NULL, test_curve[idx].desc); + if (err) + { + fail ("can't create context for curve '%s': %s\n", + test_curve[idx].desc, gpg_strerror (err)); + continue; + } + if (get_and_cmp_mpi ("p", test_curve[idx].p, test_curve[idx].desc, ctx)) + continue; + if (get_and_cmp_mpi ("a", test_curve[idx].a, test_curve[idx].desc, ctx)) + continue; + if (get_and_cmp_mpi ("b", test_curve[idx].b, test_curve[idx].desc, ctx)) + continue; + if (get_and_cmp_mpi ("g.x",test_curve[idx].g_x, test_curve[idx].desc,ctx)) + continue; + if (get_and_cmp_mpi ("g.y",test_curve[idx].g_y, test_curve[idx].desc,ctx)) + continue; + if (get_and_cmp_mpi ("n", test_curve[idx].n, test_curve[idx].desc, ctx)) + continue; + if (get_and_cmp_point ("g", test_curve[idx].g_x, test_curve[idx].g_y, + test_curve[idx].desc, ctx)) + continue; + if (get_and_cmp_mpi ("h", test_curve[idx].h, test_curve[idx].desc, ctx)) + continue; + + } + + info ("checking sample public key (nistp256)\n"); + q = hex2mpi (sample_p256_q); + err = gcry_sexp_build (&keyparam, NULL, + "(public-key(ecc(curve %s)(q %m)))", + "NIST P-256", q); + if (err) + die ("gcry_sexp_build failed: %s\n", gpg_strerror (err)); + gcry_mpi_release (q); + + /* We can't call gcry_pk_testkey because it is only implemented for + private keys. */ + /* err = gcry_pk_testkey (keyparam); */ + /* if (err) */ + /* fail ("gcry_pk_testkey failed for sample public key: %s\n", */ + /* gpg_strerror (err)); */ + + gcry_ctx_release (ctx); + err = gcry_mpi_ec_new (&ctx, keyparam, NULL); + if (err) + fail ("gcry_mpi_ec_new failed for sample public key (nistp256): %s\n", + gpg_strerror (err)); + else + { + gcry_sexp_t sexp; + + get_and_cmp_mpi ("q", sample_p256_q, "nistp256", ctx); + get_and_cmp_point ("q", sample_p256_q_x, sample_p256_q_y, "nistp256", + ctx); + + /* Delete Q. */ + err = gcry_mpi_ec_set_mpi ("q", NULL, ctx); + if (err) + fail ("clearing Q for nistp256 failed: %s\n", gpg_strerror (err)); + if (gcry_mpi_ec_get_mpi ("q", ctx, 0)) + fail ("clearing Q for nistp256 did not work\n"); + + /* Set Q again. */ + q = hex2mpi (sample_p256_q); + err = gcry_mpi_ec_set_mpi ("q", q, ctx); + if (err) + fail ("setting Q for nistp256 failed: %s\n", gpg_strerror (err)); + get_and_cmp_mpi ("q", sample_p256_q, "nistp256(2)", ctx); + gcry_mpi_release (q); + + /* Get as s-expression. */ + err = gcry_pubkey_get_sexp (&sexp, 0, ctx); + if (err) + fail ("gcry_pubkey_get_sexp(0) failed: %s\n", gpg_strerror (err)); + else if (debug) + print_sexp ("Result of gcry_pubkey_get_sexp (0):\n", sexp); + gcry_sexp_release (sexp); + + err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_PUBKEY, ctx); + if (err) + fail ("gcry_pubkey_get_sexp(GET_PUBKEY) failed: %s\n", + gpg_strerror (err)); + else if (debug) + print_sexp ("Result of gcry_pubkey_get_sexp (GET_PUBKEY):\n", sexp); + gcry_sexp_release (sexp); + + err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_SECKEY, ctx); + if (gpg_err_code (err) != GPG_ERR_NO_SECKEY) + fail ("gcry_pubkey_get_sexp(GET_SECKEY) returned wrong error: %s\n", + gpg_strerror (err)); + gcry_sexp_release (sexp); + } + + /* Skipping Ed25519 if in FIPS mode (it isn't supported) */ + if (gcry_fips_mode_active()) + goto cleanup; + + info ("checking sample public key (Ed25519)\n"); + q = hex2mpi (sample_ed25519_q); + gcry_sexp_release (keyparam); + err = gcry_sexp_build (&keyparam, NULL, + "(public-key(ecc(curve %s)(flags eddsa)(q %m)))", + "Ed25519", q); + if (err) + die ("gcry_sexp_build failed: %s\n", gpg_strerror (err)); + gcry_mpi_release (q); + + /* We can't call gcry_pk_testkey because it is only implemented for + private keys. */ + /* err = gcry_pk_testkey (keyparam); */ + /* if (err) */ + /* fail ("gcry_pk_testkey failed for sample public key: %s\n", */ + /* gpg_strerror (err)); */ + + gcry_ctx_release (ctx); + err = gcry_mpi_ec_new (&ctx, keyparam, NULL); + if (err) + fail ("gcry_mpi_ec_new failed for sample public key: %s\n", + gpg_strerror (err)); + else + { + gcry_sexp_t sexp; + + get_and_cmp_mpi ("q", sample_ed25519_q, "Ed25519", ctx); + get_and_cmp_point ("q", sample_ed25519_q_x, sample_ed25519_q_y, + "Ed25519", ctx); + get_and_cmp_mpi ("q@eddsa", sample_ed25519_q_eddsa, "Ed25519", ctx); + + /* Set d to see whether Q is correctly re-computed. */ + d = hex2mpi (sample_ed25519_d); + err = gcry_mpi_ec_set_mpi ("d", d, ctx); + if (err) + fail ("setting d for Ed25519 failed: %s\n", gpg_strerror (err)); + gcry_mpi_release (d); + get_and_cmp_mpi ("q", sample_ed25519_q, "Ed25519(recompute Q)", ctx); + + /* Delete Q by setting d and then clearing d. The clearing is + required so that we can check whether Q has been cleared and + because further tests only expect a public key. */ + d = hex2mpi (sample_ed25519_d); + err = gcry_mpi_ec_set_mpi ("d", d, ctx); + if (err) + fail ("setting d for Ed25519 failed: %s\n", gpg_strerror (err)); + gcry_mpi_release (d); + err = gcry_mpi_ec_set_mpi ("d", NULL, ctx); + if (err) + fail ("setting d for Ed25519 failed(2): %s\n", gpg_strerror (err)); + if (gcry_mpi_ec_get_mpi ("q", ctx, 0)) + fail ("setting d for Ed25519 did not reset Q\n"); + + /* Set Q again. We need to use an opaque MPI here because + sample_ed25519_q is in uncompressed format which can only be + auto-detected if passed opaque. */ + q = hex2mpiopa (sample_ed25519_q); + err = gcry_mpi_ec_set_mpi ("q", q, ctx); + if (err) + fail ("setting Q for Ed25519 failed: %s\n", gpg_strerror (err)); + gcry_mpi_release (q); + get_and_cmp_mpi ("q", sample_ed25519_q, "Ed25519(2)", ctx); + + /* Get as s-expression. */ + err = gcry_pubkey_get_sexp (&sexp, 0, ctx); + if (err) + fail ("gcry_pubkey_get_sexp(0) failed: %s\n", gpg_strerror (err)); + else if (debug) + print_sexp ("Result of gcry_pubkey_get_sexp (0):\n", sexp); + gcry_sexp_release (sexp); + + err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_PUBKEY, ctx); + if (err) + fail ("gcry_pubkey_get_sexp(GET_PUBKEY) failed: %s\n", + gpg_strerror (err)); + else if (debug) + print_sexp ("Result of gcry_pubkey_get_sexp (GET_PUBKEY):\n", sexp); + gcry_sexp_release (sexp); + + err = gcry_pubkey_get_sexp (&sexp, GCRY_PK_GET_SECKEY, ctx); + if (gpg_err_code (err) != GPG_ERR_NO_SECKEY) + fail ("gcry_pubkey_get_sexp(GET_SECKEY) returned wrong error: %s\n", + gpg_strerror (err)); + gcry_sexp_release (sexp); + + } + + cleanup: + gcry_ctx_release (ctx); + gcry_sexp_release (keyparam); +} + + + + +/* Create a new point from (X,Y,Z) given as hex strings. */ +gcry_mpi_point_t +make_point (const char *x, const char *y, const char *z) +{ + gcry_mpi_point_t point; + + point = gcry_mpi_point_new (0); + gcry_mpi_point_snatch_set (point, hex2mpi (x), hex2mpi (y), hex2mpi (z)); + + return point; +} + + +/* This tests checks that the low-level EC API yields the same result + as using the high level API. The values have been taken from a + test run using the high level API. */ +static void +basic_ec_math (void) +{ + gpg_error_t err; + gcry_ctx_t ctx; + gcry_mpi_t P, A; + gcry_mpi_point_t G, Q; + gcry_mpi_t d; + gcry_mpi_t x, y, z; + + wherestr = "basic_ec_math"; + info ("checking basic math functions for EC\n"); + + P = hex2mpi ("0xfffffffffffffffffffffffffffffffeffffffffffffffff"); + A = hex2mpi ("0xfffffffffffffffffffffffffffffffefffffffffffffffc"); + G = make_point ("188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", + "7192B95FFC8DA78631011ED6B24CDD573F977A11E794811", + "1"); + d = hex2mpi ("D4EF27E32F8AD8E2A1C6DDEBB1D235A69E3CEF9BCE90273D"); + Q = gcry_mpi_point_new (0); + + err = ec_p_new (&ctx, P, A); + if (err) + die ("ec_p_new failed: %s\n", gpg_strerror (err)); + + x = gcry_mpi_new (0); + y = gcry_mpi_new (0); + z = gcry_mpi_new (0); + + { + /* A quick check that multiply by zero works. */ + gcry_mpi_t tmp; + + tmp = gcry_mpi_new (0); + gcry_mpi_ec_mul (Q, tmp, G, ctx); + gcry_mpi_release (tmp); + gcry_mpi_point_get (x, y, z, Q); + if (gcry_mpi_cmp_ui (z, 0)) + fail ("multiply a point by zero failed\n"); + } + + gcry_mpi_ec_mul (Q, d, G, ctx); + + if (gcry_mpi_ec_get_affine (x, y, Q, ctx)) + fail ("failed to get affine coordinates\n"); + if (cmp_mpihex (x, "008532093BA023F4D55C0424FA3AF9367E05F309DC34CDC3FE") + || cmp_mpihex (y, "00C13CA9E617C6C8487BFF6A726E3C4F277913D97117939966")) + fail ("computed affine coordinates of public key do not match\n"); + if (debug) + { + print_mpi ("q.x", x); + print_mpi ("q.y", y); + } + + gcry_mpi_release (z); + gcry_mpi_release (y); + gcry_mpi_release (x); + gcry_mpi_point_release (Q); + gcry_mpi_release (d); + gcry_mpi_point_release (G); + gcry_mpi_release (A); + gcry_mpi_release (P); + gcry_ctx_release (ctx); +} + + +/* This is the same as basic_ec_math but uses more advanced + features. */ +static void +basic_ec_math_simplified (void) +{ +} + + +/* Check the math used with Twisted Edwards curves. */ +static void +twistededwards_math (void) +{ + gpg_error_t err; + gcry_ctx_t ctx; + gcry_mpi_point_t G, Q; + gcry_mpi_t k; + gcry_mpi_t w, a, x, y, z, p, n, b, I; + + wherestr = "twistededwards_math"; + info ("checking basic Twisted Edwards math\n"); + + err = gcry_mpi_ec_new (&ctx, NULL, "Ed25519"); + if (err) + die ("gcry_mpi_ec_new failed: %s\n", gpg_strerror (err)); + + k = hex2mpi + ("2D3501E723239632802454EE5DDC406EFB0BDF18486A5BDE9C0390A9C2984004" + "F47252B628C953625B8DEB5DBCB8DA97AA43A1892D11FA83596F42E0D89CB1B6"); + G = gcry_mpi_ec_get_point ("g", ctx, 1); + if (!G) + die ("gcry_mpi_ec_get_point(G) failed\n"); + Q = gcry_mpi_point_new (0); + + + w = gcry_mpi_new (0); + a = gcry_mpi_new (0); + x = gcry_mpi_new (0); + y = gcry_mpi_new (0); + z = gcry_mpi_new (0); + I = gcry_mpi_new (0); + p = gcry_mpi_ec_get_mpi ("p", ctx, 1); + n = gcry_mpi_ec_get_mpi ("n", ctx, 1); + b = gcry_mpi_ec_get_mpi ("b", ctx, 1); + + /* Check: 2^{p-1} mod p == 1 */ + gcry_mpi_sub_ui (a, p, 1); + gcry_mpi_powm (w, GCRYMPI_CONST_TWO, a, p); + if (gcry_mpi_cmp_ui (w, 1)) + fail ("failed assertion: 2^{p-1} mod p == 1\n"); + + /* Check: p % 4 == 1 */ + gcry_mpi_mod (w, p, GCRYMPI_CONST_FOUR); + if (gcry_mpi_cmp_ui (w, 1)) + fail ("failed assertion: p %% 4 == 1\n"); + + /* Check: 2^{n-1} mod n == 1 */ + gcry_mpi_sub_ui (a, n, 1); + gcry_mpi_powm (w, GCRYMPI_CONST_TWO, a, n); + if (gcry_mpi_cmp_ui (w, 1)) + fail ("failed assertion: 2^{n-1} mod n == 1\n"); + + /* Check: b^{(p-1)/2} mod p == p-1 */ + gcry_mpi_sub_ui (a, p, 1); + gcry_mpi_div (x, NULL, a, GCRYMPI_CONST_TWO, -1); + gcry_mpi_powm (w, b, x, p); + gcry_mpi_abs (w); + if (gcry_mpi_cmp (w, a)) + fail ("failed assertion: b^{(p-1)/2} mod p == p-1\n"); + + /* I := 2^{(p-1)/4} mod p */ + gcry_mpi_sub_ui (a, p, 1); + gcry_mpi_div (x, NULL, a, GCRYMPI_CONST_FOUR, -1); + gcry_mpi_powm (I, GCRYMPI_CONST_TWO, x, p); + + /* Check: I^2 mod p == p-1 */ + gcry_mpi_powm (w, I, GCRYMPI_CONST_TWO, p); + if (gcry_mpi_cmp (w, a)) + fail ("failed assertion: I^2 mod p == p-1\n"); + + /* Check: G is on the curve */ + if (!gcry_mpi_ec_curve_point (G, ctx)) + fail ("failed assertion: G is on the curve\n"); + + /* Check: nG == (0,1) */ + gcry_mpi_ec_mul (Q, n, G, ctx); + if (gcry_mpi_ec_get_affine (x, y, Q, ctx)) + fail ("failed to get affine coordinates\n"); + if (gcry_mpi_cmp_ui (x, 0) || gcry_mpi_cmp_ui (y, 1)) + fail ("failed assertion: nG == (0,1)\n"); + + /* Now two arbitrary point operations taken from the ed25519.py + sample data. */ + gcry_mpi_release (a); + a = hex2mpi + ("4f71d012df3c371af3ea4dc38385ca5bb7272f90cb1b008b3ed601c76de1d496" + "e30cbf625f0a756a678d8f256d5325595cccc83466f36db18f0178eb9925edd3"); + gcry_mpi_ec_mul (Q, a, G, ctx); + if (gcry_mpi_ec_get_affine (x, y, Q, ctx)) + fail ("failed to get affine coordinates\n"); + if (cmp_mpihex (x, ("157f7361c577aad36f67ed33e38dc7be" + "00014fecc2165ca5cee9eee19fe4d2c1")) + || cmp_mpihex (y, ("5a69dbeb232276b38f3f5016547bb2a2" + "4025645f0b820e72b8cad4f0a909a092"))) + { + fail ("sample point multiply failed:\n"); + print_mpi ("r", a); + print_mpi ("Rx", x); + print_mpi ("Ry", y); + } + + gcry_mpi_release (a); + a = hex2mpi + ("2d3501e723239632802454ee5ddc406efb0bdf18486a5bde9c0390a9c2984004" + "f47252b628c953625b8deb5dbcb8da97aa43a1892d11fa83596f42e0d89cb1b6"); + gcry_mpi_ec_mul (Q, a, G, ctx); + if (gcry_mpi_ec_get_affine (x, y, Q, ctx)) + fail ("failed to get affine coordinates\n"); + if (cmp_mpihex (x, ("6218e309d40065fcc338b3127f468371" + "82324bd01ce6f3cf81ab44e62959c82a")) + || cmp_mpihex (y, ("5501492265e073d874d9e5b81e7f8784" + "8a826e80cce2869072ac60c3004356e5"))) + { + fail ("sample point multiply failed:\n"); + print_mpi ("r", a); + print_mpi ("Rx", x); + print_mpi ("Ry", y); + } + + + gcry_mpi_release (I); + gcry_mpi_release (b); + gcry_mpi_release (n); + gcry_mpi_release (p); + gcry_mpi_release (w); + gcry_mpi_release (a); + gcry_mpi_release (x); + gcry_mpi_release (y); + gcry_mpi_release (z); + gcry_mpi_point_release (Q); + gcry_mpi_point_release (G); + gcry_mpi_release (k); + gcry_ctx_release (ctx); +} + + +/* Check the point on curve function. */ +static void +point_on_curve (void) +{ + static struct { + const char *curve; + int oncurve; /* Point below is on the curve. */ + const char *qx; + const char *qy; + } t[] = { + { + "NIST P-256", 0, + "015B4F6775D68D4D2E2192C6B8027FC5A3D49957E453CB251155AA3FF5D3EC9974", + "4BC4C87B57A25E1056831208AB5B8F091142F891E9FF19F1E090B030DF1087B3" + }, { + "NIST P-256", 0, + "D22C316E7EBE7B293BD66808E000806F0754398A5D72A4F9BBC21C26EAC0A651", + "3C8DB80CC3CDE5E530D040536E6A58AAB41C33FA70B30896943513FF3690132D" + }, { + "NIST P-256", 0, + "0130F7E7BC52854CA493A0DE87DC4AB3B4343758F2B634F15B10D70DBC0A5A5291", + "86F9CA73C25CE86D54CB21C181AECBB52A5971334FF5040F76CAE9845ED46023" + }, { + "NIST P-256", 1, + "14957B602C7849F28858C7407696F014BC091D6D68C449560B7A38147D6E6A9B", + "A8E09EFEECFE00C797A0848F38B61992D30C61FAB13021E88C8BD3545B3A6C63" + }, { + "NIST P-256", 0, + "923DE4957241DD97780841C76294DB0D4F5DC04C3045081174764D2D32AD2D53", + "01B4B1A2027C02F0F520A3B01E4CE3C668BF481346A74499C5D1044A53E210B600" + }, { + "NIST P-256", 1, + "9021DFAB8B4DAEAADA634AAA26D6E5FFDF8C0476FF5CA31606C870A1B933FB36", + "9AFC65EEB24E46C7B75712EF29A981CB09FAC56E2B81D3ED024748CCAB1CB77E" + }, { + "NIST P-256", 0, + "011529F0B26DE5E0EB2DA4BFB6C149C802CB52EE479DD666553286928A4005E990", + "0EBC63DB2104884456DC0AA81A3F4E99D93B7AE2CD4B1489655EA9BE6289CF9E" + }, { + "NIST P-256", 1, + "216EC5DE8CA989199D31F0DFCD381DCC9270A0785365EC3E34CA347C070A87BE", + "87A88897BA763509ECC1DBE28D9D37F6F4E70E3B99B1CD3C0B934D4190968A6D" + }, { + "NIST P-256", 1, + "7ABAA44ACBC6016FDB52A6F45F6178E65CBFC35F9920D99149CA9999612CE945", + "88F7684BDCDA31EAFB6CAD859F8AB29B5D921D7DB2B34DF7E40CE36235F45B63" + }, { + "NIST P-256", 0, + "E765B4272D211DD0064189B55421FB76BB3A7756364A6CB1627FAED848157A84", + "C13171CFFB243E06B203F0996BBDD16F52292AD11F2DA81106E9C2FD87F4FA0F" + }, { + "NIST P-256", 0, + "EE4999DFC3A1871EE7A592BE26A09BEC9D9B561613EE9EFB6ED42F17985C9CDC", + "8399E967338A7A618336AF70DA67D9CAC1C19267809652F5C5183C8B129E0902" + }, { + "NIST P-256", 0, + "F755D0CF2642A2C7FBACCC8E9E442B8B047A99C6E052B2FA5AB0544B36B4D51C", + "AA080F17657B6565D9A4D94BD260B54D92FEE8DC4A78C4FC9C19209933AF39B0" + } , { + "NIST P-384", 0, + "CBFC7DBEBF15BEAD682549757F9BBA0E3F67669DF13FCE0EBE8024B725B38B00" + "83EC46A8F2FF3203C5C7F8C7E722A5EF", + "0548FE281BEAB18FD1AB86F59B0CA524479A4A81373C83B78AFFD801FAC75922" + "96470753DCF46173C9AA4A8A4C2FBE51" + }, { + "NIST P-384", 0, + "1DC8E054A883DB81EAEDE6C487B26816C927B8196780525A6CA8F675D2557752" + "02CE06CCBE705EA8A38AA2894D4BEEE6", + "010191050E867AFAA96A199FE9C591CF8B853D81486786DA889124881FB39D2F" + "8E0875F4C4BB1E3D0F8535C7A52306FB82" + }, { + "NIST P-384", 1, + "2539FC368CE1D5E464B6C0FBB12D557B712327DB086975255AD7D17F7E7E4F23" + "D719ED4116E2CC907AEB92CF22331A60", + "8843FDBA742CB64323E49CEBE8DD74908CFC9C3AA0015662DFBB7219E92CF32E" + "9FC63F61EF19DE9B3CEA98D163ABF254" + }, { + "NIST P-384", 0, + "0B786DACF400D43575394349EDD9F9CD145FC7EF737A3C5F69B253BE7639DB24" + "EC2F0CA62FF1F90B6515DE356EC2A404", + "225D6B2939CC7F7133F43353946A682C68DAC6BB75EE9CF6BD9A1609FA915692" + "72F4D3A87E88529754E109BB9B61B03B" + }, { + "NIST P-384", 0, + "76C660C9F58CF2051F9F8B06049694AB6FE418009DE6F0A0833BC690CEC06CC2" + "9A440AD51C94CF5BC28817C8C6E2D302", + "012974E5D9E55304ED294AB6C7A3C65B663E67ABC5E6F6C0F6498B519F2F6CA1" + "8306976291F3ADC0B5ABA42DED376EA9A5" + }, { + "NIST P-384", 0, + "23D758B1EDB8E12E9E707C53C131A19D9464B20EE05C99766F5ABDF9F906AD03" + "B958BF28B022E54E320672C4BAD4EEC0", + "01E9E72870C88F4C82A5AB3CC8A3398E8F006BF3EC05FFBB1EFF8AEE88020FEA" + "9E558E9F58ED1D324C9DCBCB4E8F2A5970" + }, { + "NIST P-384", 0, + "D062B96D5A10F715ACF361F99262ABF0F7693A8BB60ECB1DF459CF95750E4293" + "18BCB9FC60499D009F949298F3F9F47B", + "9089C6328E4B39A73D7EE6FAE1A77E48CE354B83BBCE432082C32C8FD6784B86" + "CFE9C552E2E720F5DA5806503D3784CD" + }, { + "NIST P-384", 0, + "2A951D4D6EB35C43D94866280D37365B82441BC84D62CBFF3365CAB1FD0A3E20" + "823CA8F84D2BBF4EA687885437DE7839", + "01CC7D762AFE613F7B5568BC516568A421159C40599E8D52DE10E8F9488931E1" + "69F3656C322DE45C4A70DC6DB9A661E599" + }, { + "NIST P-384", 1, + "A4BAEE6CDAF3AEB69032B3FBA811707C54F5753670DA5173D891547E8CBAEEF3" + "89B92C9A55573A596123415FBFA26991", + "3241EA716583C11C71BB30AF6C5E3A6637956F17ADBBE641BAB52E8539F9FC7B" + "F3B04F46DBFFE08151E0F0950CC70081" + }, { + "NIST P-384", 0, + "5C0E18B0DE3261BCBCFC7B702C2D75CF481336BFBADF420BADC616235C1966AB" + "4C0F876575DDEC1BDB3F3F04061C9AE4", + "E90C78550D1C922F1D8161D8C9C0576E29BD09CA665376FA887D13FA8DF48352" + "D7BBEEFB803F6CC8FC7895E47F348D33" + }, { + "NIST P-384", 1, + "2015864CD50F0A1A50E6401F44191665C19E4AD4B4903EA9EB464E95D1070E36" + "F1D8325E45734D5A0FDD103F4DF6F83E", + "5FB3E9A5C59DD5C5262A8176CB7032A00AE33AED08485884A3E5D68D9EEB990B" + "F26E8D87EC175577E782AD51A6A12C02" + }, { + "NIST P-384", 1, + "56EBF5310EEF5A5D8D001F570A18625383ECD4882B3FC738A69874E7C9D8F89C" + "187BECA23369DFD6C15CC0DA0629958F", + "C1230B349FB662CB762563DB8F9FCB32D5CCA16120681C474D67D279CCA6F6DB" + "73DE6AA96140B5C457B7486E06D318CE" + }, { + "NIST P-521", 0, + "01E4D82EE5CD6DA37080252295EFA273BBBA6952012D0120EAF131E73F1E5024" + "36E3324624471040030E1C345D65490ECEE9B64E03B15B6C7EB69A39C618BAFEED70", + "03EE3A3C88A6933B7B16016BE4CC4E3BF5EA0625CB3DB2604CDCBBD02CABBC90" + "8904D9DB42998F6C5101D4D4318ACFC9643C9CD641F636D1810ED86F1840EA74F3C0" + }, { + "NIST P-521", 0, + "01F3DFCB5433387B6B2E3F74177F4F3D7300F05E1AD49DE112630E27B1C8A437" + "1E742CB020E0039B5477FC897D17332034F9660B3066764EFF5FB440EB8856E782E3", + "02D337616C9D202DC5E290C486F5855CBD6A8470AE62CA96245834CF49257D8D" + "96D4041B15007650DEE668C00DDBF749054256C571F60980AC74D0DBCA7FB96C2F48" + }, { + "NIST P-521", 1, + "822A846606DC9E96452CAC373567A8B57D9ACA15B177F75DD7EF10C635F52CE4" + "EF6ABEEDB90D3F48F50A0C9015A95C955A25C45DE8413DE3BF899B6B1E62CF7CB8", + "0102771B5F3EC8C36838CEC04DCBC28AD1E38C37DAB0EA89B5EE92D21F7A35CE" + "ABC8B155EDC70154D6DFA2E77EC1D8C4A3406A6BD0ECF8F1EE2AC33A02464CB70C97" + }, { + "NIST P-521", 0, + "F733D48467912D1FFE46CF442F27FDD218D190E7B8A829D822DA3B6BAF9B987E" + "5B4BCCE34499248F59EEAF74F63ED15FF73F243C6FC3FD5E5842F6A3BA34C2022D", + "0281AAAD1B7EEBABEB6EC67932CB7E95717AFA3B4CF7A2DB151CD537C419C3A5" + "156ED9160758190B47696CDC15E81BBAD12975283907A571604DB23F702AEA4B38FF" + }, { + "NIST P-521", 0, + "03B1B274175AAEB5907152E5114CCAEADA28A7ADD4A2B1831C3D8302E8596489" + "E2C98B9B8D0CAE98C03BB11E28CE66D4736449758AF58BAFE40EF5A5FA22C9A43117", + "94C5951F81D544E959EDFC5DC1D5F42FE427871D4FB91A43A0B4A6BEA6B35B9E" + "BC5FB444C70BE4FD47B4ED16704F8C86EF019FC47C7FF2271F8B0DDEA9E2D3BCDD" + }, { + "NIST P-521", 1, + "F2248C318055DE37CD706D4FCAF7E7D96737A4A7B6B8067A66DCD58B6B8DFC55" + "90ECE67F6AA67F9C51B57E7B023075F2F42909BF47361CB6881C10F55FB7215B56", + "0162F735CE6A2ADA54CAF96A12D6888C02DE0A74638CF34CE39DABBACA4D651B" + "7E6ED1A65B551B36BAE7BE474BB6E6905ED0E33C7BA2021885027C7C6E40C5613004" + }, { + "NIST P-521", 0, + "9F08E97FEADCF0A391CA1EA4D97B5FE62D3B164593E12027EB967BD6E1FA841A" + "9831158DF164BCAD0BF3ADA96127745E25F349BDDD52EEA1654892B35960C9C023", + "AE2A25F5440F258AFACA6925C4C9F7AEAD3CB67153C4FACB31AC33F58B43A78C" + "B14F682FF726CEE2A6B6F6B481AEEB29A9B3150F02D1CFB764672BA8294C477291" + }, { + "NIST P-521", 0, + "01047B52014748C904980716953206A93F0D01B34CA94A997407FA93FE304F86" + "17BB6E402B2BB8B434C2671ECE953ABE7BADB75713CD9DF950943A33A9A19ACCDABE", + "7433533F098037DEA616337986887D01C5CC8DEC3DC1FDB9CDF7287EF27CC125" + "54FCF3A5E212DF9DAD9F8A3A7173B23FC6E15930704F3AEE1B074BDDB0ED6823E4" + }, { + "NIST P-521", 0, + "01C2A9EBF51592FE6589F618EAADA1697D9B2EC7CE5D48C9E80FC597642B23F1" + "F0EBE953449762BD3F094F57791D9850AFE98BBDA9872BE399B7BDD617860076BB03", + "0B822E27692F63DB8E12C59BB3CCA172B9BBF613CAE5F9D1474186E45E8B26FF" + "962084E1C6BE74821EDBB60941A3B75516F603719563433383812BFEA89EC14B89" + }, { + "NIST P-521", 0, + "99390F342C3F0D46E80C5B65C61E8AA8ACA0B6D4E1352404586364A05D8398E9" + "2BC71A644E8663F0A9B87D0B3ACAEE32F2AB9B321317AD23059D045EBAB91C5D93", + "82FCF93AE4467EB57766F2B150E736636727E7282500CD482DA70D153D195F2B" + "DF9B96D689A0DC1BB9137B41557A33F202F1B71840544CBEFF03072E77E4BB6F0B" + }, { + "NIST P-521", 1, + "018E48E80594FF5496D8CC7DF8A19D6AA18805A4EF4490038AED6A1E9AA18056" + "D0244A97DCF6D132C6804E3F4F369922119544B4C057D783C848FB798B48730A382C", + "01AF510B4F5E1C40BC9C110216D35E7C6D7A2BEE52914FC98258676288449901" + "F27A07EE91DF2D5D79259712906C3E18A990CBF35BCAC41A952820CE2BA8D0220080" + }, { + "NIST P-521", 1, + "ADCEF3539B4BC831DC0AFD173137A4426152058AFBAE06A17FCB89F4DB6E48B5" + "335CB88F8E4DB475A1E390E5656072F06605BFB84CBF9795B7992ECA04A8E10CA1", + "01BCB985AFD6404B9EDA49B6190AAA346BF7D5909CA440C0F7E505C62FAC8635" + "31D3EB7B2AC4DD4F4404E4B12E9D6D3C596179587F3724B1EFFF684CFDB4B21826B9" + } + }; + gpg_error_t err; + int tidx; + const char *lastcurve = NULL; + gcry_ctx_t ctx = NULL; + gcry_mpi_t qx = NULL; + gcry_mpi_t qy = NULL; + gcry_mpi_point_t Q; + int oncurve; + + wherestr = "point_on_curve"; + for (tidx=0; tidx < DIM (t); tidx++) + { + if (!t[tidx].curve) + { + if (!lastcurve || !ctx) + die ("invalid test vectors at idx %d\n", tidx); + } + else if (!ctx || !lastcurve || strcmp (t[tidx].curve, lastcurve)) + { + lastcurve = t[tidx].curve; + gcry_ctx_release (ctx); + err = gcry_mpi_ec_new (&ctx, NULL, lastcurve); + if (err) + die ("error creating context for curve %s at idx %d: %s\n", + lastcurve, tidx, gpg_strerror (err)); + + info ("checking points on curve %s\n", lastcurve); + } + + gcry_mpi_release (qx); + gcry_mpi_release (qy); + qx = hex2mpi (t[tidx].qx); + qy = hex2mpi (t[tidx].qy); + + Q = gcry_mpi_point_set (NULL, qx, qy, GCRYMPI_CONST_ONE); + if (!Q) + die ("gcry_mpi_point_set(Q) failed at idx %d\n", tidx); + + oncurve = gcry_mpi_ec_curve_point (Q, ctx); + + if (t[tidx].oncurve && !oncurve) + { + fail ("point expected on curve but not identified as such (i=%d):\n", + tidx); + print_point (" Q", Q); + } + else if (!t[tidx].oncurve && oncurve) + { + fail ("point not expected on curve but identified as such (i=%d):\n", + tidx); + print_point (" Q", Q); + } + gcry_mpi_point_release (Q); + } + + gcry_mpi_release (qx); + gcry_mpi_release (qy); + gcry_ctx_release (ctx); +} + + +int +main (int argc, char **argv) +{ + + if (argc > 1 && !strcmp (argv[1], "--verbose")) + verbose = 1; + else if (argc > 1 && !strcmp (argv[1], "--debug")) + verbose = debug = 1; + + if (!gcry_check_version (GCRYPT_VERSION)) + die ("version mismatch\n"); + + xgcry_control (GCRYCTL_DISABLE_SECMEM, 0); + xgcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); + if (debug) + xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0); + xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); + + set_get_point (); + context_alloc (); + context_param (); + basic_ec_math (); + point_on_curve (); + + /* The tests are for P-192 and ed25519 which are not supported in + FIPS mode. */ + if (!gcry_fips_mode_active()) + { + basic_ec_math_simplified (); + twistededwards_math (); + } + + info ("All tests completed. Errors: %d\n", error_count); + return error_count ? 1 : 0; +} diff --git a/tests/smoke-test/Makefile b/tests/smoke-test/Makefile new file mode 100644 index 0000000..0e0dda3 --- /dev/null +++ b/tests/smoke-test/Makefile @@ -0,0 +1,71 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /CoreOS/libgcrypt/smoke-test +# Description: Test calls upstream test suite. +# Author: Ondrej Moris +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2010 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/CoreOS/libgcrypt/smoke-test +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) runtest.sh Makefile PURPOSE + +.PHONY: all install download clean + +run: $(FILES) build + ./runtest.sh + +build: $(BUILT_FILES) + chmod a+x runtest.sh + +clean: + rm -f *~ $(BUILT_FILES) + + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Ondrej Moris " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: Test calls upstream test suite." >> $(METADATA) + @echo "Type: Sanity" >> $(METADATA) + @echo "TestTime: 15m" >> $(METADATA) + @echo "RunFor: libgcrypt" >> $(METADATA) + @echo "Requires: libgcrypt" >> $(METADATA) + @echo "Requires: nfs-utils" >> $(METADATA) + @echo "Requires: rpm-build" >> $(METADATA) + @echo "Requires: gawk" >> $(METADATA) + @echo "Requires: gcc-c++ fipscheck" >> $(METADATA) + @echo "Requires: libgpg-error-devel wget" >> $(METADATA) + @echo "Requires: pkgconfig texinfo libselinux-utils" >> $(METADATA) + @echo "Releases: -RHEL3 -RHEL4" >> $(METADATA) + @echo "Priority: Normal" >> $(METADATA) + @echo "Architectures: i386 x86_64 s390x ia64" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + @echo "Confidential: no" >> $(METADATA) + @echo "Destructive: no" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/smoke-test/PURPOSE b/tests/smoke-test/PURPOSE new file mode 100644 index 0000000..5df6ca9 --- /dev/null +++ b/tests/smoke-test/PURPOSE @@ -0,0 +1,3 @@ +PURPOSE of /CoreOS/libgcrypt/Sanity/smoke-test +Description: Test calls upstream test suite. +Author: Ondrej Moris diff --git a/tests/smoke-test/runtest.sh b/tests/smoke-test/runtest.sh new file mode 100755 index 0000000..dd1803d --- /dev/null +++ b/tests/smoke-test/runtest.sh @@ -0,0 +1,71 @@ +#!/bin/bash +# vim: dict=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# runtest.sh of /CoreOS/libgcrypt/smoke-test +# Description: Test calls upstream test suite. +# Author: Ondrej Moris +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2010 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Include rhts environment +#. /usr/bin/rhts-environment.sh +. /usr/share/beakerlib/beakerlib.sh + +PACKAGE="libgcrypt" + +rlJournalStart + + rlPhaseStartSetup + TmpDir=`mktemp -d` + rlAssertRpm $PACKAGE + rlFileBackup --clean "/etc/gcrypt/fips_enabled" + rlRun "pushd $TmpDir" 0 + rlFetchSrcForInstalled $PACKAGE + rlRun "rpm -ihv `ls *.rpm`" 0 + if grep '1' /proc/sys/crypto/fips_enabled; then + rlRun "echo '1' > /etc/gcrypt/fips_enabled" 0 + fi + rlPhaseEnd + + rlPhaseStartTest + TOPDIR=`rpm --eval %_topdir` + rlRun "pushd $TOPDIR" 0 + rlRun "rm -rf BUILD/libgcrypt-*" 0-255 + rlRun "rpmbuild -vv -bc SPECS/libgcrypt.spec" 0 + rlRun "pushd BUILD/libgcrypt-*" 0 + rlRun "fipshmac src/.libs/libgcrypt.so.??" 0 + rlRun "make check > $TmpDir/make_check.out" 0 + rlRun "popd" 0 + rlRun "popd" 0 + rlRun "grep \"All [0-9]\+ tests passed\" $TmpDir/make_check.out" 0 \ + "All tests passed" + rlRun "cat $TmpDir/make_check.out" 0 + rlPhaseEnd + + rlPhaseStartCleanup + rlRun "popd" 0 + rlRun "rm -r $TmpDir" 0 + rlFileRestore + rlPhaseEnd + +rlJournalPrintText +rlJournalEnd diff --git a/tests/tests.yml b/tests/tests.yml new file mode 100644 index 0000000..dd115e9 --- /dev/null +++ b/tests/tests.yml @@ -0,0 +1,20 @@ +- hosts: localhost + tags: + - classic + - container + roles: + - role: standard-test-beakerlib + tests: + - smoke-test + required_packages: + - fipscheck + - gawk + - gcc-c++ + - libgcrypt + - libgpg-error-devel + - libselinux-utils + - nfs-utils + - pkgconfig + - rpm-build + - texinfo + - wget diff --git a/wk@g10code.com b/wk@g10code.com new file mode 100644 index 0000000..5e193e3 --- /dev/null +++ b/wk@g10code.com @@ -0,0 +1,2007 @@ +Login: wk Name: Werner Koch +No project. +No plan. +Public key: + pub 1024D/5B0358A2 1999-03-15 [expires: 2011-07-11] + uid Werner Koch + uid Werner Koch + uid Werner Koch + uid Werner Koch + sub 1024D/010A57ED 2004-03-21 [expires: 2007-12-31] + sub 2048R/C3680A6E 2006-01-01 [expires: 2007-12-31] + + pub 1024R/1CE0C630 2006-01-01 [expires: 2008-12-31] + uid Werner Koch (dist sig) + + pub 1024R/37D92FFB 2003-11-17 [expires: 2009-12-31] + uid g10 Code (code signing key 1) + + pub 1024D/57548DCD 1998-07-07 [expired: 2005-12-31] + uid Werner Koch (gnupg sig) + + +5B0358A2 is my main key. +1CE0C630 is used to sign software distributions. +37D92FFB is used to sign certain source files. +57548DCD was used to sign GNU crypto software; + it has been superseded by 1CE0C630. + +Please note that I use a subkey for signing messages; some old OpenPGP +implementations may not be able to check such a signature. The primary +key is stored at a more or less secure place and only used on a spare +laptop which is not connected to any network. If you find a key +certified by this one, you can be sure that I personally met this +person and checked the name part of the user ID against an official +looking passport or another suitable photo id. My signature does not +say anything about the email address (I merely check that the address +looks plausible). + + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.7 (GNU/Linux) + +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 +Ooh6BBMRAgA6BQJEXmVkMxpodHRwOi8vd3d3LnNjLWRlbHBoaW4tZXNjaHdlaWxl +ci5kZS9wZ3AvaW5kZXguaHRtbAAKCRC0deIHurWCKcwdAJ4hvG79xMFKtYL0GGP8 +WuvvxnMnzQCfZUjHFhMNMGgrCPthD6oeNaw2FxCIRgQTEQIABgUCRFz9JwAKCRCK +o2Kv6XIyzVjaAJ9MSW3iP1fUZqr7xdbj/PLkHLzJeACfZNe6IgDrJk9E3a/8IKZi +E4iYtqWIRgQTEQIABgUCRFz9LwAKCRCn31hycNRMI+EXAKDRHf6ZRUGa6T7Uosgx +huo5I3sK6gCfRxthF9FN1SXK11O+tjRS1mwN0JaIYwQTEQIAGwUCNxrPkAUJDMl8 +gAMLCgMDFQMCAxYCAQIXgAASCRBd4kmWWwNYogdlR1BHAAEBXcIAnjv7ON5AiwzC +LBwm9h9ywufXJQuVAJ9RMq6lpPqnDly6UCKz+kGt0EplyIhmBBMRAgAeAwsKAwMV +AwIDFgIBAheAAhkBBQJAXdnoBQkTa4v/ABIHZUdQRwABAQkQXeJJllsDWKLs0gCg +y5RdOqhFvwUFYWj+dHb4LGt7xi0AoKduFxGMuM/loPShQnjvk/VVFesAiF4EExEC +AB4DCwoDAxUDAgMWAgECF4ACGQEFAkBd2egFCRNri/8ACgkQXeJJllsDCRDs0gCg +y5RdOqhFvwUFYWj+dHb4LGt7xi0AoKduFxGMuM/loPShQnjvk/VVFesAiQEVAwUQ +O0HCUNImKUTOasbBAQFLZwgAkgMC/ximskOjL/CxghgdkSWkDFdpEr3XYhzUdLes +WgN4AM28mGZZKA9la7dXXRrKYkxhX8mpL4C3Q9LnrafP+Zn1c8mTuNIxX86j7iZA +IksoZ4D2csN8NSMYT9pKK6jZP1IOckCFBBI0W/yMGUGulDitWj4TwIArf2xQkV73 +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +/////////////////////////////////////////////4hGBBMRAgAGBQJDRBuk +AAoJEOrUtZD2iZvAafoAoKReCbMFRrpwzb2tS7M6iHDbN9E+AJoDy8nLf8A4f/EV +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 +wZyP4MwTIOb4NIhGBBARAgAGBQJEKFdaAAoJEBH0xB6z+64zBhUAoJ6kWu5gDqHB +Z8Wan0YynEZi6tKyAJsHBacxx6UNYPENlVXlb0xl+kssa4h6BBMRAgA6BQJEXmVA +MxpodHRwOi8vd3d3LnNjLWRlbHBoaW4tZXNjaHdlaWxlci5kZS9wZ3AvaW5kZXgu +aHRtbAAKCRCUj9ag4Q9QLulZAJ992LLlu7wU5sJddqnffDzPoKh69QCgoX8QzBEi +SZjLKSrALwLCTYI/akSIegQTEQIAOgUCRF5lZDMaaHR0cDovL3d3dy5zYy1kZWxw +aGluLWVzY2h3ZWlsZXIuZGUvcGdwL2luZGV4Lmh0bWwACgkQtHXiB7q1gikU0QCf +ZM81Hr4p7ZPwxMZW+TVcRdaSIjoAoMq7mN4xSLtRsB/lGlFLhc1O4soLiEYEExEC +AAYFAkRc/SoACgkQiqNir+lyMs3HBACfb7fa3KzNGB9Oma3KDWeC42feCzAAoIfF +w3OXxtigxx8+AowiXGsZmqI+iEYEExECAAYFAkRc/TEACgkQp99YcnDUTCOrZQCg +gV7PoPMl1d+gvPTiuUAZm8UG/dYAn3PlOcTP4vxayC7OGSkoDA8Dut+KiEYEExEC +AAYFAkNEG6QACgkQ6tS1kPaJm8DI0ACfRfci8SHm+sQpjzKqr0zxfJT5yF0AnA37 +mn7nQyY28SJ2sddCo/f1JhvAiEYEEBECAAYFAkQFglgACgkQb11ZaBzVLeiG9wCf +aX6+h8bpMOraCn/sH1yQb6aI34EAoLzx4H6lGdyqnQTYiLXSrBTrto/niEYEEBEC +AAYFAkQGCjQACgkQmsnSLGNcY0vZ4wCgvBjcB5ABcNYRMEFSWsClxhaRAqUAmwUv +MA9NWdLk0pcUndbE3w70B5hUiEwEEhECAAwFAkQGKycFgwZSqcEACgkQ3+ZXkjKV +xc2qMwCfdew+RX+7ultYmO0Y8gRoLJzjBfgAn1UkZILe3+NKZBJTd1ZowJQiljHI +iEwEEhECAAwFAkQGK2cFgwZSqYEACgkQoOUVvzmICVQuFwCgqbjde48qPvUqLEip +he/zFq6pqgAAn1dXi6z+1s+bHavwCQK/q+3K5gdHiJwEEwECAAYFAkQNdesACgkQ +/dJ0ek5GOmrWRgQAoFF9IdTs5vX5OIDKIHW+d4aJfPg6w91SKkfpElDxNqZuk3rA +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 +nj+zW9f9Z2M0K2r+gldEC2Ew2yTl +=I1gH +-----END PGP PUBLIC KEY BLOCK-----