From f9fd52029257db9f0a3f33f4266974e222f1d7ef Mon Sep 17 00:00:00 2001 From: zyppe <210hcl@gmail.com> Date: Sat, 10 Feb 2024 22:23:48 +0800 Subject: [PATCH] Initialize for libgcrypt --- .gitignore | 1 + .libgcrypt.metadata | 1 + baselibs.conf | 7 + cavs-test.sh | 61 + cavs_driver.pl | 3072 ++++++++++++ drbg_test.patch | 1371 ++++++ ...pt-1.4.1-rijndael_no_strict_aliasing.patch | 17 + ...t-1.5.0-LIBGCRYPT_FORCE_FIPS_MODE-env.diff | 27 + libgcrypt-1.6.1-fips-cavs.patch | 1126 +++++ libgcrypt-1.6.1-use-fipscheck.patch | 81 + libgcrypt-1.8.3-fips-ctor.patch | 266 ++ libgcrypt-1.8.4-allow_FSM_same_state.patch | 15 + libgcrypt-1.8.4-fips-keygen.patch | 66 + ...1.8.4-fips_ctor_skip_integrity_check.patch | 32 + libgcrypt-1.8.4-getrandom.patch | 124 + libgcrypt-1.8.4-use_xfree.patch | 39 + libgcrypt-1.9.4.tar.bz2.sig | Bin 0 -> 119 bytes ...tion-of-AES-GCM-acceleration-ppc64le.patch | 1658 +++++++ libgcrypt-FIPS-GMAC_AES-benckmark.patch | 13 + libgcrypt-FIPS-HMAC-short-keylen.patch | 203 + ...FIPS-RSA-DSA-ECDSA-hashing-operation.patch | 245 + libgcrypt-FIPS-RSA-keylen-tests.patch | 585 +++ libgcrypt-FIPS-RSA-keylen.patch | 250 + libgcrypt-FIPS-SLI-pk.patch | 160 + libgcrypt-FIPS-Zeroize-hmac.patch | 35 + libgcrypt-FIPS-disable-3DES.patch | 52 + libgcrypt-FIPS-disable-DSA.patch | 44 + libgcrypt-FIPS-fix-gcry_mpi_sub_ui.patch | 230 + libgcrypt-FIPS-fix-regression-tests.patch | 448 ++ libgcrypt-FIPS-hw-optimizations.patch | 31 + libgcrypt-FIPS-kdf-leylength.patch | 39 + libgcrypt-FIPS-module-version.patch | 89 + libgcrypt-FIPS-rndjent_poll.patch | 114 + libgcrypt-FIPS-service-indicators.patch | 375 ++ ...ypt-FIPS-verify-unsupported-KDF-test.patch | 68 + ...-chacha20-poly1305-for-P10-operation.patch | 2028 ++++++++ libgcrypt-PCT-DSA.patch | 118 + libgcrypt-PCT-ECC.patch | 342 ++ libgcrypt-PCT-RSA.patch | 123 + ...-Restore-self-tests-from-constructor.patch | 16 + libgcrypt-dsa-rfc6979-test-fix.patch | 124 + libgcrypt-ecc-ecdsa-no-blinding.patch | 82 + libgcrypt-fips_selftest_trigger_file.patch | 40 + ...ypt-fipsdrv-enable-algo-for-dsa-sign.patch | 65 + ...t-fipsdrv-enable-algo-for-dsa-verify.patch | 64 + libgcrypt-fix-rng.patch | 24 + libgcrypt-fix-tests-fipsmode.patch | 177 + libgcrypt-global_init-constructor.patch | 254 + ...sing-HWF_PPC_ARCH_3_10-in-HW-feature.patch | 26 + libgcrypt-indicate-shake.patch | 13 + ...-invoke-global_init-from-constructor.patch | 14 + libgcrypt-jitterentropy-3.3.0.patch | 4168 +++++++++++++++++ libgcrypt-jitterentropy-3.4.0.patch | 618 +++ libgcrypt-out-of-core-handler.patch | 12 + libgcrypt-pthread-in-t-lock-test.patch | 13 + libgcrypt-random_selftests-testentropy.patch | 15 + libgcrypt-rsa-no-blinding.patch | 92 + libgcrypt.changes | 1106 +++++ libgcrypt.keyring | 65 + libgcrypt.spec | 289 ++ libgcrypt_indicators_changes.patch | 238 + random.conf | 9 + 62 files changed, 21080 insertions(+) create mode 100644 .gitignore create mode 100644 .libgcrypt.metadata create mode 100644 baselibs.conf create mode 100644 cavs-test.sh create mode 100644 cavs_driver.pl create mode 100644 drbg_test.patch create mode 100644 libgcrypt-1.4.1-rijndael_no_strict_aliasing.patch create mode 100644 libgcrypt-1.5.0-LIBGCRYPT_FORCE_FIPS_MODE-env.diff create mode 100644 libgcrypt-1.6.1-fips-cavs.patch create mode 100644 libgcrypt-1.6.1-use-fipscheck.patch create mode 100644 libgcrypt-1.8.3-fips-ctor.patch create mode 100644 libgcrypt-1.8.4-allow_FSM_same_state.patch create mode 100644 libgcrypt-1.8.4-fips-keygen.patch create mode 100644 libgcrypt-1.8.4-fips_ctor_skip_integrity_check.patch create mode 100644 libgcrypt-1.8.4-getrandom.patch create mode 100644 libgcrypt-1.8.4-use_xfree.patch create mode 100644 libgcrypt-1.9.4.tar.bz2.sig create mode 100644 libgcrypt-Bulk-implementation-of-AES-GCM-acceleration-ppc64le.patch create mode 100644 libgcrypt-FIPS-GMAC_AES-benckmark.patch create mode 100644 libgcrypt-FIPS-HMAC-short-keylen.patch create mode 100644 libgcrypt-FIPS-RSA-DSA-ECDSA-hashing-operation.patch create mode 100644 libgcrypt-FIPS-RSA-keylen-tests.patch create mode 100644 libgcrypt-FIPS-RSA-keylen.patch create mode 100644 libgcrypt-FIPS-SLI-pk.patch create mode 100644 libgcrypt-FIPS-Zeroize-hmac.patch create mode 100644 libgcrypt-FIPS-disable-3DES.patch create mode 100644 libgcrypt-FIPS-disable-DSA.patch create mode 100644 libgcrypt-FIPS-fix-gcry_mpi_sub_ui.patch create mode 100644 libgcrypt-FIPS-fix-regression-tests.patch create mode 100644 libgcrypt-FIPS-hw-optimizations.patch create mode 100644 libgcrypt-FIPS-kdf-leylength.patch create mode 100644 libgcrypt-FIPS-module-version.patch create mode 100644 libgcrypt-FIPS-rndjent_poll.patch create mode 100644 libgcrypt-FIPS-service-indicators.patch create mode 100644 libgcrypt-FIPS-verify-unsupported-KDF-test.patch create mode 100644 libgcrypt-Optimized-chacha20-poly1305-for-P10-operation.patch create mode 100644 libgcrypt-PCT-DSA.patch create mode 100644 libgcrypt-PCT-ECC.patch create mode 100644 libgcrypt-PCT-RSA.patch create mode 100644 libgcrypt-Restore-self-tests-from-constructor.patch create mode 100644 libgcrypt-dsa-rfc6979-test-fix.patch create mode 100644 libgcrypt-ecc-ecdsa-no-blinding.patch create mode 100644 libgcrypt-fips_selftest_trigger_file.patch create mode 100644 libgcrypt-fipsdrv-enable-algo-for-dsa-sign.patch create mode 100644 libgcrypt-fipsdrv-enable-algo-for-dsa-verify.patch create mode 100644 libgcrypt-fix-rng.patch create mode 100644 libgcrypt-fix-tests-fipsmode.patch create mode 100644 libgcrypt-global_init-constructor.patch create mode 100644 libgcrypt-hwf-ppc-fix-missing-HWF_PPC_ARCH_3_10-in-HW-feature.patch create mode 100644 libgcrypt-indicate-shake.patch create mode 100644 libgcrypt-invoke-global_init-from-constructor.patch create mode 100644 libgcrypt-jitterentropy-3.3.0.patch create mode 100644 libgcrypt-jitterentropy-3.4.0.patch create mode 100644 libgcrypt-out-of-core-handler.patch create mode 100644 libgcrypt-pthread-in-t-lock-test.patch create mode 100644 libgcrypt-random_selftests-testentropy.patch create mode 100644 libgcrypt-rsa-no-blinding.patch create mode 100644 libgcrypt.changes create mode 100644 libgcrypt.keyring create mode 100644 libgcrypt.spec create mode 100644 libgcrypt_indicators_changes.patch create mode 100644 random.conf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0e6e9c3 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +libgcrypt-1.9.4.tar.bz2 diff --git a/.libgcrypt.metadata b/.libgcrypt.metadata new file mode 100644 index 0000000..bf5ad05 --- /dev/null +++ b/.libgcrypt.metadata @@ -0,0 +1 @@ +8b5471d358e81c2716ca1ff1c6b56bbf96afec59f7f87f15cd48a371cf7894f1 libgcrypt-1.9.4.tar.bz2 diff --git a/baselibs.conf b/baselibs.conf new file mode 100644 index 0000000..046ee08 --- /dev/null +++ b/baselibs.conf @@ -0,0 +1,7 @@ +libgcrypt20 + obsoletes "libgcrypt- <= " + provides "libgcrypt- = " +libgcrypt20-hmac +libgcrypt-devel + requires -libgcrypt- + requires "libgcrypt20- = " diff --git a/cavs-test.sh b/cavs-test.sh new file mode 100644 index 0000000..ac7f595 --- /dev/null +++ b/cavs-test.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# +# This is the driver script around the actual FIPS testing +# Written by: Stephan Müller +# (c) atsec information security corporation + +# The easiest way to perform the cipher compliance testing +# is the following: +# +# 1. patch/compile/copy the openssl binary with the patch if necessary +# (old versions hang when running the MC test if unpatched) +# +# 2. unpack the test vector ZIP file to a local dir +# +# 3. set PATH in a way that cavs_driver.pl is found +# +# 4. go to the local dir where you unzipped the test vector archive and execute +# $0 +# +# 5. send atsec the prepared CAVS_results-*.zip archive found in the same dir + +DATE=$(date +%Y%m%d) +ARCH=$(uname -m) +PATH=$PATH:$(pwd) + +# test interface to be used +# can be overridden by passing an argument to this script +# possible values are: +# openssl OpenSSL (default) +# libgcrypt Libgcrypt +# cryptoapi Kernel +INTERFACE="libgcrypt" + +if [ "$1" == "-I" -a -n "$2" ]; then + INTERFACE="$2" +fi + +for i in $(find ./ -name "*.req"); +do +( + cd $(dirname $i) || exit 1 + + # We have to see whether we check on DSA based on path name + echo $(dirname $i) | if [ ! $(grep -v DSA) ]; then + /usr/lib/libgcrypt/cavs_driver.pl -I $INTERFACE -D $(basename $i) + else + /usr/lib/libgcrypt/cavs_driver.pl -I $INTERFACE $(basename $i) + fi + + + # for CAVS, we have path/req/ + # and want to have the responses in path/resp/*.rsp + if [ $(basename $(dirname $i)) = "req" ]; then + mkdir ../resp > /dev/null 2>&1 + outfile="$(basename $i .req).rsp" + mv "$outfile" ../resp/ + fi +) & +done +wait +zip -r CAVS_results-$ARCH-$DATE.zip $(find ./ -name "*.rsp") diff --git a/cavs_driver.pl b/cavs_driver.pl new file mode 100644 index 0000000..56350b9 --- /dev/null +++ b/cavs_driver.pl @@ -0,0 +1,3072 @@ +#!/usr/bin/perl +# +# $Id: cavs_driver.pl 3235 2014-04-01 06:24:16Z 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 +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# NO WARRANTY +# +# BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +# FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +# OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +# PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +# OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +# TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +# PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +# REPAIR OR CORRECTION. +# +# IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +# WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +# REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +# INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +# OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +# TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +# YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +# PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGES. +# +# +# test execution instruction: +# 1. get the request files from the lab +# 2. call each request file from 1. with this program: +# $0 .rep +# 3. send the resulting file .rsp to the lab +# +# +# Test should be easily adoptable to other implementations +# See the first functions for this task +# +# Following tests are covered (others may also be covered +# but have not been tested) +# +# AES +# [CBC|CFB128|ECB|OFB]GFSbox[128|192|256] +# [CBC|CFB128|ECB|OFB]MCT[128|192|256] +# [CBC|CFB128|ECB|OFB]VarKey[128|192|256] +# [CBC|CFB128|ECB|OFB]KeySbox[128|192|256] +# [CBC|CFB128|ECB|OFB]MMT[128|192|256] +# [CBC|CFB128|ECB|OFB]VarTxt[128|192|256] +# +# RSA +# SigGen[15|RSA] +# SigVer15 +# (SigVerRSA is not applicable for OpenSSL as X9.31 padding +# is not done through openssl dgst) +# KeyGen RSA X9.31 +# +# SHA +# SHA[1|224|256|384|512]ShortMsg +# SHA[1|224|256|384|512]LongMsg +# SHA[1|224|256|384|512]Monte +# +# HMAC (SHA - caveat: we only support hash output equal to the block size of +# of the hash - we do not support truncation of the hash; to support +# that, we first need to decipher the HMAC.req file - see hmac_kat() ) +# HMAC +# +# TDES +# T[CBC|CFB??|ECB|OFB]Monte[1|2|3] +# T[CBC|CFB??|ECB|OFB]permop +# T[CBC|CFB??|ECB|OFB]MMT[1|2|3] +# T[CBC|CFB??|ECB|OFB]subtab +# 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 +# +# DSA2 +# PQGGen +# PQGVer +# KeyPair +# SigGen +# SigVer +# +# DRBG: +# CTR DRBG +# Hash DRBG +# HMAC DRBG +# with and w/o PR +# +# RC4 (atsec developed tests) +# RC4KeyBD +# RC4MCT +# 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; +use IPC::Open2; +use Getopt::Std; +use MIME::Base64; + +use Math::BigInt; + +# Contains the command line options +my %opt; + +################################################################# +##### Central interface functions to the external ciphers ####### +################################################################# +# Only these interface routines should be changed in case of +# porting to a new cipher library +# +# For porting to a new library, create implementation of these functions +# and then add pointers to the respective implementation of each +# function to the given variables. + +# common encryption/decryption routine +# $1 key in hex form (please note for 3DES: even when ede3 for three +# independent ciphers is given with the cipher specification, we hand in +# either one key for k1 = k2 = k3, two keys which are concatinated for +# k1 = k3, k2 independent, or three keys which are concatinated for +# k1, k2, k3 independent) +# $2 iv in hex form +# $3 cipher - the cipher string is defined as specified in the openssl +# enc(1ssl) specification for the option "-ciphername" +# (e.g. aes-128-cbc or des-ede3-cbc) +# $4 encrypt=1/decrypt=0 +# $5 de/encrypted data in hex form +# return en/decrypted data in hex form +my $encdec; + +# +# Derive an RSA key from the given X9.31 parameters. +# $1: modulus size +# $2: E in hex form +# $3: Xp1 in hex form +# $4: Xp2 in hex form +# $5: Xp in hex form +# $6: Xq1 in hex form +# $7: Xq2 in hex form +# $8: Xq 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 +# N\n +# D\n +my $rsa_derive; + +# Sign a message with RSA +# $1: data to be signed in hex form +# $2: Hash algo +# $3: Key file in PEM format with the private key +# return: digest in hex format +my $rsa_sign; + +# Verify a message with RSA +# $1: data to be verified in hex form +# $2: hash algo +# $3: file holding the public RSA key in PEM format +# $4: file holding the signature in binary form +# return: 1 == verified / 0 == not verified +my $rsa_verify; + +# generate a new private RSA key with the following properties: +# exponent is 65537 +# PEM format +# $1 key size in bit +# $2 keyfile name +# return: nothing, but file created +my $gen_rsakey; + +# Creating a hash +# $1: Plaintext in hex form +# $2: hash type in the form documented in openssl's dgst(1ssl) - e.g. +# sha1, sha224, sha256, sha384, sha512 +# return: hash in hex form +my $hash; + +# supplying the call to the external cipher implementation +# that is being used to keep STDIN and STDOUT open +# to maintain the state of the block chaining +# $1: cipher +# $2: 1=encryption, 0=decryption +# $3: buffersize needed for openssl +# $4: encryption key in binary form +# $5: IV in binary form +# return: command line to execute the application +my $state_cipher; +# the only difference of the DES version is that it implements the inner loop +# of the TDES tests +my $state_cipher_des; + +# supplying the call to the external cipher implementation +# that is being used to keep STDIN and STDOUT open +# to maintain the state of the RNG with its seed +# +# input holds seed values +# $1: cipher key in hex format +# $2: DT value in hex format +# $3: V value in hex format +# +# return: command line to execute the application +# +# the application is expected to deliver random values on STDOUT - the script +# reads 128 bits repeatedly where the state of the RNG must be retained +# between the reads. The output of the RNG on STDOUT is assumed to be binary. +my $state_rng; + +# Generate an HMAC based on SHAx +# $1: Key to be used for the HMAC in hex format +# $2: length of the hash to be calculated in bits +# $3: Message for which the HMAC shall be calculated in hex format +# $4: hash type (1 - SHA1, 224 - SHA224, and so on) +# return: calculated HMAC in hex format +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 +# Q\n +# G\n +# Seed\n +# counter\n +# 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 +# $2: P in hex form +# $3: Q in hex form +# $4: G in hex form +# $5: Y in hex form +my $dsa_genpubkey; + +# Verify a message with DSA +# $1: data to be verified in hex form +# $2: file holding the public DSA key in PEM format +# $3: R value of the signature +# $4: S value of the signature +# return: 1 == verified / 0 == not verified +my $dsa_verify; + +# generate a new DSA key with the following properties: +# PEM 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; + +# interface with SP800-90A DRBG +# $1 cipher - the sign whether prediction resistance is required is visible on +# set additional entropy +# $2 expected length of output +# $3 entropy in hex +# $4 nonce in hex +# $5 personalization string in hex - if "z", string was empty +# $6 1st additional input in hex - if "z", string was empty +# $7 2nd additional input in hex - if "z", string was empty +# $8 1st additional entropy in hex - if "z", string was empty +# $9 2nd additional entropy in hex - if "z", string was empty +# return: random value in hex format +my $drbg; + +################################################################ +##### OpenSSL interface functions +################################################################ +sub openssl_encdec($$$$$) { + my $key=shift; + my $iv=shift; + my $cipher=shift; + my $enc = (shift) ? "-e" : "-d"; + my $data=shift; + + # We only invoke the driver with the IV parameter, if we have + # an IV, otherwise, we skip it + $iv = "-iv $iv" if ($iv); + + $data=hex2bin($data); + my $program="openssl enc -$cipher -nopad -nosalt -K $key $enc $iv"; + $program = "rc4 -k $key" if $opt{'R'}; #for ARCFOUR, no IV must be given + $data=pipe_through_program($data,$program); + return bin2hex($data); +} + +sub openssl_rsa_sign($$$) { + my $data = shift; + my $cipher = shift; + my $keyfile = shift; + + $data=hex2bin($data); + die "ARCFOUR not available for RSA" if $opt{'R'}; + $data=pipe_through_program($data, + "openssl dgst -$cipher -binary -sign $keyfile"); + return bin2hex($data); +} + +sub openssl_rsa_verify($$$$) { + my $data = shift; + my $cipher = shift; + my $keyfile = shift; + my $sigfile = shift; + + $data = hex2bin($data); + die "ARCFOUR not available for RSA" if $opt{'R'}; + $data = pipe_through_program($data, + "openssl dgst -$cipher -binary -verify $keyfile -signature $sigfile"); + + # Parse through the OpenSSL output information + return ($data =~ /OK/); +} + +sub openssl_gen_rsakey($$) { + my $keylen = shift; + my $file = shift; + + die "ARCFOUR not available for RSA" if $opt{'R'}; + # generating of a key with exponent 0x10001 + my @args = ("openssl", "genrsa", "-F4", "-out", "$file", "$keylen"); + system(@args) == 0 + or die "system @args failed: $?"; + die "system @args failed: file $file not created" if (! -f $file); +} + +sub openssl_hash($$) { + my $pt = shift; + my $cipher = shift; + + die "ARCFOUR not available for hashes" if $opt{'R'}; + my $hash = hex2bin($pt); + #bin2hex not needed as the '-hex' already converts it + return pipe_through_program($hash, "openssl dgst -$cipher -hex"); +} + +sub openssl_state_cipher($$$$$) { + my $cipher = shift; + my $encdec = shift; + my $bufsize = shift; + my $key = shift; + my $iv = shift; + + my $enc = $encdec ? "-e": "-d"; + + # We only invoke the driver with the IV parameter, if we have + # an IV, otherwise, we skip it + $iv = "-iv ".bin2hex($iv) if ($iv); + + my $out = "openssl enc -'$cipher' $enc -nopad -nosalt -bufsize $bufsize -K ".bin2hex($key)." $iv"; + #for ARCFOUR, no IV must be given + $out = "rc4 -k " . bin2hex($key) if $opt{'R'}; + return $out; +} + +###### End of OpenSSL interface implementation ############ + +########################################################### +###### libgcrypt implementation +########################################################### +sub libgcrypt_encdec($$$$$) { + my $key=shift; + my $iv=shift; + my $cipher=shift; + my $enc = (shift) ? "encrypt" : "decrypt"; + my $data=shift; + + # We only invoke the driver with the IV parameter, if we have + # an IV, otherwise, we skip it + $iv = "--iv $iv" if ($iv); + + my $program="fipsdrv --key $key $iv --algo $cipher $enc"; + + return pipe_through_program($data,$program); + +} + +sub libgcrypt_rsa_derive($$$$$$$$) { + my $n = shift; + my $e = shift; + my $xp1 = shift; + my $xp2 = shift; + my $xp = shift; + my $xq1 = shift; + my $xq2 = shift; + my $xq = shift; + my $sexp; + my @tmp; + + $n = sprintf ("%u", $n); + $e = sprintf ("%u", hex($e)); + $sexp = "(genkey(rsa(nbits " . sprintf ("%u:%s", length($n), $n) . ")" + . "(rsa-use-e " . sprintf ("%u:%s", length($e), $e) . ")" + . "(derive-parms" + . "(Xp1 #$xp1#)" + . "(Xp2 #$xp2#)" + . "(Xp #$xp#)" + . "(Xq1 #$xq1#)" + . "(Xq2 #$xq2#)" + . "(Xq #$xq#))))\n"; + + return pipe_through_program($sexp, "fipsdrv rsa-derive"); +} + + +sub libgcrypt_rsa_sign($$$) { + my $data = shift; + my $hashalgo = shift; + my $keyfile = shift; + + die "ARCFOUR not available for RSA" if $opt{'R'}; + + return pipe_through_program($data, + "fipsdrv --pkcs1 --algo $hashalgo --key $keyfile rsa-sign"); +} + +sub libgcrypt_rsa_verify($$$$) { + my $data = shift; + my $hashalgo = shift; + my $keyfile = shift; + my $sigfile = shift; + + die "ARCFOUR not available for RSA" if $opt{'R'}; + $data = pipe_through_program($data, + "fipsdrv --pkcs1 --algo $hashalgo --key $keyfile --signature $sigfile rsa-verify"); + + # Parse through the output information + return ($data =~ /GOOD signature/); +} + +sub libgcrypt_gen_rsakey($$) { + my $keylen = shift; + my $file = shift; + + die "ARCFOUR not available for RSA" if $opt{'R'}; + my @args = ("fipsdrv --keysize $keylen rsa-gen > $file"); + system(@args) == 0 + or die "system @args failed: $?"; + die "system @args failed: file $file not created" if (! -f $file); +} + +sub libgcrypt_hash($$) { + my $pt = shift; + my $hashalgo = shift; + + my $program = "fipsdrv --algo $hashalgo digest"; + die "ARCFOUR not available for hashes" if $opt{'R'}; + + return pipe_through_program($pt, $program); +} + +sub libgcrypt_state_cipher($$$$$) { + my $cipher = shift; + my $enc = (shift) ? "encrypt": "decrypt"; + my $bufsize = shift; + my $key = shift; + my $iv = shift; + + # We only invoke the driver with the IV parameter, if we have + # an IV, otherwise, we skip it + $iv = "--iv ".bin2hex($iv) if ($iv); + + my $program="fipsdrv --binary --key ".bin2hex($key)." $iv --algo '$cipher' --chunk '$bufsize' $enc"; + + return $program; +} + +sub libgcrypt_state_cipher_des($$$$$) { + my $cipher = shift; + my $enc = (shift) ? "encrypt": "decrypt"; + my $bufsize = shift; + my $key = shift; + my $iv = shift; + + # We only invoke the driver with the IV parameter, if we have + # an IV, otherwise, we skip it + $iv = "--iv ".bin2hex($iv) if ($iv); + + my $program="fipsdrv --algo '$cipher' --mct-server $enc"; + + return $program; +} + +sub libgcrypt_state_rng($$$) { + my $key = shift; + my $dt = shift; + my $v = shift; + + return "fipsdrv --binary --loop --key $key --iv $v --dt $dt random"; +} + +sub libgcrypt_hmac($$$$) { + my $key = shift; + my $maclen = shift; + my $msg = shift; + my $hashtype = shift; + + my $program = "fipsdrv --key $key --algo $hashtype hmac-sha"; + return pipe_through_program($msg, $program); +} + +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 --qsize $qsize --key \'$domain\' dsa-g-gen"; + return pipe_through_program("", $program); +} + +sub libgcrypt_gen_dsakey($$$) { + my $mod = shift; + my $qsize = shift; + my $file = shift; + + my $program = "fipsdrv --keysize $mod --qsize $qsize --key $file dsa-gen"; + my $tmp; + my %ret; + + die "ARCFOUR not available for DSA" if $opt{'R'}; + + $tmp = pipe_through_program("", $program); + die "dsa key gen failed: file $file not created" if (! -f $file); + + @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; + my $q = shift; + my $g = shift; + my $y = shift; + + my $sexp; + + $sexp = "(public-key(dsa(p #$p#)(q #$q#)(g #$g#)(y #$y#)))"; + + open(FH, ">", $filename) or die; + print FH $sexp; + close FH; +} + +sub libgcrypt_dsa_sign($$) { + my $data = shift; + my $keyfile = shift; + my $tmp; + my %ret; + + die "ARCFOUR not available for DSA" if $opt{'R'}; + + $tmp = pipe_through_program($data, "fipsdrv --key $keyfile dsa-sign"); + @ret{'Y', 'R', 'S'} = split(/\n/, $tmp); + return %ret; +} + +sub libgcrypt_dsa_verify($$$$) { + my $data = shift; + my $keyfile = shift; + my $r = shift; + my $s = shift; + + my $ret; + + die "ARCFOUR not available for DSA" if $opt{'R'}; + + my $sigfile = "$keyfile.sig"; + open(FH, ">$sigfile") or die "Cannot create file $sigfile: $?"; + print FH "(sig-val(dsa(r #$r#)(s #$s#)))"; + close FH; + + $ret = pipe_through_program($data, + "fipsdrv --key $keyfile --signature $sigfile dsa-verify"); + unlink ($sigfile); + # Parse through the output information + return ($ret =~ /GOOD signature/); +} + +sub libgcrypt_drbg($$$$$$$$$) { + my $cipher = shift; + my $drbg_expectedlen = shift; + my $drbg_entropy = shift; + my $drbg_nonce = shift; + my $drbg_pers = shift; + my $drbg_addtla = shift; + my $drbg_addtlb = shift; + my $drbg_entpra = shift; + my $drbg_entprb = shift; + my $out = ""; + my $parameter = ""; + my $flags = 0; + + $drbg_expectedlen = $drbg_expectedlen / 8; + + if ($cipher =~ /aes128/) { + $flags |= (1 << 0 | 1 << 13); + } + if ($cipher =~ /aes192/) { + $flags |= (1 << 0 | 1 << 14); + } + if ($cipher =~ /aes256/) { + $flags |= (1 << 0 | 1 << 15); + } + if ($cipher =~ /sha1/) { + $flags |= 1 << 4; + } + if ($cipher =~ /sha256/) { + $flags |= 1 << 6; + } + if ($cipher =~ /sha384/) { + $flags |= 1 << 7; + } + if ($cipher =~ /sha512/) { + $flags |= 1 << 8; + } + if ($cipher =~ /hmac/) { + $flags |= 1 << 12; + } + + if ($drbg_entpra ne "" && $drbg_entprb ne "") { + $flags |= 1 << 28; + } + + $parameter .= " -f $flags"; + # test drvier requires concatenated entropy/nonce + $drbg_entropy = $drbg_entropy . $drbg_nonce; + $parameter .= " -e $drbg_entropy"; + $parameter .= " -l $drbg_expectedlen"; + if ($drbg_pers ne "z") { $parameter .= " -p $drbg_pers"; } + if ($drbg_addtla ne "z") { $parameter .= " -c $drbg_addtla";} + if ($drbg_addtlb ne "z") { $parameter .= " -d $drbg_addtlb";} + if ($drbg_entpra ne "z" && $drbg_entpra ne "") { + $parameter .= " -y $drbg_entpra"; + } + if ($drbg_entprb ne "z" && $drbg_entprb ne "") { + $parameter .= " -z $drbg_entprb"; + } + + $out = pipe_through_program("", + "/usr/lib/libgcrypt/drbg_test $parameter 2>/dev/null"); + + return $out; +} + + +######### End of libgcrypt implementation ################ + +################################################################ +###### Kernel Crypto API interface functions +################################################################ + +#my $DIR = "/sys/kernel/debug/cryptoapi/"; +my $DIR = "/sys/kernel/debug/drbg-cavs/"; +my $CIPHER_AES = Math::BigInt->new("0x0000000000000001"); +my $CIPHER_TDES = Math::BigInt->new("0x0000000000000002"); + +my $CIPHER_SHA1 = Math::BigInt->new("0x0000000000010000"); +my $CIPHER_SHA224 = Math::BigInt->new("0x0000000000020000"); +my $CIPHER_SHA256 = Math::BigInt->new("0x0000000000040000"); +my $CIPHER_SHA384 = Math::BigInt->new("0x0000000000100000"); +my $CIPHER_SHA512 = Math::BigInt->new("0x0000000000200000"); + +my $CIPHER_X931RNG = Math::BigInt->new("0x0000000001000000"); + +my $TYPE_CTR = Math::BigInt->new("0x0010000000000000"); +my $TYPE_GENERIC = Math::BigInt->new("0x0020000000000000"); +my $TYPE_ASM = Math::BigInt->new("0x0040000000000000"); +my $TYPE_CBC = Math::BigInt->new("0x0100000000000000"); +my $TYPE_ECB = Math::BigInt->new("0x0200000000000000"); +my $TYPE_KEEP = Math::BigInt->new("0x0400000000000000"); +my $TYPE_HMAC = Math::BigInt->new("0x1000000000000000"); +my $TYPE_ENC = Math::BigInt->new("0x2000000000000000"); +my $TYPE_DEC = Math::BigInt->new("0x4000000000000000"); + +sub writedata($$) { + my $file=shift; + my $data=shift; + $file = $DIR . $file; + open(FH, ">$file") or die "Cannot open file $file"; + my $dlen = length($data); + my $len = syswrite(FH, $data, $dlen); + if($len != $dlen) { + die "Cannot write data of length $dlen"; + } + close(FH); +} + +sub readdata($$) { + my $file=shift; + my $bytes=shift; + my $out; + $file = $DIR . $file; + open(FH, "<$file") or die "Cannot open file $file"; + my $len = sysread(FH, $out, $bytes); + if(!defined($len)) { + $out=""; + } + return $out; +} + +sub cryptoapi_setupencdec($$$$$) { + my $key=shift; + my $iv=shift; + my $cipher=shift; + my $enc = shift; + my $keep = shift; + + # enc / dec yet unhandled - should not matter anyhow + if($cipher eq "des-ede3-cbc") { + $cipher = $CIPHER_TDES|$TYPE_CBC; + } elsif($cipher eq "des-ede3") { + $cipher = $CIPHER_TDES|$TYPE_ECB; + } elsif($cipher =~ /^aes-\d{3}-cbc$/) { + $cipher = $CIPHER_AES|$TYPE_CBC; + } elsif($cipher =~ /^aes-\d{3}-ecb$/) { + $cipher = $CIPHER_AES|$TYPE_ECB; + } else { + die "Unknown cipher $cipher for kernel crypto API"; + } + if($enc) { + $cipher = $cipher | $TYPE_ENC; + } else { + $cipher = $cipher | $TYPE_DEC; + } + if($keep) { + $cipher = $cipher | $TYPE_KEEP; + } + + # DIFFERENT IMPLEMENTATION enable generic implementation! + # $cipher = $cipher | $TYPE_GENERIC; + + # DIFFERENT IMPLEMENTATION enable asm implementation! + # $cipher = $cipher | $TYPE_ASM; + + $cipher = $cipher->as_hex; + + writedata("cipher", $cipher); + writedata("key", hex2bin($key)); + + # We only invoke the driver with the IV parameter, if we have + # an IV, otherwise, we skip it + if(defined($iv)) { + writedata("iv", hex2bin($iv)); + } +} + +sub cryptoapi_encdec($$$$$) { + my $key=shift; + my $iv=shift; + my $cipher=shift; + my $enc = shift; + my $data = shift; + cryptoapi_setupencdec($key, $iv, $cipher, $enc, 0); + writedata("data", hex2bin($data)); + my $out; + $out = readdata("data", 100000); + return bin2hex($out); +} + +sub cryptoapi_state_cipher($$$$$) { + my $cipher = shift; + my $enc = shift; + my $bufsize = shift; + my $key = bin2hex(shift); + my $iv = shift; + $iv = bin2hex($iv) if ($iv); + cryptoapi_setupencdec($key, $iv, $cipher, $enc, 1); + my $file = $DIR . "data"; + return "statewrapper.pl $file $bufsize"; +} + +sub cryptoapi_hash($$) { + my $pt = shift; + my $hashalgo = shift; + + my $out; + if($hashalgo eq "sha1") { + $hashalgo = $CIPHER_SHA1; + } elsif($hashalgo eq "sha224") { + $hashalgo = $CIPHER_SHA224; + } elsif($hashalgo eq "sha256") { + $hashalgo = $CIPHER_SHA256; + } elsif($hashalgo eq "sha384") { + $hashalgo = $CIPHER_SHA384; + } elsif($hashalgo eq "sha512") { + $hashalgo = $CIPHER_SHA512; + } else { + die "Unknown hashalgo $hashalgo for kernel crypto API"; + } + + # DIFFERENT IMPLEMENTATION enable generic implementation! + # $hashalgo = $hashalgo | $TYPE_GENERIC; + + $hashalgo = $hashalgo->as_hex; + writedata("cipher", $hashalgo); + writedata("data", hex2bin($pt)); + + die "ARCFOUR not available for hashes" if $opt{'R'}; + + $out = readdata("data", 100000); + return bin2hex($out); +} + +sub cryptoapi_hmac($$$$) { + my $key = shift; + my $maclen = shift; + my $msg = shift; + my $hashtype = shift; + + my $out; + if($hashtype eq "1") { + $hashtype = $CIPHER_SHA1 | $TYPE_HMAC; + } elsif($hashtype eq "224") { + $hashtype = $CIPHER_SHA224 | $TYPE_HMAC; + } elsif($hashtype eq "256") { + $hashtype = $CIPHER_SHA256 | $TYPE_HMAC; + } elsif($hashtype eq "384") { + $hashtype = $CIPHER_SHA384 | $TYPE_HMAC; + } elsif($hashtype eq "512") { + $hashtype = $CIPHER_SHA512 | $TYPE_HMAC; + } else { + die "Unknown hashalgo $hashtype for kernel crypto API"; + } + + # DIFFERENT IMPLEMENTATION enable generic implementation! + # $hashtype = $hashalgo | $TYPE_GENERIC; + + $hashtype = $hashtype->as_hex; + writedata("cipher", $hashtype); + writedata("key", hex2bin($key)); + writedata("data", hex2bin($msg)); + + $out = readdata("data", 100000); + return bin2hex($out); +} + +sub cryptoapi_state_rng($$$) { + my $key = shift; + my $dt = shift; + my $v = shift; + + my $seed = $v . $key . $dt; + $seed=hex2bin($seed); + + writedata("cipher", $CIPHER_X931RNG->as_hex); + writedata("key", $seed); + + my $file = $DIR . "data"; + return "statewrapper.pl $file"; +} + +sub cryptoapi_drbg($$$$$$$$$) { + my $cipher = shift; + my $drbg_expectedlen = shift; + my $drbg_entropy = shift; + my $drbg_nonce = shift; + my $drbg_pers = shift; + my $drbg_addtla = shift; + my $drbg_addtlb = shift; + my $drbg_entpra = shift; + my $drbg_entprb = shift; + my $out = ""; + + $drbg_expectedlen = $drbg_expectedlen / 8; + + if ($cipher =~ /hash\s+(\w+)/) { $cipher = $1; } + if ($cipher =~ /hmac\s+(\w+)/) { $cipher = "hmac($1)"; } + if ($cipher =~ /ctr\s+(\w+)/) { $cipher = "ctr($1)"; } + + if ($drbg_entpra ne "" && $drbg_entprb ne "") { + $cipher = "drbg(pr($cipher))"; + } else { + $cipher = "drbg(nopr($cipher))"; + } + + # test drvier requires concatenated entropy/nonce + $drbg_entropy = $drbg_entropy . $drbg_nonce; + writedata("name", $cipher); + writedata("entropy", hex2bin($drbg_entropy)); + if ($drbg_pers ne "z") { writedata("pers", hex2bin($drbg_pers)); } + if ($drbg_addtla ne "z") { writedata("addtla", hex2bin($drbg_addtla));} + if ($drbg_addtlb ne "z") { writedata("addtlb", hex2bin($drbg_addtlb));} + if ($drbg_entpra ne "z" && $drbg_entpra ne "") { + writedata("entpra", hex2bin($drbg_entpra)); + } + if ($drbg_entprb ne "z" && $drbg_entprb ne "") { + writedata("entprb", hex2bin($drbg_entprb)); + } + $out = readdata("data", $drbg_expectedlen); + $out = bin2hex($out); + return $out; +} + +################################################################ +###### Vendor1 interface functions +################################################################ + +sub vendor1_encdec($$$$$) { + my $key=shift; + my $iv=shift; + my $cipher=shift; + my $enc = (shift) ? "encrypt" : "decrypt"; + my $data=shift; + + $data=hex2bin($data); + my $program = "./aes $enc $key"; + $data=pipe_through_program($data,$program); + return bin2hex($data); +} + +sub vendor1_state_cipher($$$$$) { + my $cipher = shift; + my $encdec = shift; + my $bufsize = shift; + my $key = shift; + my $iv = shift; + + $key = bin2hex($key); + my $enc = $encdec ? "encrypt": "decrypt"; + my $out = "./aes $enc $key $bufsize"; + return $out; +} + +##### No other interface functions below this point ###### +########################################################## + +########################################################## +# General helper routines + +# Executing a program by feeding STDIN and retrieving +# STDOUT +# $1: data string to be piped to the app on STDIN +# rest: program and args +# returns: STDOUT of program as string +sub pipe_through_program($@) { + my $in = shift; + my @args = @_; + + my ($CO, $CI); + my $pid = open2($CO, $CI, @args); + + my $out = ""; + my $len = length($in); + my $first = 1; + while (1) { + my $rin = ""; + my $win = ""; + # Output of prog is FD that we read + vec($rin,fileno($CO),1) = 1; + # Input of prog is FD that we write + # check for $first is needed because we can have NULL input + # that is to be written to the app + if ( $len > 0 || $first) { + (vec($win,fileno($CI),1) = 1); + $first=0; + } + # Let us wait for 100ms + my $nfound = select(my $rout=$rin, my $wout=$win, undef, 0.1); + if ( $wout ) { + my $written = syswrite($CI, $in, $len); + die "broken pipe" if !defined $written; + $len -= $written; + substr($in, 0, $written) = ""; + if ($len <= 0) { + close $CI or die "broken pipe: $!"; + } + } + if ( $rout ) { + my $tmp_out = ""; + my $bytes_read = sysread($CO, $tmp_out, 4096); + $out .= $tmp_out; + last if ($bytes_read == 0); + } + } + close $CO or die "broken pipe: $!"; + waitpid $pid, 0; + + return $out; +} + +# +# convert ASCII hex to binary input +# $1 ASCII hex +# return binary representation +sub hex2bin($) { + my $in = shift; + my $len = length($in); + $len = 0 if ($in eq "00"); + return pack("H$len", "$in"); +} + +# +# convert binary input to ASCII hex +# $1 binary value +# return ASCII hex representation +sub bin2hex($) { + my $in = shift; + my $len = length($in)*2; + return unpack("H$len", "$in"); +} + +# $1: binary byte (character) +# returns: binary byte with odd parity using low bit as parity bit +sub odd_par($) { + my $in = ord(shift); + my $odd_count=0; + for(my $i=1; $i<8; $i++) { + $odd_count++ if ($in & (1<<$i)); + } + + my $out = $in; + if ($odd_count & 1) { # check if parity is already odd + $out &= ~1; # clear the low bit + } else { + $out |= 1; # set the low bit + } + + return chr($out); +} + +# DES keys uses only the 7 high bits of a byte, the 8th low bit +# is the parity bit +# as the new key is calculated from oldkey XOR cipher in the MCT test, +# the parity is not really checked and needs to be set to match +# expectation (OpenSSL does not really care, but the FIPS +# test result is expected that the key has the appropriate parity) +# $1: arbitrary binary string +# returns: string with odd parity set in low bit of each byte +sub fix_key_parity($) { + my $in = shift; + my $out = ""; + for (my $i = 0; $i < length($in); $i++) { + $out .= odd_par(substr($in, $i, 1)); + } + + return $out; +} + +#################################################### +# DER/PEM utility functions +# Cf. http://www.columbia.edu/~ariel/ssleay/layman.html + +# Convert unsigned integer to base256 bigint bytes +# $1 integer +# returns base256 octet string +sub int_base256_unsigned($) { + my $n = shift; + + my $out = chr($n & 255); + while ($n>>=8) { + $out = chr($n & 255) . $out; + } + + return $out; +} + +# Convert signed integer to base256 bigint bytes +# $1 integer +# returns base256 octet string +sub int_base256_signed($) { + my $n = shift; + my $negative = ($n < 0); + + if ($negative) { + $n = -$n-1; + } + + my $out = int_base256_unsigned($n); + + if (ord(substr($out, 0, 1)) & 128) { + # it's supposed to be positive but has sign bit set, + # add a leading zero + $out = chr(0) . $out; + } + + if ($negative) { + my $neg = chr(255) x length($out); + $out ^= $neg; + } + + return $out; +} + +# Length header for specified DER object length +# $1 length as integer +# return octet encoding for length +sub der_len($) { + my $len = shift; + + if ($len <= 127) { + return chr($len); + } else { + my $blen = int_base256_unsigned($len); + + return chr(128 | length($blen)) . $blen; + } +} + +# Prepend length header to object +# $1 object as octet sequence +# return length header for object followed by object as octets +sub der_len_obj($) { + my $x = shift; + + return der_len(length($x)) . $x; +} + +# DER sequence +# $* objects +# returns DER sequence consisting of the objects passed as arguments +sub der_seq { + my $seq = join("", @_); + return chr(0x30) . der_len_obj($seq); +} + +# DER bitstring +# $1 input octets (must be full octets, fractional octets not supported) +# returns input encapsulated as bitstring +sub der_bitstring($) { + my $x = shift; + + $x = chr(0) . $x; + + return chr(0x03) . der_len_obj($x); +} + +# base-128-encoded integer, used for object numbers. +# $1 integer +# returns octet sequence +sub der_base128($) { + my $n = shift; + + my $out = chr($n & 127); + + while ($n>>=7) { + $out = chr(128 | ($n & 127)) . $out; + } + + return $out; +} + +# Generating the PEM certificate string +# (base-64-encoded DER string) +# $1 DER string +# returns octet sequence +sub pem_cert($) { + my $n = shift; + + my $out = "-----BEGIN PUBLIC KEY-----\n"; + $out .= encode_base64($n); + $out .= "-----END PUBLIC KEY-----\n"; + + return $out; +} + +# DER object identifier +# $* sequence of id numbers +# returns octets +sub der_objectid { + my $v1 = shift; + my $v2 = shift; + + my $out = chr(40*$v1 + $v2) . join("", map { der_base128($_) } @_); + + return chr(0x06) . der_len_obj($out); +} + +# DER signed integer +# $1 number as octet string (base 256 representation, high byte first) +# returns number in DER integer encoding +sub der_bigint($) { + my $x = shift; + + return chr(0x02) . der_len_obj($x); +} + +# DER positive integer with leading zeroes stripped +# $1 number as octet string (base 256 representation, high byte first) +# returns number in DER integer encoding +sub der_pos_bigint($) { + my $x = shift; + + # strip leading zero digits + $x =~ s/^[\0]+//; + + # need to prepend a zero if high bit set, since it would otherwise be + # interpreted as a negative number. Also needed for number 0. + if (!length($x) || ord(substr($x, 0, 1)) >= 128) { + $x = chr(0) . $x; + } + + return der_bigint($x); +} + +# $1 number as signed integer +# returns number as signed DER integer encoding +sub der_int($) { + my $n = shift; + + return der_bigint(int_base256_signed($n)); +} + +# the NULL object constant +sub der_null() { + return chr(0x05) . chr(0x00); +} + +# Unit test helper +# $1 calculated result +# $2 expected result +# no return value, dies if results differ, showing caller's line number +sub der_test($$) { + my $actual = bin2hex(shift); + my $expected = shift; + + my @caller = caller; + $actual eq $expected or die "Error:line $caller[2]:assertion failed: " + ."$actual != $expected\n"; +} + +# Unit testing for the DER encoding functions +# Examples from http://www.columbia.edu/~ariel/ssleay/layman.html +# No input, no output. Dies if unit tests fail. +sub der_unit_test { + ## uncomment these if you want to test the test framework + #print STDERR "Unit test running\n"; + #der_test chr(0), "42"; + + der_test der_null, "0500"; + + # length bytes + der_test der_len(1), "01"; + der_test der_len(127), "7f"; + der_test der_len(128), "8180"; + der_test der_len(256), "820100"; + der_test der_len(65536), "83010000"; + + # bigint + der_test der_bigint(chr(0)), "020100"; + der_test der_bigint(chr(128)), "020180"; # -128 + der_test der_pos_bigint(chr(128)), "02020080"; # +128 + der_test der_pos_bigint(chr(0).chr(0).chr(1)), "020101"; + der_test der_pos_bigint(chr(0)), "020100"; + + # integers (tests base256 conversion) + der_test der_int( 0), "020100"; + der_test der_int( 127), "02017f"; + der_test der_int( 128), "02020080"; + der_test der_int( 256), "02020100"; + der_test der_int( -1), "0201ff"; + der_test der_int( -128), "020180"; + der_test der_int( -129), "0202ff7f"; + der_test der_int(-65536), "0203ff0000"; + der_test der_int(-65537), "0203feffff"; + + # object encoding, "RSA Security" + der_test der_base128(840), "8648"; + der_test der_objectid(1, 2, 840, 113549), "06062a864886f70d"; + + # Combinations + der_test der_bitstring("ABCD"), "03050041424344"; + der_test der_bitstring(der_null), "0303000500"; + der_test der_seq(der_int(0), der_null), "30050201000500"; + + # The big picture + der_test der_seq(der_seq(der_objectid(1, 2, 840, 113549), der_null), + der_bitstring(der_seq(der_pos_bigint(chr(5)), + der_pos_bigint(chr(3))))), + "3017300a06062a864886f70d05000309003006020105020103"; +} + +#################################################### +# OpenSSL missing functionality workarounds + +## Format of an RSA public key: +# 0:d=0 hl=3 l= 159 cons: SEQUENCE +# 3:d=1 hl=2 l= 13 cons: SEQUENCE +# 5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption +# 16:d=2 hl=2 l= 0 prim: NULL +# 18:d=1 hl=3 l= 141 prim: BIT STRING +# [ sequence: INTEGER (n), INTEGER (e) ] + +# generate RSA pub key in PEM format +# $1: filename where PEM key is to be stored +# $2: n of the RSA key in hex +# $3: e of the RSA key in hex +# return: nothing, but file created +sub gen_pubrsakey($$$) { + my $filename=shift; + my $n = shift; + my $e = shift; + + # make sure the DER encoder works ;-) + der_unit_test(); + + # generate DER encoding of the public key + + my $rsaEncryption = der_objectid(1, 2, 840, 113549, 1, 1, 1); + + my $der = der_seq(der_seq($rsaEncryption, der_null), + der_bitstring(der_seq(der_pos_bigint(hex2bin($n)), + der_pos_bigint(hex2bin($e))))); + + open(FH, ">", $filename) or die; + print FH pem_cert($der); + close FH; + +} + +# generate RSA pub key in PEM format +# +# This implementation uses "openssl asn1parse -genconf" which was added +# in openssl 0.9.8. It is not available in older openssl versions. +# +# $1: filename where PEM key is to be stored +# $2: n of the RSA key in hex +# $3: e of the RSA key in hex +# return: nothing, but file created +sub gen_pubrsakey_using_openssl($$$) { + my $filename=shift; + my $n = shift; + my $e = shift; + + my $asn1 = "asn1=SEQUENCE:pubkeyinfo + +[pubkeyinfo] +algorithm=SEQUENCE:rsa_alg +pubkey=BITWRAP,SEQUENCE:rsapubkey + +[rsa_alg] +algorithm=OID:rsaEncryption +parameter=NULL + +[rsapubkey] +n=INTEGER:0x$n + +e=INTEGER:0x$e"; + + open(FH, ">$filename.cnf") or die "Cannot create file $filename.cnf: $?"; + print FH $asn1; + close FH; + my @args = ("openssl", "asn1parse", "-genconf", "$filename.cnf", "-noout", "-out", "$filename.der"); + system(@args) == 0 or die "system @args failed: $?"; + @args = ("openssl", "rsa", "-inform", "DER", "-in", "$filename.der", + "-outform", "PEM", "-pubin", "-pubout", "-out", "$filename"); + system(@args) == 0 or die "system @args failed: $?"; + die "RSA PEM formatted key file $filename was not created" + if (! -f $filename); + + unlink("$filename.cnf"); + unlink("$filename.der"); +} + +############################################ +# Test cases + +# This is the Known Answer Test +# $1: the string that we have to put in front of the key +# when printing the key +# $2: crypto key1 in hex form +# $3: crypto key2 in hex form (TDES, undef otherwise) +# $4: crypto key3 in hex form (TDES, undef otherwise) +# $5: IV in hex form +# $6: Plaintext (enc=1) or Ciphertext (enc=0) in hex form +# $7: cipher +# $8: encrypt=1/decrypt=0 +# return: string formatted as expected by CAVS +sub kat($$$$$$$$) { + my $keytype = shift; + my $key1 = shift; + my $key2 = shift; + my $key3 = shift; + my $iv = shift; + my $pt = shift; + my $cipher = shift; + my $enc = shift; + + my $out = ""; + + $out .= "$keytype = $key1\n"; + + # this is the concardination of the keys for 3DES + if (defined($key2)) { + $out .= "KEY2 = $key2\n"; + $key1 = $key1 . $key2; + } + if (defined($key3)) { + $out .= "KEY3 = $key3\n"; + $key1= $key1 . $key3; + } + + $out .= "IV = $iv\n" if (defined($iv) && $iv ne ""); + if ($enc) { + $out .= "PLAINTEXT = $pt\n"; + $out .= "CIPHERTEXT = " . &$encdec($key1, $iv, $cipher, 1, $pt) . "\n"; + } else { + $out .= "CIPHERTEXT = $pt\n"; + $out .= "PLAINTEXT = " . &$encdec($key1, $iv, $cipher, 0, $pt) . "\n"; + } + + return $out; +} + +# This is the Known Answer Test for Hashes +# $1: Plaintext in hex form +# $2: hash +# $3: hash length (undef if not applicable) +# return: string formatted as expected by CAVS +sub hash_kat($$$) { + my $pt = shift; + my $cipher = shift; + my $len = shift; + + my $out = ""; + $out .= "Len = $len\n" if (defined($len)); + $out .= "Msg = $pt\n"; + + $pt = "" if(!$len); + $out .= "MD = " . &$hash($pt, $cipher) . "\n"; + return $out; +} + +# Known Answer Test for HMAC hash +# $1: key length in bytes +# $2: MAC length in bytes +# $3: key for HMAC in hex form +# $4: message to be hashed +# return: string formatted as expected by CAVS +sub hmac_kat($$$$) { + my $klen = shift; + my $tlen = shift; + my $key = shift; + my $msg = shift; + + # XXX this is a hack - we need to decipher the HMAC REQ files in a more + # sane way + # + # This is a conversion table from the expected hash output size + # to the assumed hash type - we only define here the block size of + # the underlying hashes and do not allow any truncation + my %hashtype = ( + 20 => 1, + 28 => 224, + 32 => 256, + 48 => 384, + 64 => 512 + ); + + die "Hash output size $tlen is not supported!" + if(!defined($hashtype{$tlen})); + + my $out = ""; + $out .= "Klen = $klen\n"; + $out .= "Tlen = $tlen\n"; + $out .= "Key = $key\n"; + $out .= "Msg = $msg\n"; + $out .= "Mac = " . lc(&$hmac($key, $tlen, $msg, $hashtype{$tlen})) . "\n"; + + return $out; +} + + +# Cipher Monte Carlo Testing +# $1: the string that we have to put in front of the key +# when printing the key +# $2: crypto key1 in hex form +# $3: crypto key2 in hex form (TDES, undef otherwise) +# $4: crypto key3 in hex form (TDES, undef otherwise) +# $5: IV in hex form +# $6: Plaintext (enc=1) or Ciphertext (enc=0) in hex form +# $7: cipher +# $8: encrypt=1/decrypt=0 +# return: string formatted as expected by CAVS +sub crypto_mct($$$$$$$$) { + my $keytype = shift; + my $key1 = hex2bin(shift); + my $key2 = shift; + my $key3 = shift; + my $iv = hex2bin(shift); + my $source_data = hex2bin(shift); + my $cipher = shift; + my $enc = shift; + + my $out = ""; + + $key2 = hex2bin($key2) if (defined($key2)); + $key3 = hex2bin($key3) if (defined($key3)); + my $bufsize = length($source_data); + + # for AES: outer loop 0-99, inner 0-999 based on FIPS compliance tests + # for RC4: outer loop 0-99, inner 0-999 based on atsec compliance tests + # for DES: outer loop 0-399, inner 0-9999 based on FIPS compliance tests + my $ciph = substr($cipher,0,3); + my $oloop=100; + my $iloop=1000; + if ($ciph =~ /des/) {$oloop=400;$iloop=10000;} + + for (my $i=0; $i<$oloop; ++$i) { + $out .= "COUNT = $i\n"; + if (defined($key2)) { + $out .= "$keytype = ". bin2hex($key1). "\n"; + $out .= "KEY2 = ". bin2hex($key2). "\n"; + $key1 = $key1 . $key2; + } else { + $out .= "$keytype = ". bin2hex($key1). "\n"; + } + if(defined($key3)) { + $out .= "KEY3 = ". bin2hex($key3). "\n"; + $key1 = $key1 . $key3; + } + my $keylen = length($key1); + + $out .= "IV = ". bin2hex($iv) . "\n" + if (defined($iv) && $iv ne ""); + + if ($enc) { + $out .= "PLAINTEXT = ". bin2hex($source_data). "\n"; + } else { + $out .= "CIPHERTEXT = ". bin2hex($source_data). "\n"; + } + 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/ && defined($state_cipher_des)); + my $pid = open2($CO, $CI, $cipher_imp); + + my $calc_data = $iv; # CT[j] + my $old_calc_data; # CT[j-1] + my $old_old_calc_data; # CT[j-2] + my $next_source; + + # 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) + : "00"x(length($source_data)); + print $CI "1\n" + .$iloop."\n" + .bin2hex($key1)."\n" + .$iv_arg."\n" + .bin2hex($source_data)."\n\n" or die; + chomp(my $line = <$CO>); + $calc_data = hex2bin($line); + chomp($line = <$CO>); + $old_calc_data = hex2bin($line); + chomp($line = <$CO>); + $old_old_calc_data = hex2bin($line); + chomp($line = <$CO>); + $iv = hex2bin($line) if (defined($iv) && $iv ne ""); + chomp($line = <$CO>); + $next_source = hex2bin($line); + # Skip over empty line. + $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; + + #print STDERR "source_data=", bin2hex($source_data), "\n"; + syswrite $CI, $source_data or die $!; + my $len = sysread $CO, $calc_data, $bufsize; +#my $a = bin2hex($source_data); +#my $b = bin2hex($calc_data); +#warn "$a $b"; +#sleep 1; + + #print STDERR "len=$len, bufsize=$bufsize\n"; + die if $len ne $bufsize; + #print STDERR "calc_data=", bin2hex($calc_data), "\n"; + + if ( (!$enc && $ciph =~ /des/) || + $ciph =~ /rc4/ || + $cipher =~ /ecb/ ) { + #TDES in decryption mode, RC4 and ECB mode + #have a special rule + $source_data = $calc_data; + } else { + $source_data = $old_calc_data; + } +#my $c = bin2hex($source_data); +#my $d = bin2hex($calc_data); +#warn "$c $d"; + } + } + close $CO; + close $CI; + waitpid $pid, 0; + + if ($enc) { + $out .= "CIPHERTEXT = ". bin2hex($calc_data). "\n\n"; + } else { + $out .= "PLAINTEXT = ". bin2hex($calc_data). "\n\n"; + } + + if ( $ciph =~ /aes/ ) { + $key1 ^= substr($old_calc_data . $calc_data, -$keylen); + #print STDERR bin2hex($key1)."\n"; + } elsif ( $ciph =~ /des/ ) { + die "Wrong keylen $keylen" if ($keylen != 24); + + # $nkey needed as $key holds the concatenation of the + # old key atm + my $nkey = fix_key_parity(substr($key1,0,8) ^ $calc_data); + #print STDERR "KEY1 = ". bin2hex($nkey)."\n"; + if (substr($key1,0,8) ne substr($key1,8,8)) { + #print STDERR "KEY2 recalc: KEY1==KEY3, KEY2 indep. or all KEYs are indep.\n"; + $key2 = fix_key_parity((substr($key1,8,8) ^ $old_calc_data)); + } else { + #print STDERR "KEY2 recalc: KEY1==KEY2==KEY3\n"; + $key2 = fix_key_parity((substr($key1,8,8) ^ $calc_data)); + } + #print STDERR "KEY2 = ". bin2hex($key2)."\n"; + if ( substr($key1,0,8) eq substr($key1,16)) { + #print STDERR "KEY3 recalc: KEY1==KEY2==KEY3 or KEY1==KEY3, KEY2 indep.\n"; + $key3 = fix_key_parity((substr($key1,16) ^ $calc_data)); + } else { + #print STDERR "KEY3 recalc: all KEYs are independent\n"; + $key3 = fix_key_parity((substr($key1,16) ^ $old_old_calc_data)); + } + #print STDERR "KEY3 = ". bin2hex($key3)."\n"; + + # reset the first key - concardination happens at + # beginning of loop + $key1=$nkey; + } elsif ($ciph =~ /rc4/ ) { + $key1 ^= substr($calc_data, 0, 16); + #print STDERR bin2hex($key1)."\n"; + } else { + die "Test limitation: cipher '$cipher' not supported in Monte Carlo testing"; + } + + if ($cipher =~ /des-ede3-ofb/) { + $source_data = $source_data ^ $next_source; + } elsif (!$enc && $cipher =~ /des-ede3-cfb/) { + #TDES decryption CFB has a special rule + $source_data = $next_source; + } elsif ( $ciph =~ /rc4/ || $cipher eq "des-ede3" || $cipher =~ /ecb/) { + #No resetting of IV as the IV is all zero set initially (i.e. no IV) + $source_data = $calc_data; + } elsif (! $enc && $ciph =~ /des/ ) { + #TDES in decryption mode has a special rule + $iv = $old_calc_data; + $source_data = $calc_data; + } else { + $iv = $calc_data; + $source_data = $old_calc_data; + } + } + + return $out; +} + +# Hash Monte Carlo Testing +# $1: Plaintext in hex form +# $2: hash +# return: string formatted as expected by CAVS +sub hash_mct($$) { + my $pt = shift; + my $cipher = shift; + + my $out = ""; + + $out .= "Seed = $pt\n\n"; + + for (my $j=0; $j<100; ++$j) { + $out .= "COUNT = $j\n"; + my $md0=$pt; + my $md1=$pt; + my $md2=$pt; + for (my $i=0; $i<1000; ++$i) { + #print STDERR "outer loop $j; inner loop $i\n"; + my $mi= $md0 . $md1 . $md2; + $md0=$md1; + $md1=$md2; + $md2 = &$hash($mi, $cipher); + $md2 =~ s/\n//; + } + $out .= "MD = $md2\n\n"; + $pt=$md2; + } + + return $out; +} + +# RSA SigGen test +# $1: Message to be signed in hex form +# $2: Hash algorithm +# $3: file name with RSA key in PEM form +# return: string formatted as expected by CAVS +sub rsa_siggen($$$) { + my $data = shift; + my $cipher = shift; + my $keyfile = shift; + + my $out = ""; + + $out .= "SHAAlg = $cipher\n"; + $out .= "Msg = $data\n"; + $out .= "S = " . &$rsa_sign($data, lc($cipher), $keyfile) . "\n"; + + return $out; +} + +# RSA SigVer test +# $1: Message to be verified in hex form +# $2: Hash algoritm +# $3: Signature of message in hex form +# $4: n of the RSA key in hex in hex form +# $5: e of the RSA key in hex in hex form +# return: string formatted as expected by CAVS +sub rsa_sigver($$$$$) { + my $data = shift; + my $cipher = shift; + my $signature = shift; + my $n = shift; + my $e = shift; + + my $out = ""; + + $out .= "SHAAlg = $cipher\n"; + $out .= "e = $e\n"; + $out .= "Msg = $data\n"; + $out .= "S = $signature\n"; + + # 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 + my $keyfile = "rsa_sigver.tmp.$$"; + gen_pubrsakey($keyfile, $n, $e); + + my $sigfile = "$keyfile.sig"; + open(FH, ">$sigfile") or die "Cannot create file $sigfile: $?"; + print FH hex2bin($signature); + close FH; + + $out .= "Result = " . (&$rsa_verify($data, lc($cipher), $keyfile, $sigfile) ? "P\n" : "F\n"); + + unlink($keyfile); + unlink($sigfile); + + return $out; +} + +# RSA X9.31 key generation test +# $1 modulus size +# $2 e +# $3 xp1 +# $4 xp2 +# $5 Xp +# $6 xq1 +# $7 xq2 +# $8 Xq +# return: string formatted as expected by CAVS +sub rsa_keygen($$$$$$$$) { + my $modulus = shift; + my $e = shift; + my $xp1 = shift; + my $xp2 = shift; + my $Xp = shift; + my $xq1 = shift; + my $xq2 = shift; + my $Xq = shift; + + my $out = ""; + + my $ret = &$rsa_derive($modulus, $e, $xp1, $xp2, $Xp, $xq1, $xq2, $Xq); + + my ($P, $Q, $N, $D) = split(/\n/, $ret); + + $out .= "e = $e\n"; + $out .= "xp1 = $xp1\n"; + $out .= "xp2 = $xp2\n"; + $out .= "Xp = $Xp\n"; + $out .= "p = $P\n"; + $out .= "xq1 = $xq1\n"; + $out .= "xq2 = $xq2\n"; + $out .= "Xq = $Xq\n"; + $out .= "q = $Q\n"; + $out .= "n = $N\n"; + $out .= "d = $D\n\n"; + + return $out; + +} + +# X9.31 RNG test +# $1 key for the AES cipher +# $2 DT value +# $3 V value +# $4 type ("VST", "MCT") +# return: string formatted as expected by CAVS +sub rngx931($$$$) { + my $key=shift; + my $dt=shift; + my $v=shift; + my $type=shift; + + my $out = "Key = $key\n"; + $out .= "DT = $dt\n"; + $out .= "V = $v\n"; + + my $count = 1; + $count = 10000 if ($type eq "MCT"); + + my $rnd_val = ""; + + # we read 16 bytes from RNG + my $bufsize = 16; + + my ($CO, $CI); + my $rng_imp = &$state_rng($key, $dt, $v); + my $pid = open2($CO, $CI, $rng_imp); + for (my $i = 0; $i < $count; ++$i) { + my $len = sysread $CO, $rnd_val, $bufsize; + #print STDERR "len=$len, bufsize=$bufsize\n"; + die "len=$len != bufsize=$bufsize" if $len ne $bufsize; + #print STDERR "calc_data=", bin2hex($rnd_val), "\n"; + } + close $CO; + close $CI; + waitpid $pid, 0; + + $out .= "R = " . bin2hex($rnd_val) . "\n\n"; + + return $out; +} + +sub drbg_kat($$$$$$$$$) { + my $cipher = shift; + my $drbg_expectedlen = shift; + my $drbg_entropy = shift; + my $drbg_nonce = shift; + my $drbg_pers = shift; + my $drbg_addtla = shift; + my $drbg_addtlb = shift; + my $drbg_entpra = shift; + my $drbg_entprb = shift; + my $out = ""; + + my $ret = &$drbg($cipher, $drbg_expectedlen, $drbg_entropy, + $drbg_nonce, $drbg_pers, $drbg_addtla, + $drbg_addtlb, $drbg_entpra, $drbg_entprb); + $out = "ReturnedBits = " . $ret . "\n"; + return $out; +} + +# DSA PQGen test +# $1 modulus size +# $2 q size +# $3 number of rounds to perform the test +# return: string formatted as expected by CAVS +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, $qsize, ""); + my ($P, $Q, $G, $Seed, $c, $H) = split(/\n/, $ret); + 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 + $c = hex($c); + + $out .= "P = $P\n"; + $out .= "Q = $Q\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; +} + +# 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 ($P eq $p && $Q eq $q && $seed eq lc $seed2 && $c eq $c2) { + $out .= "Result = P\n\n"; + } + else { + $out .= "Result = F\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 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 +# $2: file name with DSA key in PEM form +# return: string formatted as expected by CAVS +sub dsa_siggen($$) { + my $data = shift; + my $keyfile = shift; + + my $out = ""; + + my %ret = &$dsa_sign($data, $keyfile); + + $out .= "Msg = $data\n"; + $out .= "Y = " . $ret{'Y'} . "\n"; + $out .= "R = " . $ret{'R'} . "\n"; + $out .= "S = " . $ret{'S'} . "\n"; + + return $out; +} + + +# DSA signature verification +# $1 modulus +# $2 P +# $3 Q +# $4 G +# $5 Y - public key +# $6 r +# $7 s +# $8 message to be verified +# return: string formatted as expected by CAVS +sub dsa_sigver($$$$$$$$) { + my $modulus = shift; + my $p = shift; + my $q = shift; + my $g = shift; + my $y = shift; + my $r = shift; + my $s = shift; + my $msg = shift; + + my $out = ""; + + #PQG are already printed - do not print them here + + $out .= "Msg = $msg\n"; + $out .= "Y = $y\n"; + $out .= "R = $r\n"; + $out .= "S = $s\n"; + + # 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 + my $keyfile = "dsa_sigver.tmp.$$"; + &$dsa_genpubkey($keyfile, $p, $q, $g, $y); + + $out .= "Result = " . (&$dsa_verify($msg, $keyfile, $r, $s) ? "P\n" : "F\n"); + + unlink($keyfile); + + return $out; +} + +############################################################## +# Parser of input file and generator of result file +# + +sub usage() { + + print STDERR "Usage: +$0 [-R] [-D] [-I name] + +-R execution of ARCFOUR instead of OpenSSL +-I NAME Use interface style NAME: + openssl OpenSSL (default) + libgcrypt Libgcrypt + cryptoapi Kernel +-D SigGen and SigVer are executed with DSA + Please note that the DSA CAVS vectors do not allow distinguishing + them from the RSA vectors. As the RSA test is the default, you have + to supply this option to apply the DSA logic"; +} + +# Parser of CAVS test vector file +# $1: Test vector file +# $2: Output file for test results +# return: nothing +sub parse($$) { + my $infile = shift; + my $outfile = shift; + + my $out = ""; + + # this is my cipher/hash type + my $cipher = ""; + + # Test type + # 1 - cipher known answer test + # 2 - cipher Monte Carlo test + # 3 - hash known answer test + # 4 - hash Monte Carlo test + # 5 - RSA signature generation + # 6 - RSA signature verification + my $tt = 0; + + # Variables for tests + my $keytype = ""; # we can have "KEY", "KEYs", "KEY1" + my $key1 = ""; + my $key2 = undef; #undef needed for allowing + my $key3 = undef; #the use of them as input variables + my $pt = ""; + my $enc = 1; + my $iv = ""; + my $len = undef; #see key2|3 + my $n = ""; + my $e = ""; + my $signature = ""; + my $rsa_keyfile = ""; + my $dsa_keyfile = ""; + my $dt = ""; + my $v = ""; + 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 $xp1 = ""; + my $xp2 = ""; + my $Xp = ""; + my $xq1 = ""; + my $xq2 = ""; + my $Xq = ""; + my $drbg_expectedlen = ""; + my $drbg_entropy = ""; + my $drbg_nonce = ""; + my $drbg_pers = ""; + my $drbg_addtla = ""; + my $drbg_addtlb = ""; + my $drbg_entpra = ""; + my $drbg_entprb = ""; + + my $mode = ""; + + open(IN, "<$infile"); + while() { + + my $line = $_; + chomp($line); + $line =~ s/\r//; + + my $keylen = ""; + + # Mode and type check + # consider the following parsed line + # '# AESVS MCT test data for CBC' + # '# TDES Multi block Message Test for CBC' + # '# INVERSE PERMUTATION - KAT for CBC' + # '# SUBSTITUTION TABLE - KAT for CBC' + # '# TDES Monte Carlo (Modes) Test for CBC' + # '# "SHA-1 Monte" information for "IBMRHEL5"' + # '# "SigVer PKCS#1 Ver 1.5" information for "IBMRHEL5"' + # '# "SigGen PKCS#1 Ver 1.5" information for "IBMRHEL5"' + # '#RC4VS MCT test data' + + # avoid false positives from user specified 'for "PRODUCT"' strings + my $tmpline = $line; + $tmpline =~ s/ for ".*"//; + + ##### 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|KeyPair|PQGVer|DRBG)/) { + if ($tmpline =~ /CBC/) { $mode="cbc"; } + elsif ($tmpline =~ /ECB/) { $mode="ecb"; } + elsif ($tmpline =~ /OFB/) { $mode="ofb"; } + elsif ($tmpline =~ /CFB/) { $mode="cfb"; } + #we do not need mode as the cipher is already clear + elsif ($tmpline =~ /SHA-1/) { $cipher="sha1"; } + elsif ($tmpline =~ /SHA-224/) { $cipher="sha224"; } + elsif ($tmpline =~ /SHA-256/) { $cipher="sha256"; } + elsif ($tmpline =~ /SHA-384/) { $cipher="sha384"; } + elsif ($tmpline =~ /SHA-512/) { $cipher="sha512"; } + #we do not need mode as the cipher is already clear + elsif ($tmpline =~ /RC4VS/) { $cipher="rc4"; } + elsif ($tmpline =~ /SigGen|SigVer/) { + die "Error: X9.31 is not supported" + if ($tmpline =~ /X9/); + $cipher="sha1"; #place holder - might be overwritten later + } + + if ($tmpline =~ /^#.*AESVS/) { + # AES cipher (part of it) + $cipher="aes"; + } + if ($tmpline =~ /^#.*(TDES|KAT)/) { + # TDES cipher (full definition) + # the FIPS-140 test generator tool does not produce + # machine readable output! + if ($mode eq "cbc") { $cipher="des-ede3-cbc"; } + if ($mode eq "ecb") { $cipher="des-ede3"; } + if ($mode eq "ofb") { $cipher="des-ede3-ofb"; } + if ($mode eq "cfb") { $cipher="des-ede3-cfb"; } + } + + # check for RNG + if ($tmpline =~ /ANSI X9\.31/) { + # change the tmpline to add the type of the + # test which is ONLY visible from the file + # name :-( + if ($infile =~ /MCT\.req/) { + $tmpline .= " MCT"; + } elsif ($infile =~ /VST\.req/) { + $tmpline .= " VST"; + } else { + die "Unexpected cipher type with $infile"; + } + } + + if ($tt == 0) { + ##### Identify the test type + if ($tmpline =~ /DRBG/) { + $tt = 18; + die "Interface function for SP800-90A DRBG testing not defined for tested library" + if (!defined($drbg)); + } 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)); + } elsif ($tmpline =~ /SigVer/ && $opt{'D'} ) { + $tt = 12; + die "Interface function dsa_verify or dsa_genpubkey for DSA verification not defined for tested library" + if (!defined($dsa_verify) || !defined($dsa_genpubkey)); + } 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_dsakey)); + } elsif ($tmpline =~ /PQGGen/) { + $tt = 10; + die "Interface function for DSA PQGGen testing not defined for tested library" + 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" + if (!defined($hmac)); + } elsif ($tmpline =~ /ANSI X9\.31/ && $tmpline =~ /MCT/) { + $tt = 8; + die "Interface function state_rng for RNG MCT not defined for tested library" + if (!defined($state_rng)); + } elsif ($tmpline =~ /ANSI X9\.31/ && $tmpline =~ /VST/) { + $tt = 7; + die "Interface function state_rng for RNG KAT not defined for tested library" + if (!defined($state_rng)); + } elsif ($tmpline =~ /SigVer/ ) { + $tt = 6; + die "Interface function rsa_verify or gen_rsakey for RSA verification not defined for tested library" + if (!defined($rsa_verify) || !defined($gen_rsakey)); + } elsif ($tmpline =~ /SigGen/ ) { + $tt = 5; + die "Interface function rsa_sign or gen_rsakey for RSA sign not defined for tested library" + if (!defined($rsa_sign) || !defined($gen_rsakey)); + } elsif ($tmpline =~ /Monte|MCT|Carlo/ && $cipher =~ /^sha/) { + $tt = 4; + die "Interface function hash for Hashing not defined for tested library" + if (!defined($hash)); + } 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)); + } elsif ($cipher =~ /^sha/) { + $tt = 3; + die "Interface function hash for Hashing not defined for tested library" + if (!defined($hash)); + } else { + $tt = 1; + die "Interface function encdec for Encryption/Decryption not defined for tested library" + if (!defined($encdec)); + } + } + } + + # This is needed as ARCFOUR does not operate with an IV + $iv = "00000000000000000000000000000000" if ($cipher eq "rc4" + && $iv eq "" ); + + # we are now looking for the string + # '# Key Length : 256' + # found in AES + if ($tmpline =~ /^# Key Length.*?(128|192|256)/) { + if ($cipher eq "aes") { + $cipher="$cipher-$1-$mode"; + } else { + die "Error: Key length $1 given for cipher $cipher which is unexpected"; + } + } + + # Get the test data + if ($line =~ /^(KEY|KEY1|Key)\s*=\s*(.*)/) { # found in ciphers and RNG + die "KEY seen twice - input file crap" if ($key1 ne ""); + $keytype=$1; + $key1=$2; + $key1 =~ s/\s//g; #replace potential white spaces + } + elsif ($line =~ /^(KEYs)\s*=\s*(.*)/) { # found in ciphers and RNG + die "KEY seen twice - input file crap" if ($key1 ne ""); + $keytype=$1; + $key1=$2; + $key1 =~ s/\s//g; #replace potential white spaces + $key2 = $key1; + $key3 = $key1; + } + elsif ($line =~ /^KEY2\s*=\s*(.*)/) { # found in TDES + die "First key not set, but got already second key - input file crap" if ($key1 eq ""); + die "KEY2 seen twice - input file crap" if (defined($key2)); + $key2=$1; + $key2 =~ s/\s//g; #replace potential white spaces + } + elsif ($line =~ /^KEY3\s*=\s*(.*)/) { # found in TDES + die "Second key not set, but got already third key - input file crap" if ($key2 eq ""); + die "KEY3 seen twice - input file crap" if (defined($key3)); + $key3=$1; + $key3 =~ s/\s//g; #replace potential white spaces + } + elsif ($line =~ /^IV\s*=\s*(.*)/) { # found in ciphers + die "IV seen twice - input file crap" if ($iv ne ""); + $iv=$1; + $iv =~ s/\s//g; #replace potential white spaces + } + elsif ($line =~ /^PLAINTEXT\s*=\s*(.*)/) { # found in ciphers + if ( $1 !~ /\?/ ) { #only use it if there is valid hex data + die "PLAINTEXT/CIPHERTEXT seen twice - input file crap" if ($pt ne ""); + $pt=$1; + $pt =~ s/\s//g; #replace potential white spaces + $enc=1; + } + } + elsif ($line =~ /^CIPHERTEXT\s*=\s*(.*)/) { # found in ciphers + if ( $1 !~ /\?/ ) { #only use it if there is valid hex data + die "PLAINTEXT/CIPHERTEXT seen twice - input file crap" if ($pt ne ""); + $pt=$1; + $pt =~ s/\s//g; #replace potential white spaces + $enc=0; + } + } + elsif ($line =~ /^Len\s*=\s*(.*)/) { # found in hashs + $len=$1; + } + elsif ($line =~ /^(Msg|Seed)\s*=\s*(.*)/) { # found in hashs + die "Msg/Seed seen twice - input file crap" if ($pt ne ""); + $pt=$2; + } + 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($modulus, $qsize, $dsa_keyfile); + $out .= "P = " . $pqg{'P'} . "\n"; + $out .= "Q = " . $pqg{'Q'} . "\n"; + $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 + $rsa_keyfile = "rsa_siggen.tmp.$$"; + &$gen_rsakey($modulus, $rsa_keyfile); + my $modulus = pipe_through_program("", "openssl rsa -pubout -modulus -in $rsa_keyfile"); + $modulus =~ s/Modulus=(.*?)\s(.|\s)*/$1/; + $out .= "n = $modulus\n"; + $out .= "\ne = 10001\n" + } + } + elsif ($line =~ /^SHAAlg\s*=\s*(.*)/) { #found in RSA requests + $cipher=$1; + } + elsif($line =~ /^n\s*=\s*(.*)/) { # found in RSA requests + $out .= $line . "\n"; + $n=$1; + } + elsif ($line =~ /^e\s*=\s*(.*)/) { # found in RSA requests + $e=$1; + } + elsif ($line =~ /^S\s*=\s*(.*)/) { # found in RSA requests + die "S seen twice - input file crap" if ($signature ne ""); + $signature=$1; + } + elsif ($line =~ /^DT\s*=\s*(.*)/) { # X9.31 RNG requests + die "DT seen twice - check input file" + if ($dt ne ""); + $dt=$1; + } + elsif ($line =~ /^V\s*=\s*(.*)/) { # X9.31 RNG requests + die "V seen twice - check input file" + if ($v ne ""); + $v=$1; + } + elsif ($line =~ /^Klen\s*=\s*(.*)/) { # HMAC requests + die "Klen seen twice - check input file" + if ($klen ne ""); + $klen=$1; + } + elsif ($line =~ /^Tlen\s*=\s*(.*)/) { # HMAC RNG requests + die "Tlen seen twice - check input file" + if ($tlen ne ""); + $tlen=$1; + } + 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); + $capital_p = $1; + $out .= $line . "\n"; # print it + } + elsif ($line =~ /^Q\s*=\s*(.*)/) { #DSA SigVer + die "Q seen twice - check input file" + if ($capital_q); + $capital_q = $1; + $out .= $line . "\n"; # print it + } + elsif ($line =~ /^G\s*=\s*(.*)/) { #DSA SigVer + die "G seen twice - check input file" + if ($capital_g); + $capital_g = $1; + $out .= $line . "\n"; # print it + } + elsif ($line =~ /^Y\s*=\s*(.*)/) { #DSA SigVer + die "Y seen twice - check input file" + if ($capital_y); + $capital_y = $1; + } + elsif ($line =~ /^R\s*=\s*(.*)/) { #DSA SigVer + die "R seen twice - check input file" + 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); + $xp1 = $1; + } + elsif ($line =~ /^xp2\s*=\s*(.*)/) { #RSA key gen + die "xp2 seen twice - check input file" + if ($xp2); + $xp2 = $1; + } + elsif ($line =~ /^Xp\s*=\s*(.*)/) { #RSA key gen + die "Xp seen twice - check input file" + if ($Xp); + $Xp = $1; + } + elsif ($line =~ /^xq1\s*=\s*(.*)/) { #RSA key gen + die "xq1 seen twice - check input file" + if ($xq1); + $xq1 = $1; + } + elsif ($line =~ /^xq2\s*=\s*(.*)/) { #RSA key gen + die "xq2 seen twice - check input file" + if ($xq2); + $xq2 = $1; + } + elsif ($line =~ /^Xq\s*=\s*(.*)/) { #RSA key gen + die "Xq seen twice - check input file" + if ($Xq); + $Xq = $1; + } + # DRBG types + elsif ($line =~ /^\[SHA-1\]/) { $cipher="sha1"; $out .= $line . "\n";} + elsif ($line =~ /^\[SHA-224\]/) { $cipher="sha224"; $out .= $line . "\n";} + elsif ($line =~ /^\[SHA-256\]/) { $cipher="sha256"; $out .= $line . "\n";} + elsif ($line =~ /^\[SHA-384\]/) { $cipher="sha384"; $out .= $line . "\n";} + elsif ($line =~ /^\[SHA-512\]/) { $cipher="sha512"; $out .= $line . "\n";} + elsif ($line =~ /^\[AES-128/) { $cipher="aes128"; $out .= $line . "\n";} + elsif ($line =~ /^\[AES-192/) { $cipher="aes192"; $out .= $line . "\n";} + elsif ($line =~ /^\[AES-256/) { $cipher="aes256"; $out .= $line . "\n";} + elsif ($line =~ /^\[ReturnedBitsLen\s*=\s*(.*)]/) { $drbg_expectedlen = $1; $out .= $line . "\n";} + elsif ($line =~ /^EntropyInput\s*=\s*(.*)/) { $drbg_entropy=$1; $out .= $line . "\n";} + elsif ($line =~ /^Nonce\s*=\s*(.*)/) { $drbg_nonce=$1; $out .= $line . "\n";} + elsif ($line =~ /^PersonalizationString\s*=\s*(.*)/) { + $drbg_pers=$1; + if ($drbg_pers eq "") { + $drbg_pers = "z"; + } + $out .= $line . "\n"; + } + elsif ($line =~ /^AdditionalInput\s*=\s*(.*)/) { + if ($drbg_addtla eq "") { + $drbg_addtla=$1; + if ($drbg_addtla eq "") { + $drbg_addtla = "z"; + } + } else { + $drbg_addtlb=$1; + if ($drbg_addtlb eq "") { + $drbg_addtlb = "z"; + } + } + $out .= $line . "\n"; + } + elsif ($line =~ /^EntropyInputPR\s*=\s*(.*)/) { + if ($drbg_entpra eq "") { + $drbg_entpra=$1; + if ($drbg_entpra eq "") { + $drbg_entpra = "z"; + } + } else { + $drbg_entprb=$1; + if ($drbg_entprb eq "") { + $drbg_entprb = "z"; + } + } + $out .= $line . "\n"; + } + else { + $out .= $line . "\n"; + } + + # call tests if all input data is there + if ($tt == 1) { + if ($key1 ne "" && $pt ne "" && $cipher ne "") { + $out .= kat($keytype, $key1, $key2, $key3, $iv, $pt, $cipher, $enc); + $keytype = ""; + $key1 = ""; + $key2 = undef; + $key3 = undef; + $iv = ""; + $pt = ""; + } + } + elsif ($tt == 2) { + if ($key1 ne "" && $pt ne "" && $cipher ne "") { + $out .= crypto_mct($keytype, $key1, $key2, $key3, $iv, $pt, $cipher, $enc); + $keytype = ""; + $key1 = ""; + $key2 = undef; + $key3 = undef; + $iv = ""; + $pt = ""; + } + } + elsif ($tt == 3) { + if ($pt ne "" && $cipher ne "") { + $out .= hash_kat($pt, $cipher, $len); + $pt = ""; + $len = undef; + } + } + elsif ($tt == 4) { + if ($pt ne "" && $cipher ne "") { + $out .= hash_mct($pt, $cipher); + $pt = ""; + } + } + elsif ($tt == 5) { + if ($pt ne "" && $cipher ne "" && $rsa_keyfile ne "") { + $out .= rsa_siggen($pt, $cipher, $rsa_keyfile); + $pt = ""; + } + } + elsif ($tt == 6) { + if ($pt ne "" && $cipher ne "" && $signature ne "" && $n ne "" && $e ne "") { + $out .= rsa_sigver($pt, $cipher, $signature, $n, $e); + $pt = ""; + $signature = ""; + } + } + elsif ($tt == 7 ) { + if ($key1 ne "" && $dt ne "" && $v ne "") { + $out .= rngx931($key1, $dt, $v, "VST"); + $key1 = ""; + $dt = ""; + $v = ""; + } + } + elsif ($tt == 8 ) { + if ($key1 ne "" && $dt ne "" && $v ne "") { + $out .= rngx931($key1, $dt, $v, "MCT"); + $key1 = ""; + $dt = ""; + $v = ""; + } + } + elsif ($tt == 9) { + if ($klen ne "" && $tlen ne "" && $key1 ne "" && $pt ne "") { + $out .= hmac_kat($klen, $tlen, $key1, $pt); + $key1 = ""; + $tlen = ""; + $klen = ""; + $pt = ""; + } + } + elsif ($tt == 10) { + 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 "") { + $out .= dsa_siggen($pt, $dsa_keyfile); + $pt = ""; + } + } + elsif ($tt == 12) { + if ($modulus ne "" && + $capital_p ne "" && + $capital_q ne "" && + $capital_g ne "" && + $capital_y ne "" && + $capital_r ne "" && + $signature ne "" && + $pt ne "") { + $out .= dsa_sigver($modulus, + $capital_p, + $capital_q, + $capital_g, + $capital_y, + $capital_r, + $signature, + $pt); + + # We do not clear the domain values PQG and + # the modulus value as they + # are specified only once in a file + # and we do not need to print them as they + # are already printed above + $capital_y = ""; + $capital_r = ""; + $signature = ""; + $pt = ""; + } + } + elsif ($tt == 13) { + if($modulus ne "" && + $e ne "" && + $xp1 ne "" && + $xp2 ne "" && + $Xp ne "" && + $xq1 ne "" && + $xq2 ne "" && + $Xq ne "") { + $out .= rsa_keygen($modulus, + $e, + $xp1, + $xp2, + $Xp, + $xq1, + $xq2, + $Xq); + $e = ""; + $xp1 = ""; + $xp2 = ""; + $Xp = ""; + $xq1 = ""; + $xq2 = ""; + $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 ($cipher ne "" && + $drbg_expectedlen ne "" && + $drbg_entropy ne "" && + $drbg_nonce ne "" && + $drbg_pers ne "" && + $drbg_addtla ne "" && + $drbg_addtlb ne "") { + if ($drbg_entpra ne "" && $drbg_entprb eq "") { + next; + } + my $tmpcipher = $cipher; + if ($infile =~ /HMAC_DRBG\.req/) { + $tmpcipher = "hmac $tmpcipher"; + } elsif ($infile =~ /Hash_DRBG\.req/) { + $tmpcipher = "hash $tmpcipher"; + } elsif ($infile =~ /CTR_DRBG\.req/) { + $tmpcipher = "ctr $tmpcipher"; + } else { + die "unknown DRBG input file $infile"; + } + $out .= drbg_kat($tmpcipher, $drbg_expectedlen, + $drbg_entropy, $drbg_nonce, + $drbg_pers, $drbg_addtla, + $drbg_addtlb, $drbg_entpra, + $drbg_entprb); + $drbg_entropy = ""; + $drbg_nonce = ""; + $drbg_pers = ""; + $drbg_addtla = ""; + $drbg_addtlb = ""; + $drbg_entpra = ""; + $drbg_entprb = ""; + } + } + elsif ($tt > 0) { + die "Test case $tt not defined"; + } + } + + close IN; + $out =~ s/\n/\r\n/g; # make it a dos file + open(OUT, ">$outfile") or die "Cannot create output file $outfile: $?"; + print OUT $out; + close OUT; + +} + +# Signalhandler +sub cleanup() { + unlink("rsa_siggen.tmp.$$"); + unlink("rsa_sigver.tmp.$$"); + unlink("rsa_sigver.tmp.$$.sig"); + unlink("rsa_sigver.tmp.$$.der"); + unlink("rsa_sigver.tmp.$$.cnf"); + unlink("dsa_siggen.tmp.$$"); + unlink("dsa_sigver.tmp.$$"); + unlink("dsa_sigver.tmp.$$.sig"); + exit; +} + +############################################################ +# +# let us pretend to be C :-) +sub main() { + + usage() unless @ARGV; + + getopts("DRI:", \%opt) or die "bad option"; + + ##### Set library + + if ( ! defined $opt{'I'} || $opt{'I'} eq 'libgcrypt' ) { + print STDERR "Using libgcrypt interface functions\n"; + $encdec = \&libgcrypt_encdec; + $rsa_sign = \&libgcrypt_rsa_sign; + $rsa_verify = \&libgcrypt_rsa_verify; + $gen_rsakey = \&libgcrypt_gen_rsakey; + $rsa_derive = \&libgcrypt_rsa_derive; + $hash = \&libgcrypt_hash; + $state_cipher = \&libgcrypt_state_cipher; + $state_cipher_des = \&libgcrypt_state_cipher_des; + $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; + $drbg = \&libgcrypt_drbg; + } elsif ( $opt{'I'} eq 'openssl' ) { + print STDERR "Using OpenSSL interface functions\n"; + $encdec = \&openssl_encdec; + $rsa_sign = \&openssl_rsa_sign; + $rsa_verify = \&openssl_rsa_verify; + $gen_rsakey = \&openssl_gen_rsakey; + $hash = \&openssl_hash; + $state_cipher = \&openssl_state_cipher; + } elsif ( $opt{'I'} eq 'cryptoapi' ) { + print STDERR "Using cryptoapi interface functions\n"; + $encdec = \&cryptoapi_encdec; + $hash = \&cryptoapi_hash; + $state_cipher = \&cryptoapi_state_cipher; + $hmac = \&cryptoapi_hmac; + $state_rng = \&cryptoapi_state_rng; + $drbg = \&cryptoapi_drbg; + } else { + die "Invalid interface option given"; + } + + my $infile=$ARGV[0]; + die "Error: Test vector file $infile not found" if (! -f $infile); + + my $outfile = $infile; + # let us add .rsp regardless whether we could strip .req + $outfile =~ s/\.req$//; + if ($opt{'R'}) { + $outfile .= ".rc4"; + } else { + $outfile .= ".rsp"; + } + if (-f $outfile) { + die "Output file $outfile could not be removed: $?" + unless unlink($outfile); + } + print STDERR "Performing tests from source file $infile with results stored in destination file $outfile\n"; + + #Signal handler + $SIG{HUP} = \&cleanup; + $SIG{INT} = \&cleanup; + $SIG{QUIT} = \&cleanup; + $SIG{TERM} = \&cleanup; + + # Do the job + parse($infile, $outfile); + + cleanup(); + +} + +########################################### +# Call it +main(); +1; diff --git a/drbg_test.patch b/drbg_test.patch new file mode 100644 index 0000000..943731d --- /dev/null +++ b/drbg_test.patch @@ -0,0 +1,1371 @@ +Index: libgcrypt-1.9.0/tests/drbg_test.c +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.0/tests/drbg_test.c +@@ -0,0 +1,1332 @@ ++/* DRBG test for libgcrypt ++ Copyright (C) 2014 Stephan Mueller ++ ++ Compile: ++ gcc -g -I/home/sm/hacking/sources/libs/include -L/home/sm/hacking/sources/libs/lib -o drbg_test drbg_test.c -lgcrypt -lpthread ++ ++ Execute: ++ LD_LIBRARY_PATH=/home/sm/hacking/sources/libs/lib/ ./drbg_test ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "gcrypt.h" ++ ++/* The following definitions are taken verbatim from random/random-drbg.c. ++ * libgcrypt upstream removed the public apis from gcrypt.h in ++ * http://git.gnupg.org/cgi-bin/gitweb.cgi?p=libgcrypt.git;a=commit;h=fd13372fa9069d3a72947ea59c57e33637c936bf ++ */ ++/****************************************************************** ++ * Constants ++ ******************************************************************/ ++ ++/* ++ * DRBG flags bitmasks ++ * ++ * 31 (B) 28 19 (A) 0 ++ * +-+-+-+--------+---+-----------+-----+ ++ * |~|~|u|~~~~~~~~| 3 | 2 | 1 | ++ * +-+-+-+--------+- -+-----------+-----+ ++ * ctl flg| |drbg use selection flags ++ * ++ */ ++ ++/* Internal state control flags (B) */ ++#define DRBG_PREDICTION_RESIST ((u32)1<<28) ++ ++/* CTR type modifiers (A.1)*/ ++#define DRBG_CTRAES ((u32)1<<0) ++#define DRBG_CTRSERPENT ((u32)1<<1) ++#define DRBG_CTRTWOFISH ((u32)1<<2) ++#define DRBG_CTR_MASK (DRBG_CTRAES | DRBG_CTRSERPENT \ ++ | DRBG_CTRTWOFISH) ++ ++/* HASH type modifiers (A.2)*/ ++#define DRBG_HASHSHA1 ((u32)1<<4) ++#define DRBG_HASHSHA224 ((u32)1<<5) ++#define DRBG_HASHSHA256 ((u32)1<<6) ++#define DRBG_HASHSHA384 ((u32)1<<7) ++#define DRBG_HASHSHA512 ((u32)1<<8) ++#define DRBG_HASH_MASK (DRBG_HASHSHA1 | DRBG_HASHSHA224 \ ++ | DRBG_HASHSHA256 | DRBG_HASHSHA384 \ ++ | DRBG_HASHSHA512) ++/* type modifiers (A.3)*/ ++#define DRBG_HMAC ((u32)1<<12) ++#define DRBG_SYM128 ((u32)1<<13) ++#define DRBG_SYM192 ((u32)1<<14) ++#define DRBG_SYM256 ((u32)1<<15) ++#define DRBG_TYPE_MASK (DRBG_HMAC | DRBG_SYM128 | DRBG_SYM192 \ ++ | DRBG_SYM256) ++#define DRBG_CIPHER_MASK (DRBG_CTR_MASK | DRBG_HASH_MASK \ ++ | DRBG_TYPE_MASK) ++ ++#define DRBG_PR_CTRAES128 (DRBG_PREDICTION_RESIST | DRBG_CTRAES | DRBG_SYM128) ++#define DRBG_PR_CTRAES192 (DRBG_PREDICTION_RESIST | DRBG_CTRAES | DRBG_SYM192) ++#define DRBG_PR_CTRAES256 (DRBG_PREDICTION_RESIST | DRBG_CTRAES | DRBG_SYM256) ++#define DRBG_NOPR_CTRAES128 (DRBG_CTRAES | DRBG_SYM128) ++#define DRBG_NOPR_CTRAES192 (DRBG_CTRAES | DRBG_SYM192) ++#define DRBG_NOPR_CTRAES256 (DRBG_CTRAES | DRBG_SYM256) ++#define DRBG_PR_HASHSHA1 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA1) ++#define DRBG_PR_HASHSHA256 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA256) ++#define DRBG_PR_HASHSHA384 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA384) ++#define DRBG_PR_HASHSHA512 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA512) ++#define DRBG_NOPR_HASHSHA1 (DRBG_HASHSHA1) ++#define DRBG_NOPR_HASHSHA256 (DRBG_HASHSHA256) ++#define DRBG_NOPR_HASHSHA384 (DRBG_HASHSHA384) ++#define DRBG_NOPR_HASHSHA512 (DRBG_HASHSHA512) ++#define DRBG_PR_HMACSHA1 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA1 \ ++ | DRBG_HMAC) ++#define DRBG_PR_HMACSHA256 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA256 \ ++ | DRBG_HMAC) ++#define DRBG_PR_HMACSHA384 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA384 \ ++ | DRBG_HMAC) ++#define DRBG_PR_HMACSHA512 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA512 \ ++ | DRBG_HMAC) ++#define DRBG_NOPR_HMACSHA1 (DRBG_HASHSHA1 | DRBG_HMAC) ++#define DRBG_NOPR_HMACSHA256 (DRBG_HASHSHA256 | DRBG_HMAC) ++#define DRBG_NOPR_HMACSHA384 (DRBG_HASHSHA384 | DRBG_HMAC) ++#define DRBG_NOPR_HMACSHA512 (DRBG_HASHSHA512 | DRBG_HMAC) ++ ++ ++/* The default DRGB type. */ ++#define DRBG_DEFAULT_TYPE DRBG_NOPR_HMACSHA256 ++ ++#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) ++ ++static char hex_char_map_l[] = { '0', '1', '2', '3', '4', '5', '6', '7', ++ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; ++static char hex_char_map_u[] = { '0', '1', '2', '3', '4', '5', '6', '7', ++ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; ++static char hex_char(unsigned int bin, int u) ++{ ++ if (bin < sizeof(hex_char_map_l)) ++ return (u) ? hex_char_map_u[bin] : hex_char_map_l[bin]; ++ return 'X'; ++} ++ ++/* ++ * Convert binary string into hex representation ++ * @bin input buffer with binary data ++ * @binlen length of bin ++ * @hex output buffer to store hex data ++ * @hexlen length of already allocated hex buffer (should be at least ++ * twice binlen -- if not, only a fraction of binlen is converted) ++ * @u case of hex characters (0=>lower case, 1=>upper case) ++ */ ++static void bin2hex(const unsigned char *bin, size_t binlen, ++ char *hex, size_t hexlen, int u) ++{ ++ size_t i = 0; ++ size_t chars = (binlen > (hexlen / 2)) ? (hexlen / 2) : binlen; ++ ++ for (i = 0; i < chars; i++) { ++ hex[(i*2)] = hex_char((bin[i] >> 4), u); ++ hex[((i*2)+1)] = hex_char((bin[i] & 0x0f), u); ++ } ++} ++ ++static int bin_char(unsigned char hex) ++{ ++ if (48 <= hex && 57 >= hex) ++ return (hex - 48); ++ if (65 <= hex && 70 >= hex) ++ return (hex - 55); ++ if (97 <= hex && 102 >= hex) ++ return (hex - 87); ++ return 0; ++} ++/* ++ * Convert hex representation into binary string ++ * @hex input buffer with hex representation ++ * @hexlen length of hex ++ * @bin output buffer with binary data ++ * @binlen length of already allocated bin buffer (should be at least ++ * half of hexlen -- if not, only a fraction of hexlen is converted) ++ */ ++static void hex2bin(const unsigned char *hex, size_t hexlen, ++ unsigned char *bin, size_t binlen) ++{ ++ size_t i = 0; ++ size_t chars = (binlen > (hexlen / 2)) ? (hexlen / 2) : binlen; ++ ++ for (i = 0; i < chars; i++) { ++ bin[i] = bin_char(hex[(i*2)]) << 4; ++ bin[i] |= bin_char(hex[((i*2)+1)]); ++ } ++} ++ ++/* Print a error message and exit the process with an error code. */ ++static void ++die (const char *format, ...) ++{ ++ va_list arg_ptr; ++ ++ va_start (arg_ptr, format); ++ vfprintf (stderr, format, arg_ptr); ++ va_end (arg_ptr); ++ exit (1); ++} ++ ++ ++struct gcry_drbg_test_vector ++{ ++ u_int32_t flags; /* flags selecting the DRBG type */ ++ unsigned char *entropy; /* entropy string for initialization -- this ++ * string is a concatenation of the entropy ++ * and nonce variable from CAVS */ ++ size_t entropylen; /* length of entropy and nonce variable */ ++ unsigned char *entpra; /* for prediction resistance: entropy for ++ * first reseeding */ ++ unsigned char *entprb; /* for prediction resistance: entropy for ++ * second reseeding */ ++ size_t entprlen; /* length of prediction resistance entropy */ ++ unsigned char *addtla; /* additional input string for first random ++ * value */ ++ unsigned char *addtlb; /* additional input string for second random ++ * value */ ++ size_t addtllen; /* length of additional input string */ ++ unsigned char *pers; /* personalization string */ ++ size_t perslen; /* personalization string length */ ++ unsigned char *expected; /* expected random value -- for CAVS test, ++ this value does not apply and the memcmp ++ in drbg_cavs_test does not apply either*/ ++ size_t expectedlen; /* length of expected random value */ ++}; ++ ++struct gcry_drbg_test_vector drbg_test_pr[] = { ++ { ++ .flags = (DRBG_PR_HASHSHA256), ++ .entropy = (unsigned char *) ++ "\x72\x88\x4c\xcd\x6c\x85\x57\x70\xf7\x0b\x8b\x86" ++ "\xc1\xeb\xd2\x4e\x36\x14\xab\x18\xc4\x9c\xc9\xcf" ++ "\x1a\xe8\xf7\x7b\x02\x49\x73\xd7\xf1\x42\x7d\xc6" ++ "\x3f\x29\x2d\xec\xd3\x66\x51\x3f\x1d\x8d\x5b\x4e", ++ .entropylen = 48, ++ .entpra = (unsigned char *) ++ "\x38\x9c\x91\xfa\xc2\xa3\x46\x89\x56\x08\x3f\x62" ++ "\x73\xd5\x22\xa9\x29\x63\x3a\x1d\xe5\x5d\x5e\x4f" ++ "\x67\xb0\x67\x7a\x5e\x9e\x0c\x62", ++ .entprb = (unsigned char *) ++ "\xb2\x8f\x36\xb2\xf6\x8d\x39\x13\xfa\x6c\x66\xcf" ++ "\x62\x8a\x7e\x8c\x12\x33\x71\x9c\x69\xe4\xa5\xf0" ++ "\x8c\xee\xeb\x9c\xf5\x31\x98\x31", ++ .entprlen = 32, ++ .expected = (unsigned char *) ++ "\x52\x7b\xa3\xad\x71\x77\xa4\x49\x42\x04\x61\xc7" ++ "\xf0\xaf\xa5\xfd\xd3\xb3\x0d\x6a\x61\xba\x35\x49" ++ "\xbb\xaa\xaf\xe4\x25\x7d\xb5\x48\xaf\x5c\x18\x3d" ++ "\x33\x8d\x9d\x45\xdf\x98\xd5\x94\xa8\xda\x92\xfe" ++ "\xc4\x3c\x94\x2a\xcf\x7f\x7b\xf2\xeb\x28\xa9\xf1" ++ "\xe0\x86\x30\xa8\xfe\xf2\x48\x90\x91\x0c\x75\xb5" ++ "\x3c\x00\xf0\x4d\x09\x4f\x40\xa7\xa2\x8c\x52\xdf" ++ "\x52\xef\x17\xbf\x3d\xd1\xa2\x31\xb4\xb8\xdc\xe6" ++ "\x5b\x0d\x1f\x78\x36\xb4\xe6\x4b\xa7\x11\x25\xd5" ++ "\x94\xc6\x97\x36\xab\xf0\xe5\x31\x28\x6a\xbb\xce" ++ "\x30\x81\xa6\x8f\x27\x14\xf8\x1c", ++ .expectedlen = 128, ++ .addtla = NULL, ++ .addtlb = NULL, ++ .addtllen = 0, ++ .pers = NULL, ++ .perslen = 0, ++ }, ++ { ++ .flags = (DRBG_PR_HASHSHA256), ++ .entropy = (unsigned char *) ++ "\x5d\xf2\x14\xbc\xf6\xb5\x4e\x0b\xf0\x0d\x6f\x2d" ++ "\xe2\x01\x66\x7b\xd0\xa4\x73\xa4\x21\xdd\xb0\xc0" ++ "\x51\x79\x09\xf4\xea\xa9\x08\xfa\xa6\x67\xe0\xe1" ++ "\xd1\x88\xa8\xad\xee\x69\x74\xb3\x55\x06\x9b\xf6", ++ .entropylen = 48, ++ .entpra = (unsigned char *) ++ "\xef\x48\x06\xa2\xc2\x45\xf1\x44\xfa\x34\x2c\xeb" ++ "\x8d\x78\x3c\x09\x8f\x34\x72\x20\xf2\xe7\xfd\x13" ++ "\x76\x0a\xf6\xdc\x3c\xf5\xc0\x15", ++ .entprb = (unsigned char *) ++ "\x4b\xbe\xe5\x24\xed\x6a\x2d\x0c\xdb\x73\x5e\x09" ++ "\xf9\xad\x67\x7c\x51\x47\x8b\x6b\x30\x2a\xc6\xde" ++ "\x76\xaa\x55\x04\x8b\x0a\x72\x95", ++ .entprlen = 32, ++ .expected = (unsigned char *) ++ "\x3b\x14\x71\x99\xa1\xda\xa0\x42\xe6\xc8\x85\x32" ++ "\x70\x20\x32\x53\x9a\xbe\xd1\x1e\x15\xef\xfb\x4c" ++ "\x25\x6e\x19\x3a\xf0\xb9\xcb\xde\xf0\x3b\xc6\x18" ++ "\x4d\x85\x5a\x9b\xf1\xe3\xc2\x23\x03\x93\x08\xdb" ++ "\xa7\x07\x4b\x33\x78\x40\x4d\xeb\x24\xf5\x6e\x81" ++ "\x4a\x1b\x6e\xa3\x94\x52\x43\xb0\xaf\x2e\x21\xf4" ++ "\x42\x46\x8e\x90\xed\x34\x21\x75\xea\xda\x67\xb6" ++ "\xe4\xf6\xff\xc6\x31\x6c\x9a\x5a\xdb\xb3\x97\x13" ++ "\x09\xd3\x20\x98\x33\x2d\x6d\xd7\xb5\x6a\xa8\xa9" ++ "\x9a\x5b\xd6\x87\x52\xa1\x89\x2b\x4b\x9c\x64\x60" ++ "\x50\x47\xa3\x63\x81\x16\xaf\x19", ++ .expectedlen = 128, ++ .addtla = (unsigned char *) ++ "\xbe\x13\xdb\x2a\xe9\xa8\xfe\x09\x97\xe1\xce\x5d" ++ "\xe8\xbb\xc0\x7c\x4f\xcb\x62\x19\x3f\x0f\xd2\xad" ++ "\xa9\xd0\x1d\x59\x02\xc4\xff\x70", ++ .addtlb = (unsigned char *) ++ "\x6f\x96\x13\xe2\xa7\xf5\x6c\xfe\xdf\x66\xe3\x31" ++ "\x63\x76\xbf\x20\x27\x06\x49\xf1\xf3\x01\x77\x41" ++ "\x9f\xeb\xe4\x38\xfe\x67\x00\xcd", ++ .addtllen = 32, ++ .pers = NULL, ++ .perslen = 0, ++ }, ++ { ++ .flags = (DRBG_PR_HASHSHA256), ++ .entropy = (unsigned char *) ++ "\xc6\x1c\xaf\x83\xa2\x56\x38\xf9\xb0\xbc\xd9\x85" ++ "\xf5\x2e\xc4\x46\x9c\xe1\xb9\x40\x98\x70\x10\x72" ++ "\xd7\x7d\x15\x85\xa1\x83\x5a\x97\xdf\xc8\xa8\xe8" ++ "\x03\x4c\xcb\x70\x35\x8b\x90\x94\x46\x8a\x6e\xa1", ++ .entropylen = 48, ++ .entpra = (unsigned char *) ++ "\xc9\x05\xa4\xcf\x28\x80\x4b\x93\x0f\x8b\xc6\xf9" ++ "\x09\x41\x58\x74\xe9\xec\x28\xc7\x53\x0a\x73\x60" ++ "\xba\x0a\xde\x57\x5b\x4b\x9f\x29", ++ .entprb = (unsigned char *) ++ "\x4f\x31\xd2\xeb\xac\xfa\xa8\xe2\x01\x7d\xf3\xbd" ++ "\x42\xbd\x20\xa0\x30\x65\x74\xd5\x5d\xd2\xad\xa4" ++ "\xa9\xeb\x1f\x4d\xf6\xfd\xb8\x26", ++ .entprlen = 32, ++ .expected = (unsigned char *) ++ "\xf6\x13\x05\xcb\x83\x60\x16\x42\x49\x1d\xc6\x25" ++ "\x3b\x8c\x31\xa3\xbe\x8b\xbd\x1c\xe2\xec\x1d\xde" ++ "\xbb\xbf\xa1\xac\xa8\x9f\x50\xce\x69\xce\xef\xd5" ++ "\xd6\xf2\xef\x6a\xf7\x81\x38\xdf\xbc\xa7\x5a\xb9" ++ "\xb2\x42\x65\xab\xe4\x86\x8d\x2d\x9d\x59\x99\x2c" ++ "\x5a\x0d\x71\x55\x98\xa4\x45\xc2\x8d\xdb\x05\x5e" ++ "\x50\x21\xf7\xcd\xe8\x98\x43\xce\x57\x74\x63\x4c" ++ "\xf3\xb1\xa5\x14\x1e\x9e\x01\xeb\x54\xd9\x56\xae" ++ "\xbd\xb6\x6f\x1a\x47\x6b\x3b\x44\xe4\xa2\xe9\x3c" ++ "\x6c\x83\x12\x30\xb8\x78\x7f\x8e\x54\x82\xd4\xfe" ++ "\x90\x35\x0d\x4c\x4d\x85\xe7\x13", ++ .expectedlen = 128, ++ .addtla = NULL, ++ .addtlb = NULL, ++ .addtllen = 0, ++ .pers = (unsigned char *) ++ "\xa5\xbf\xac\x4f\x71\xa1\xbb\x67\x94\xc6\x50\xc7" ++ "\x2a\x45\x9e\x10\xa8\xed\xf7\x52\x4f\xfe\x21\x90" ++ "\xa4\x1b\xe1\xe2\x53\xcc\x61\x47", ++ .perslen = 32, ++ }, ++ { ++ .flags = (DRBG_PR_HASHSHA256), ++ .entropy = (unsigned char *) ++ "\xb6\xc1\x8d\xdf\x99\x54\xbe\x95\x10\x48\xd9\xf6" ++ "\xd7\x48\xa8\x73\x2d\x74\xde\x1e\xde\x57\x7e\xf4" ++ "\x7b\x7b\x64\xef\x88\x7a\xa8\x10\x4b\xe1\xc1\x87" ++ "\xbb\x0b\xe1\x39\x39\x50\xaf\x68\x9c\xa2\xbf\x5e", ++ .entropylen = 48, ++ .entpra = (unsigned char *) ++ "\xdc\x81\x0a\x01\x58\xa7\x2e\xce\xee\x48\x8c\x7c" ++ "\x77\x9e\x3c\xf1\x17\x24\x7a\xbb\xab\x9f\xca\x12" ++ "\x19\xaf\x97\x2d\x5f\xf9\xff\xfc", ++ .entprb = (unsigned char *) ++ "\xaf\xfc\x4f\x98\x8b\x93\x95\xc1\xb5\x8b\x7f\x73" ++ "\x6d\xa6\xbe\x6d\x33\xeb\x2c\x82\xb1\xaf\xc1\xb6" ++ "\xb6\x05\xe2\x44\xaa\xfd\xe7\xdb", ++ .entprlen = 32, ++ .expected = (unsigned char *) ++ "\x51\x79\xde\x1c\x0f\x58\xf3\xf4\xc9\x57\x2e\x31" ++ "\xa7\x09\xa1\x53\x64\x63\xa2\xc5\x1d\x84\x88\x65" ++ "\x01\x1b\xc6\x16\x3c\x49\x5b\x42\x8e\x53\xf5\x18" ++ "\xad\x94\x12\x0d\x4f\x55\xcc\x45\x5c\x98\x0f\x42" ++ "\x28\x2f\x47\x11\xf9\xc4\x01\x97\x6b\xa0\x94\x50" ++ "\xa9\xd1\x5e\x06\x54\x3f\xdf\xbb\xc4\x98\xee\x8b" ++ "\xba\xa9\xfa\x49\xee\x1d\xdc\xfb\x50\xf6\x51\x9f" ++ "\x6c\x4a\x9a\x6f\x63\xa2\x7d\xad\xaf\x3a\x24\xa0" ++ "\xd9\x9f\x07\xeb\x15\xee\x26\xe0\xd5\x63\x39\xda" ++ "\x3c\x59\xd6\x33\x6c\x02\xe8\x05\x71\x46\x68\x44" ++ "\x63\x4a\x68\x72\xe9\xf5\x55\xfe", ++ .expectedlen = 128, ++ .addtla = (unsigned char *) ++ "\x15\x20\x2f\xf6\x98\x28\x63\xa2\xc4\x4e\xbb\x6c" ++ "\xb2\x25\x92\x61\x79\xc9\x22\xc4\x61\x54\x96\xff" ++ "\x4a\x85\xca\x80\xfe\x0d\x1c\xd0", ++ .addtlb = (unsigned char *) ++ "\xde\x29\x8e\x03\x42\x61\xa3\x28\x5e\xc8\x80\xc2" ++ "\x6d\xbf\xad\x13\xe1\x8d\x2a\xc7\xe8\xc7\x18\x89" ++ "\x42\x58\x9e\xd6\xcc\xad\x7b\x1e", ++ .addtllen = 32, ++ .pers = (unsigned char *) ++ "\x84\xc3\x73\x9e\xce\xb3\xbc\x89\xf7\x62\xb3\xe1" ++ "\xd7\x48\x45\x8a\xa9\xcc\xe9\xed\xd5\x81\x84\x52" ++ "\x82\x4c\xdc\x19\xb8\xf8\x92\x5c", ++ .perslen = 32, ++ }, ++ { ++ .flags = (DRBG_PR_HMACSHA256), ++ .entropy = (unsigned char *) ++ "\x99\x69\xe5\x4b\x47\x03\xff\x31\x78\x5b\x87\x9a" ++ "\x7e\x5c\x0e\xae\x0d\x3e\x30\x95\x59\xe9\xfe\x96" ++ "\xb0\x67\x6d\x49\xd5\x91\xea\x4d\x07\xd2\x0d\x46" ++ "\xd0\x64\x75\x7d\x30\x23\xca\xc2\x37\x61\x27\xab", ++ .entropylen = 48, ++ .entpra = (unsigned char *) ++ "\xc6\x0f\x29\x99\x10\x0f\x73\x8c\x10\xf7\x47\x92" ++ "\x67\x6a\x3f\xc4\xa2\x62\xd1\x37\x21\x79\x80\x46" ++ "\xe2\x9a\x29\x51\x81\x56\x9f\x54", ++ .entprb = (unsigned char *) ++ "\xc1\x1d\x45\x24\xc9\x07\x1b\xd3\x09\x60\x15\xfc" ++ "\xf7\xbc\x24\xa6\x07\xf2\x2f\xa0\x65\xc9\x37\x65" ++ "\x8a\x2a\x77\xa8\x69\x90\x89\xf4", ++ .entprlen = 32, ++ .expected = (unsigned char *) ++ "\xab\xc0\x15\x85\x60\x94\x80\x3a\x93\x8d\xff\xd2" ++ "\x0d\xa9\x48\x43\x87\x0e\xf9\x35\xb8\x2c\xfe\xc1" ++ "\x77\x06\xb8\xf5\x51\xb8\x38\x50\x44\x23\x5d\xd4" ++ "\x4b\x59\x9f\x94\xb3\x9b\xe7\x8d\xd4\x76\xe0\xcf" ++ "\x11\x30\x9c\x99\x5a\x73\x34\xe0\xa7\x8b\x37\xbc" ++ "\x95\x86\x23\x50\x86\xfa\x3b\x63\x7b\xa9\x1c\xf8" ++ "\xfb\x65\xef\xa2\x2a\x58\x9c\x13\x75\x31\xaa\x7b" ++ "\x2d\x4e\x26\x07\xaa\xc2\x72\x92\xb0\x1c\x69\x8e" ++ "\x6e\x01\xae\x67\x9e\xb8\x7c\x01\xa8\x9c\x74\x22" ++ "\xd4\x37\x2d\x6d\x75\x4a\xba\xbb\x4b\xf8\x96\xfc" ++ "\xb1\xcd\x09\xd6\x92\xd0\x28\x3f", ++ .expectedlen = 128, ++ .addtla = NULL, ++ .addtlb = NULL, ++ .addtllen = 0, ++ .pers = NULL, ++ .perslen = 0, ++ }, ++ { ++ .flags = (DRBG_PR_HMACSHA256), ++ .entropy = (unsigned char *) ++ "\xb9\x1f\xe9\xef\xdd\x9b\x7d\x20\xb6\xec\xe0\x2f" ++ "\xdb\x76\x24\xce\x41\xc8\x3a\x4a\x12\x7f\x3e\x2f" ++ "\xae\x05\x99\xea\xb5\x06\x71\x0d\x0c\x4c\xb4\x05" ++ "\x26\xc6\xbd\xf5\x7f\x2a\x3d\xf2\xb5\x49\x7b\xda", ++ .entropylen = 48, ++ .entpra = (unsigned char *) ++ "\xef\x67\x50\x9c\xa7\x7d\xdf\xb7\x2d\x81\x01\xa4" ++ "\x62\x81\x6a\x69\x5b\xb3\x37\x45\xa7\x34\x8e\x26" ++ "\x46\xd9\x26\xa2\x19\xd4\x94\x43", ++ .entprb = (unsigned char *) ++ "\x97\x75\x53\x53\xba\xb4\xa6\xb2\x91\x60\x71\x79" ++ "\xd1\x6b\x4a\x24\x9a\x34\x66\xcc\x33\xab\x07\x98" ++ "\x51\x78\x72\xb2\x79\xfd\x2c\xff", ++ .entprlen = 32, ++ .expected = (unsigned char *) ++ "\x9c\xdc\x63\x8a\x19\x23\x22\x66\x0c\xc5\xb9\xd7" ++ "\xfb\x2a\xb0\x31\xe3\x8a\x36\xa8\x5a\xa8\x14\xda" ++ "\x1e\xa9\xcc\xfe\xb8\x26\x44\x83\x9f\xf6\xff\xaa" ++ "\xc8\x98\xb8\x30\x35\x3b\x3d\x36\xd2\x49\xd4\x40" ++ "\x62\x0a\x65\x10\x76\x55\xef\xc0\x95\x9c\xa7\xda" ++ "\x3f\xcf\xb7\x7b\xc6\xe1\x28\x52\xfc\x0c\xe2\x37" ++ "\x0d\x83\xa7\x51\x4b\x31\x47\x3c\xe1\x3c\xae\x70" ++ "\x01\xc8\xa3\xd3\xc2\xac\x77\x9c\xd1\x68\x77\x9b" ++ "\x58\x27\x3b\xa5\x0f\xc2\x7a\x8b\x04\x65\x62\xd5" ++ "\xe8\xd6\xfe\x2a\xaf\xd3\xd3\xfe\xbd\x18\xfb\xcd" ++ "\xcd\x66\xb5\x01\x69\x66\xa0\x3c", ++ .expectedlen = 128, ++ .addtla = (unsigned char *) ++ "\x17\xc1\x56\xcb\xcc\x50\xd6\x03\x7d\x45\x76\xa3" ++ "\x75\x76\xc1\x4a\x66\x1b\x2e\xdf\xb0\x2e\x7d\x56" ++ "\x6d\x99\x3b\xc6\x58\xda\x03\xf6", ++ .addtlb = (unsigned char *) ++ "\x7c\x7b\x4a\x4b\x32\x5e\x6f\x67\x34\xf5\x21\x4c" ++ "\xf9\x96\xf9\xbf\x1c\x8c\x81\xd3\x9b\x60\x6a\x44" ++ "\xc6\x03\xa2\xfb\x13\x20\x19\xb7", ++ .addtllen = 32, ++ .pers = NULL, ++ .perslen = 0, ++ }, ++ { ++ .flags = (DRBG_PR_HMACSHA256), ++ .entropy = (unsigned char *) ++ "\x13\x54\x96\xfc\x1b\x7d\x28\xf3\x18\xc9\xa7\x89" ++ "\xb6\xb3\xc8\x72\xac\x00\xd4\x59\x36\x25\x05\xaf" ++ "\xa5\xdb\x96\xcb\x3c\x58\x46\x87\xa5\xaa\xbf\x20" ++ "\x3b\xfe\x23\x0e\xd1\xc7\x41\x0f\x3f\xc9\xb3\x67", ++ .entropylen = 48, ++ .entpra = (unsigned char *) ++ "\xe2\xbd\xb7\x48\x08\x06\xf3\xe1\x93\x3c\xac\x79" ++ "\xa7\x2b\x11\xda\xe3\x2e\xe1\x91\xa5\x02\x19\x57" ++ "\x20\x28\xad\xf2\x60\xd7\xcd\x45", ++ .entprb = (unsigned char *) ++ "\x8b\xd4\x69\xfc\xff\x59\x95\x95\xc6\x51\xde\x71" ++ "\x68\x5f\xfc\xf9\x4a\xab\xec\x5a\xcb\xbe\xd3\x66" ++ "\x1f\xfa\x74\xd3\xac\xa6\x74\x60", ++ .entprlen = 32, ++ .expected = (unsigned char *) ++ "\x1f\x9e\xaf\xe4\xd2\x46\xb7\x47\x41\x4c\x65\x99" ++ "\x01\xe9\x3b\xbb\x83\x0c\x0a\xb0\xc1\x3a\xe2\xb3" ++ "\x31\x4e\xeb\x93\x73\xee\x0b\x26\xc2\x63\xa5\x75" ++ "\x45\x99\xd4\x5c\x9f\xa1\xd4\x45\x87\x6b\x20\x61" ++ "\x40\xea\x78\xa5\x32\xdf\x9e\x66\x17\xaf\xb1\x88" ++ "\x9e\x2e\x23\xdd\xc1\xda\x13\x97\x88\xa5\xb6\x5e" ++ "\x90\x14\x4e\xef\x13\xab\x5c\xd9\x2c\x97\x9e\x7c" ++ "\xd7\xf8\xce\xea\x81\xf5\xcd\x71\x15\x49\x44\xce" ++ "\x83\xb6\x05\xfb\x7d\x30\xb5\x57\x2c\x31\x4f\xfc" ++ "\xfe\x80\xb6\xc0\x13\x0c\x5b\x9b\x2e\x8f\x3d\xfc" ++ "\xc2\xa3\x0c\x11\x1b\x80\x5f\xf3", ++ .expectedlen = 128, ++ .addtla = NULL, ++ .addtlb = NULL, ++ .addtllen = 0, ++ .pers = (unsigned char *) ++ "\x64\xb6\xfc\x60\xbc\x61\x76\x23\x6d\x3f\x4a\x0f" ++ "\xe1\xb4\xd5\x20\x9e\x70\xdd\x03\x53\x6d\xbf\xce" ++ "\xcd\x56\x80\xbc\xb8\x15\xc8\xaa", ++ .perslen = 32, ++ }, ++ { ++ .flags = (DRBG_PR_HMACSHA256), ++ .entropy = (unsigned char *) ++ "\xc7\xcc\xbc\x67\x7e\x21\x66\x1e\x27\x2b\x63\xdd" ++ "\x3a\x78\xdc\xdf\x66\x6d\x3f\x24\xae\xcf\x37\x01" ++ "\xa9\x0d\x89\x8a\xa7\xdc\x81\x58\xae\xb2\x10\x15" ++ "\x7e\x18\x44\x6d\x13\xea\xdf\x37\x85\xfe\x81\xfb", ++ .entropylen = 48, ++ .entpra = (unsigned char *) ++ "\x7b\xa1\x91\x5b\x3c\x04\xc4\x1b\x1d\x19\x2f\x1a" ++ "\x18\x81\x60\x3c\x6c\x62\x91\xb7\xe9\xf5\xcb\x96" ++ "\xbb\x81\x6a\xcc\xb5\xae\x55\xb6", ++ .entprb = (unsigned char *) ++ "\x99\x2c\xc7\x78\x7e\x3b\x88\x12\xef\xbe\xd3\xd2" ++ "\x7d\x2a\xa5\x86\xda\x8d\x58\x73\x4a\x0a\xb2\x2e" ++ "\xbb\x4c\x7e\xe3\x9a\xb6\x81\xc1", ++ .entprlen = 32, ++ .expected = (unsigned char *) ++ "\x95\x6f\x95\xfc\x3b\xb7\xfe\x3e\xd0\x4e\x1a\x14" ++ "\x6c\x34\x7f\x7b\x1d\x0d\x63\x5e\x48\x9c\x69\xe6" ++ "\x46\x07\xd2\x87\xf3\x86\x52\x3d\x98\x27\x5e\xd7" ++ "\x54\xe7\x75\x50\x4f\xfb\x4d\xfd\xac\x2f\x4b\x77" ++ "\xcf\x9e\x8e\xcc\x16\xa2\x24\xcd\x53\xde\x3e\xc5" ++ "\x55\x5d\xd5\x26\x3f\x89\xdf\xca\x8b\x4e\x1e\xb6" ++ "\x88\x78\x63\x5c\xa2\x63\x98\x4e\x6f\x25\x59\xb1" ++ "\x5f\x2b\x23\xb0\x4b\xa5\x18\x5d\xc2\x15\x74\x40" ++ "\x59\x4c\xb4\x1e\xcf\x9a\x36\xfd\x43\xe2\x03\xb8" ++ "\x59\x91\x30\x89\x2a\xc8\x5a\x43\x23\x7c\x73\x72" ++ "\xda\x3f\xad\x2b\xba\x00\x6b\xd1", ++ .expectedlen = 128, ++ .addtla = (unsigned char *) ++ "\x18\xe8\x17\xff\xef\x39\xc7\x41\x5c\x73\x03\x03" ++ "\xf6\x3d\xe8\x5f\xc8\xab\xe4\xab\x0f\xad\xe8\xd6" ++ "\x86\x88\x55\x28\xc1\x69\xdd\x76", ++ .addtlb = (unsigned char *) ++ "\xac\x07\xfc\xbe\x87\x0e\xd3\xea\x1f\x7e\xb8\xe7" ++ "\x9d\xec\xe8\xe7\xbc\xf3\x18\x25\x77\x35\x4a\xaa" ++ "\x00\x99\x2a\xdd\x0a\x00\x50\x82", ++ .addtllen = 32, ++ .pers = (unsigned char *) ++ "\xbc\x55\xab\x3c\xf6\x52\xb0\x11\x3d\x7b\x90\xb8" ++ "\x24\xc9\x26\x4e\x5a\x1e\x77\x0d\x3d\x58\x4a\xda" ++ "\xd1\x81\xe9\xf8\xeb\x30\x8f\x6f", ++ .perslen = 32, ++ }, ++ { ++ .flags = (DRBG_PR_CTRAES128), ++ .entropy = (unsigned char *) ++ "\xd1\x44\xc6\x61\x81\x6d\xca\x9d\x15\x28\x8a\x42" ++ "\x94\xd7\x28\x9c\x43\x77\x19\x29\x1a\x6d\xc3\xa2", ++ .entropylen = 24, ++ .entpra = (unsigned char *) ++ "\x96\xd8\x9e\x45\x32\xc9\xd2\x08\x7a\x6d\x97\x15" "\xb4\xec\x80\xb1", ++ .entprb = (unsigned char *) ++ "\x8b\xb6\x72\xb5\x24\x0b\x98\x65\x95\x95\xe9\xc9" "\x28\x07\xeb\xc2", ++ .entprlen = 16, ++ .expected = (unsigned char *) ++ "\x70\x19\xd0\x4c\x45\x78\xd6\x68\xa9\x9a\xaa\xfe" ++ "\xc1\xdf\x27\x9a\x1c\x0d\x0d\xf7\x24\x75\x46\xcc" ++ "\x77\x6b\xdf\x89\xc6\x94\xdc\x74\x50\x10\x70\x18" ++ "\x9b\xdc\x96\xb4\x89\x23\x40\x1a\xce\x09\x87\xce" ++ "\xd2\xf3\xd5\xe4\x51\x67\x74\x11\x5a\xcc\x8b\x3b" "\x8a\xf1\x23\xa8", ++ .expectedlen = 64, ++ .addtla = NULL, ++ .addtlb = NULL, ++ .addtllen = 0, ++ .pers = NULL, ++ .perslen = 0, ++ }, ++ { ++ .flags = (DRBG_PR_CTRAES128), ++ .entropy = (unsigned char *) ++ "\x8e\x83\xe0\xeb\x37\xea\x3e\x53\x5e\x17\x6e\x77" ++ "\xbd\xb1\x53\x90\xfc\xdc\xc1\x3c\x9a\x88\x22\x94", ++ .entropylen = 24, ++ .entpra = (unsigned char *) ++ "\x6a\x85\xe7\x37\xc8\xf1\x04\x31\x98\x4f\xc8\x73" "\x67\xd1\x08\xf8", ++ .entprb = (unsigned char *) ++ "\xd7\xa4\x68\xe2\x12\x74\xc3\xd9\xf1\xb7\x05\xbc" "\xd4\xba\x04\x58", ++ .entprlen = 16, ++ .expected = (unsigned char *) ++ "\x78\xd6\xa6\x70\xff\xd1\x82\xf5\xa2\x88\x7f\x6d" ++ "\x3d\x8c\x39\xb1\xa8\xcb\x2c\x91\xab\x14\x7e\xbc" ++ "\x95\x45\x9f\x24\xb8\x20\xac\x21\x23\xdb\x72\xd7" ++ "\x12\x8d\x48\x95\xf3\x19\x0c\x43\xc6\x19\x45\xfc" ++ "\x8b\xac\x40\x29\x73\x00\x03\x45\x5e\x12\xff\x0c" "\xc1\x02\x41\x82", ++ .expectedlen = 64, ++ .addtla = (unsigned char *) ++ "\xa2\xd9\x38\xcf\x8b\x29\x67\x5b\x65\x62\x6f\xe8" "\xeb\xb3\x01\x76", ++ .addtlb = (unsigned char *) ++ "\x59\x63\x1e\x81\x8a\x14\xa8\xbb\xa1\xb8\x41\x25" "\xd0\x7f\xcc\x43", ++ .addtllen = 16, ++ .pers = NULL, ++ .perslen = 0, ++ }, ++ { ++ .flags = (DRBG_PR_CTRAES128), ++ .entropy = (unsigned char *) ++ "\x04\xd9\x49\xa6\xdc\xe8\x6e\xbb\xf1\x08\x77\x2b" ++ "\x9e\x08\xca\x92\x65\x16\xda\x99\xa2\x59\xf3\xe8", ++ .entropylen = 24, ++ .entpra = (unsigned char *) ++ "\x38\x7e\x3f\x6b\x51\x70\x7b\x20\xec\x53\xd0\x66" "\xc3\x0f\xe3\xb0", ++ .entprb = (unsigned char *) ++ "\xe0\x86\xa6\xaa\x5f\x72\x2f\xad\xf7\xef\x06\xb8" "\xd6\x9c\x9d\xe8", ++ .entprlen = 16, ++ .expected = (unsigned char *) ++ "\xc9\x0a\xaf\x85\x89\x71\x44\x66\x4f\x25\x0b\x2b" ++ "\xde\xd8\xfa\xff\x52\x5a\x1b\x32\x5e\x41\x7a\x10" ++ "\x1f\xef\x1e\x62\x23\xe9\x20\x30\xc9\x0d\xad\x69" ++ "\xb4\x9c\x5b\xf4\x87\x42\xd5\xae\x5e\x5e\x43\xcc" ++ "\xd9\xfd\x0b\x93\x4a\xe3\xd4\x06\x37\x36\x0f\x3f" "\x72\x82\x0c\xcf", ++ .expectedlen = 64, ++ .addtla = NULL, ++ .addtlb = NULL, ++ .addtllen = 0, ++ .pers = (unsigned char *) ++ "\xbf\xa4\x9a\x8f\x7b\xd8\xb1\x7a\x9d\xfa\x45\xed" "\x21\x52\xb3\xad", ++ .perslen = 16, ++ }, ++ { ++ .flags = (DRBG_PR_CTRAES128), ++ .entropy = (unsigned char *) ++ "\x92\x89\x8f\x31\xfa\x1c\xff\x6d\x18\x2f\x26\x06" ++ "\x43\xdf\xf8\x18\xc2\xa4\xd9\x72\xc3\xb9\xb6\x97", ++ .entropylen = 24, ++ .entpra = (unsigned char *) ++ "\x20\x72\x8a\x06\xf8\x6f\x8d\xd4\x41\xe2\x72\xb7" "\xc4\x2c\xe8\x10", ++ .entprb = (unsigned char *) ++ "\x3d\xb0\xf0\x94\xf3\x05\x50\x33\x17\x86\x3e\x22" "\x08\xf7\xa5\x01", ++ .entprlen = 16, ++ .expected = (unsigned char *) ++ "\x5a\x35\x39\x87\x0f\x4d\x22\xa4\x09\x24\xee\x71" ++ "\xc9\x6f\xac\x72\x0a\xd6\xf0\x88\x82\xd0\x83\x28" ++ "\x73\xec\x3f\x93\xd8\xab\x45\x23\xf0\x7e\xac\x45" ++ "\x14\x5e\x93\x9f\xb1\xd6\x76\x43\x3d\xb6\xe8\x08" ++ "\x88\xf6\xda\x89\x08\x77\x42\xfe\x1a\xf4\x3f\xc4" "\x23\xc5\x1f\x68", ++ .expectedlen = 64, ++ .addtla = (unsigned char *) ++ "\x1a\x40\xfa\xe3\xcc\x6c\x7c\xa0\xf8\xda\xba\x59" "\x23\x6d\xad\x1d", ++ .addtlb = (unsigned char *) ++ "\x9f\x72\x76\x6c\xc7\x46\xe5\xed\x2e\x53\x20\x12" "\xbc\x59\x31\x8c", ++ .addtllen = 16, ++ .pers = (unsigned char *) ++ "\xea\x65\xee\x60\x26\x4e\x7e\xb6\x0e\x82\x68\xc4" "\x37\x3c\x5c\x0b", ++ .perslen = 16, ++ }, ++}; ++ ++struct gcry_drbg_test_vector drbg_test_nopr[] = { ++ { ++ .flags = DRBG_NOPR_HASHSHA256, ++ .entropy = (unsigned char *) ++ "\xa6\x5a\xd0\xf3\x45\xdb\x4e\x0e\xff\xe8\x75\xc3" ++ "\xa2\xe7\x1f\x42\xc7\x12\x9d\x62\x0f\xf5\xc1\x19" ++ "\xa9\xef\x55\xf0\x51\x85\xe0\xfb\x85\x81\xf9\x31" ++ "\x75\x17\x27\x6e\x06\xe9\x60\x7d\xdb\xcb\xcc\x2e", ++ .entropylen = 48, ++ .expected = (unsigned char *) ++ "\xd3\xe1\x60\xc3\x5b\x99\xf3\x40\xb2\x62\x82\x64" ++ "\xd1\x75\x10\x60\xe0\x04\x5d\xa3\x83\xff\x57\xa5" ++ "\x7d\x73\xa6\x73\xd2\xb8\xd8\x0d\xaa\xf6\xa6\xc3" ++ "\x5a\x91\xbb\x45\x79\xd7\x3f\xd0\xc8\xfe\xd1\x11" ++ "\xb0\x39\x13\x06\x82\x8a\xdf\xed\x52\x8f\x01\x81" ++ "\x21\xb3\xfe\xbd\xc3\x43\xe7\x97\xb8\x7d\xbb\x63" ++ "\xdb\x13\x33\xde\xd9\xd1\xec\xe1\x77\xcf\xa6\xb7" ++ "\x1f\xe8\xab\x1d\xa4\x66\x24\xed\x64\x15\xe5\x1c" ++ "\xcd\xe2\xc7\xca\x86\xe2\x83\x99\x0e\xea\xeb\x91" ++ "\x12\x04\x15\x52\x8b\x22\x95\x91\x02\x81\xb0\x2d" ++ "\xd4\x31\xf4\xc9\xf7\x04\x27\xdf", ++ .expectedlen = 128, ++ .addtla = NULL, ++ .addtlb = NULL, ++ .addtllen = 0, ++ .pers = NULL, ++ .perslen = 0, ++ }, ++ { ++ .flags = DRBG_NOPR_HASHSHA256, ++ .entropy = (unsigned char *) ++ "\x73\xd3\xfb\xa3\x94\x5f\x2b\x5f\xb9\x8f\xf6\x9c" ++ "\x8a\x93\x17\xae\x19\xc3\x4c\xc3\xd6\xca\xa3\x2d" ++ "\x16\xfc\x42\xd2\x2d\xd5\x6f\x56\xcc\x1d\x30\xff" ++ "\x9e\x06\x3e\x09\xce\x58\xe6\x9a\x35\xb3\xa6\x56", ++ .entropylen = 48, ++ .expected = (unsigned char *) ++ "\x71\x7b\x93\x46\x1a\x40\xaa\x35\xa4\xaa\xc5\xe7" ++ "\x6d\x5b\x5b\x8a\xa0\xdf\x39\x7d\xae\x71\x58\x5b" ++ "\x3c\x7c\xb4\xf0\x89\xfa\x4a\x8c\xa9\x5c\x54\xc0" ++ "\x40\xdf\xbc\xce\x26\x81\x34\xf8\xba\x7d\x1c\xe8" ++ "\xad\x21\xe0\x74\xcf\x48\x84\x30\x1f\xa1\xd5\x4f" ++ "\x81\x42\x2f\xf4\xdb\x0b\x23\xf8\x73\x27\xb8\x1d" ++ "\x42\xf8\x44\x58\xd8\x5b\x29\x27\x0a\xf8\x69\x59" ++ "\xb5\x78\x44\xeb\x9e\xe0\x68\x6f\x42\x9a\xb0\x5b" ++ "\xe0\x4e\xcb\x6a\xaa\xe2\xd2\xd5\x33\x25\x3e\xe0" ++ "\x6c\xc7\x6a\x07\xa5\x03\x83\x9f\xe2\x8b\xd1\x1c" ++ "\x70\xa8\x07\x59\x97\xeb\xf6\xbe", ++ .expectedlen = 128, ++ .addtla = (unsigned char *) ++ "\xf4\xd5\x98\x3d\xa8\xfc\xfa\x37\xb7\x54\x67\x73" ++ "\xc7\xc3\xdd\x47\x34\x71\x02\x5d\xc1\xa0\xd3\x10" ++ "\xc1\x8b\xbd\xf5\x66\x34\x6f\xdd", ++ .addtlb = (unsigned char *) ++ "\xf7\x9e\x6a\x56\x0e\x73\xe9\xd9\x7a\xd1\x69\xe0" ++ "\x6f\x8c\x55\x1c\x44\xd1\xce\x6f\x28\xcc\xa4\x4d" ++ "\xa8\xc0\x85\xd1\x5a\x0c\x59\x40", ++ .addtllen = 32, ++ .pers = NULL, ++ .perslen = 0, ++ }, ++ { ++ .flags = DRBG_NOPR_HASHSHA256, ++ .entropy = (unsigned char *) ++ "\x2a\x85\xa9\x8b\xd0\xda\x83\xd6\xad\xab\x9f\xbb" ++ "\x54\x31\x15\x95\x1c\x4d\x49\x9f\x6a\x15\xf6\xe4" ++ "\x15\x50\x88\x06\x29\x0d\xed\x8d\xb9\x6f\x96\xe1" ++ "\x83\x9f\xf7\x88\xda\x84\xbf\x44\x28\xd9\x1d\xaa", ++ .entropylen = 48, ++ .expected = (unsigned char *) ++ "\x2d\x55\xde\xc9\xed\x05\x47\x07\x3d\x04\xfc\x28" ++ "\x0f\x92\xf0\x4d\xd8\x00\x32\x47\x0a\x1b\x1c\x4b" ++ "\xef\xd9\x97\xa1\x17\x67\xda\x26\x6c\xfe\x76\x46" ++ "\x6f\xbc\x6d\x82\x4e\x83\x8a\x98\x66\x6c\x01\xb6" ++ "\xe6\x64\xe0\x08\x10\x6f\xd3\x5d\x90\xe7\x0d\x72" ++ "\xa6\xa7\xe3\xbb\x98\x11\x12\x56\x23\xc2\x6d\xd1" ++ "\xc8\xa8\x7a\x39\xf3\x34\xe3\xb8\xf8\x66\x00\x77" ++ "\x7d\xcf\x3c\x3e\xfa\xc9\x0f\xaf\xe0\x24\xfa\xe9" ++ "\x84\xf9\x6a\x01\xf6\x35\xdb\x5c\xab\x2a\xef\x4e" ++ "\xac\xab\x55\xb8\x9b\xef\x98\x68\xaf\x51\xd8\x16" ++ "\xa5\x5e\xae\xf9\x1e\xd2\xdb\xe6", ++ .expectedlen = 128, ++ .addtla = NULL, ++ .addtlb = NULL, ++ .addtllen = 0, ++ .pers = (unsigned char *) ++ "\xa8\x80\xec\x98\x30\x98\x15\xd2\xc6\xc4\x68\xf1" ++ "\x3a\x1c\xbf\xce\x6a\x40\x14\xeb\x36\x99\x53\xda" ++ "\x57\x6b\xce\xa4\x1c\x66\x3d\xbc", ++ .perslen = 32, ++ }, ++ { ++ .flags = DRBG_NOPR_HASHSHA256, ++ .entropy = (unsigned char *) ++ "\x69\xed\x82\xa9\xc5\x7b\xbf\xe5\x1d\x2f\xcb\x7a" ++ "\xd3\x50\x7d\x96\xb4\xb9\x2b\x50\x77\x51\x27\x74" ++ "\x33\x74\xba\xf1\x30\xdf\x8e\xdf\x87\x1d\x87\xbc" ++ "\x96\xb2\xc3\xa7\xed\x60\x5e\x61\x4e\x51\x29\x1a", ++ .entropylen = 48, ++ .expected = (unsigned char *) ++ "\xa5\x71\x24\x31\x11\xfe\x13\xe1\xa8\x24\x12\xfb" ++ "\x37\xa1\x27\xa5\xab\x77\xa1\x9f\xae\x8f\xaf\x13" ++ "\x93\xf7\x53\x85\x91\xb6\x1b\xab\xd4\x6b\xea\xb6" ++ "\xef\xda\x4c\x90\x6e\xef\x5f\xde\xe1\xc7\x10\x36" ++ "\xd5\x67\xbd\x14\xb6\x89\x21\x0c\xc9\x92\x65\x64" ++ "\xd0\xf3\x23\xe0\x7f\xd1\xe8\x75\xc2\x85\x06\xea" ++ "\xca\xc0\xcb\x79\x2d\x29\x82\xfc\xaa\x9a\xc6\x95" ++ "\x7e\xdc\x88\x65\xba\xec\x0e\x16\x87\xec\xa3\x9e" ++ "\xd8\x8c\x80\xab\x3a\x64\xe0\xcb\x0e\x45\x98\xdd" ++ "\x7c\x6c\x6c\x26\x11\x13\xc8\xce\xa9\x47\xa6\x06" ++ "\x57\xa2\x66\xbb\x2d\x7f\xf3\xc1", ++ .expectedlen = 128, ++ .addtla = (unsigned char *) ++ "\x74\xd3\x6d\xda\xe8\xd6\x86\x5f\x63\x01\xfd\xf2" ++ "\x7d\x06\x29\x6d\x94\xd1\x66\xf0\xd2\x72\x67\x4e" ++ "\x77\xc5\x3d\x9e\x03\xe3\xa5\x78", ++ .addtlb = (unsigned char *) ++ "\xf6\xb6\x3d\xf0\x7c\x26\x04\xc5\x8b\xcd\x3e\x6a" ++ "\x9f\x9c\x3a\x2e\xdb\x47\x87\xe5\x8e\x00\x5e\x2b" ++ "\x74\x7f\xa6\xf6\x80\xcd\x9b\x21", ++ .addtllen = 32, ++ .pers = (unsigned char *) ++ "\x74\xa6\xe0\x08\xf9\x27\xee\x1d\x6e\x3c\x28\x20" ++ "\x87\xdd\xd7\x54\x31\x47\x78\x4b\xe5\x6d\xa3\x73" ++ "\xa9\x65\xb1\x10\xc1\xdc\x77\x7c", ++ .perslen = 32, ++ }, ++ { ++ .flags = DRBG_NOPR_HMACSHA256, ++ .entropy = (unsigned char *) ++ "\xca\x85\x19\x11\x34\x93\x84\xbf\xfe\x89\xde\x1c" ++ "\xbd\xc4\x6e\x68\x31\xe4\x4d\x34\xa4\xfb\x93\x5e" ++ "\xe2\x85\xdd\x14\xb7\x1a\x74\x88\x65\x9b\xa9\x6c" ++ "\x60\x1d\xc6\x9f\xc9\x02\x94\x08\x05\xec\x0c\xa8", ++ .entropylen = 48, ++ .expected = (unsigned char *) ++ "\xe5\x28\xe9\xab\xf2\xde\xce\x54\xd4\x7c\x7e\x75" ++ "\xe5\xfe\x30\x21\x49\xf8\x17\xea\x9f\xb4\xbe\xe6" ++ "\xf4\x19\x96\x97\xd0\x4d\x5b\x89\xd5\x4f\xbb\x97" ++ "\x8a\x15\xb5\xc4\x43\xc9\xec\x21\x03\x6d\x24\x60" ++ "\xb6\xf7\x3e\xba\xd0\xdc\x2a\xba\x6e\x62\x4a\xbf" ++ "\x07\x74\x5b\xc1\x07\x69\x4b\xb7\x54\x7b\xb0\x99" ++ "\x5f\x70\xde\x25\xd6\xb2\x9e\x2d\x30\x11\xbb\x19" ++ "\xd2\x76\x76\xc0\x71\x62\xc8\xb5\xcc\xde\x06\x68" ++ "\x96\x1d\xf8\x68\x03\x48\x2c\xb3\x7e\xd6\xd5\xc0" ++ "\xbb\x8d\x50\xcf\x1f\x50\xd4\x76\xaa\x04\x58\xbd" ++ "\xab\xa8\x06\xf4\x8b\xe9\xdc\xb8", ++ .expectedlen = 128, ++ .addtla = NULL, ++ .addtlb = NULL, ++ .addtllen = 0, ++ .pers = NULL, ++ .perslen = 0, ++ }, ++ { ++ .flags = DRBG_NOPR_HMACSHA256, ++ .entropy = (unsigned char *) ++ "\xf9\x7a\x3c\xfd\x91\xfa\xa0\x46\xb9\xe6\x1b\x94" ++ "\x93\xd4\x36\xc4\x93\x1f\x60\x4b\x22\xf1\x08\x15" ++ "\x21\xb3\x41\x91\x51\xe8\xff\x06\x11\xf3\xa7\xd4" ++ "\x35\x95\x35\x7d\x58\x12\x0b\xd1\xe2\xdd\x8a\xed", ++ .entropylen = 48, ++ .expected = (unsigned char *) ++ "\xc6\x87\x1c\xff\x08\x24\xfe\x55\xea\x76\x89\xa5" ++ "\x22\x29\x88\x67\x30\x45\x0e\x5d\x36\x2d\xa5\xbf" ++ "\x59\x0d\xcf\x9a\xcd\x67\xfe\xd4\xcb\x32\x10\x7d" ++ "\xf5\xd0\x39\x69\xa6\x6b\x1f\x64\x94\xfd\xf5\xd6" ++ "\x3d\x5b\x4d\x0d\x34\xea\x73\x99\xa0\x7d\x01\x16" ++ "\x12\x6d\x0d\x51\x8c\x7c\x55\xba\x46\xe1\x2f\x62" ++ "\xef\xc8\xfe\x28\xa5\x1c\x9d\x42\x8e\x6d\x37\x1d" ++ "\x73\x97\xab\x31\x9f\xc7\x3d\xed\x47\x22\xe5\xb4" ++ "\xf3\x00\x04\x03\x2a\x61\x28\xdf\x5e\x74\x97\xec" ++ "\xf8\x2c\xa7\xb0\xa5\x0e\x86\x7e\xf6\x72\x8a\x4f" ++ "\x50\x9a\x8c\x85\x90\x87\x03\x9c", ++ .expectedlen = 128, ++ .addtla = (unsigned char *) ++ "\x51\x72\x89\xaf\xe4\x44\xa0\xfe\x5e\xd1\xa4\x1d" ++ "\xbb\xb5\xeb\x17\x15\x00\x79\xbd\xd3\x1e\x29\xcf" ++ "\x2f\xf3\x00\x34\xd8\x26\x8e\x3b", ++ .addtlb = (unsigned char *) ++ "\x88\x02\x8d\x29\xef\x80\xb4\xe6\xf0\xfe\x12\xf9" ++ "\x1d\x74\x49\xfe\x75\x06\x26\x82\xe8\x9c\x57\x14" ++ "\x40\xc0\xc9\xb5\x2c\x42\xa6\xe0", ++ .addtllen = 32, ++ .pers = NULL, ++ .perslen = 0, ++ }, ++ { ++ .flags = DRBG_NOPR_HMACSHA256, ++ .entropy = (unsigned char *) ++ "\x8d\xf0\x13\xb4\xd1\x03\x52\x30\x73\x91\x7d\xdf" ++ "\x6a\x86\x97\x93\x05\x9e\x99\x43\xfc\x86\x54\x54" ++ "\x9e\x7a\xb2\x2f\x7c\x29\xf1\x22\xda\x26\x25\xaf" ++ "\x2d\xdd\x4a\xbc\xce\x3c\xf4\xfa\x46\x59\xd8\x4e", ++ .entropylen = 48, ++ .expected = (unsigned char *) ++ "\xb9\x1c\xba\x4c\xc8\x4f\xa2\x5d\xf8\x61\x0b\x81" ++ "\xb6\x41\x40\x27\x68\xa2\x09\x72\x34\x93\x2e\x37" ++ "\xd5\x90\xb1\x15\x4c\xbd\x23\xf9\x74\x52\xe3\x10" ++ "\xe2\x91\xc4\x51\x46\x14\x7f\x0d\xa2\xd8\x17\x61" ++ "\xfe\x90\xfb\xa6\x4f\x94\x41\x9c\x0f\x66\x2b\x28" ++ "\xc1\xed\x94\xda\x48\x7b\xb7\xe7\x3e\xec\x79\x8f" ++ "\xbc\xf9\x81\xb7\x91\xd1\xbe\x4f\x17\x7a\x89\x07" ++ "\xaa\x3c\x40\x16\x43\xa5\xb6\x2b\x87\xb8\x9d\x66" ++ "\xb3\xa6\x0e\x40\xd4\xa8\xe4\xe9\xd8\x2a\xf6\xd2" ++ "\x70\x0e\x6f\x53\x5c\xdb\x51\xf7\x5c\x32\x17\x29" ++ "\x10\x37\x41\x03\x0c\xcc\x3a\x56", ++ .expectedlen = 128, ++ .addtla = NULL, ++ .addtlb = NULL, ++ .addtllen = 0, ++ .pers = (unsigned char *) ++ "\xb5\x71\xe6\x6d\x7c\x33\x8b\xc0\x7b\x76\xad\x37" ++ "\x57\xbb\x2f\x94\x52\xbf\x7e\x07\x43\x7a\xe8\x58" ++ "\x1c\xe7\xbc\x7c\x3a\xc6\x51\xa9", ++ .perslen = 32, ++ }, ++ { ++ .flags = DRBG_NOPR_HMACSHA256, ++ .entropy = (unsigned char *) ++ "\xc2\xa5\x66\xa9\xa1\x81\x7b\x15\xc5\xc3\xb7\x78" ++ "\x17\x7a\xc8\x7c\x24\xe7\x97\xbe\x0a\x84\x5f\x11" ++ "\xc2\xfe\x39\x9d\xd3\x77\x32\xf2\xcb\x18\x94\xeb" ++ "\x2b\x97\xb3\xc5\x6e\x62\x83\x29\x51\x6f\x86\xec", ++ .entropylen = 48, ++ .expected = (unsigned char *) ++ "\xb3\xa3\x69\x8d\x77\x76\x99\xa0\xdd\x9f\xa3\xf0" ++ "\xa9\xfa\x57\x83\x2d\x3c\xef\xac\x5d\xf2\x44\x37" ++ "\xc6\xd7\x3a\x0f\xe4\x10\x40\xf1\x72\x90\x38\xae" ++ "\xf1\xe9\x26\x35\x2e\xa5\x9d\xe1\x20\xbf\xb7\xb0" ++ "\x73\x18\x3a\x34\x10\x6e\xfe\xd6\x27\x8f\xf8\xad" ++ "\x84\x4b\xa0\x44\x81\x15\xdf\xdd\xf3\x31\x9a\x82" ++ "\xde\x6b\xb1\x1d\x80\xbd\x87\x1a\x9a\xcd\x35\xc7" ++ "\x36\x45\xe1\x27\x0f\xb9\xfe\x4f\xa8\x8e\xc0\xe4" ++ "\x65\x40\x9e\xa0\xcb\xa8\x09\xfe\x2f\x45\xe0\x49" ++ "\x43\xa2\xe3\x96\xbb\xb7\xdd\x2f\x4e\x07\x95\x30" ++ "\x35\x24\xcc\x9c\xc5\xea\x54\xa1", ++ .expectedlen = 128, ++ .addtla = (unsigned char *) ++ "\x41\x3d\xd8\x3f\xe5\x68\x35\xab\xd4\x78\xcb\x96" ++ "\x93\xd6\x76\x35\x90\x1c\x40\x23\x9a\x26\x64\x62" ++ "\xd3\x13\x3b\x83\xe4\x9c\x82\x0b", ++ .addtlb = (unsigned char *) ++ "\xd5\xc4\xa7\x1f\x9d\x6d\x95\xa1\xbe\xdf\x0b\xd2" ++ "\x24\x7c\x27\x7d\x1f\x84\xa4\xe5\x7a\x4a\x88\x25" ++ "\xb8\x2a\x2d\x09\x7d\xe6\x3e\xf1", ++ .addtllen = 32, ++ .pers = (unsigned char *) ++ "\x13\xce\x4d\x8d\xd2\xdb\x97\x96\xf9\x41\x56\xc8" ++ "\xe8\xf0\x76\x9b\x0a\xa1\xc8\x2c\x13\x23\xb6\x15" ++ "\x36\x60\x3b\xca\x37\xc9\xee\x29", ++ .perslen = 32, ++ }, ++ { ++ .flags = DRBG_NOPR_CTRAES192, ++ .entropy = (unsigned char *) ++ "\xc3\x5c\x2f\xa2\xa8\x9d\x52\xa1\x1f\xa3\x2a\xa9" ++ "\x6c\x95\xb8\xf1\xc9\xa8\xf9\xcb\x24\x5a\x8b\x40" ++ "\xf3\xa6\xe5\xa7\xfb\xd9\xd3\xc6\x8e\x27\x7b\xa9" "\xac\x9b\xbb\x00", ++ .entropylen = 40, ++ .expected = (unsigned char *) ++ "\x8c\x2e\x72\xab\xfd\x9b\xb8\x28\x4d\xb7\x9e\x17" ++ "\xa4\x3a\x31\x46\xcd\x76\x94\xe3\x52\x49\xfc\x33" ++ "\x83\x91\x4a\x71\x17\xf4\x13\x68\xe6\xd4\xf1\x48" ++ "\xff\x49\xbf\x29\x07\x6b\x50\x15\xc5\x9f\x45\x79" ++ "\x45\x66\x2e\x3d\x35\x03\x84\x3f\x4a\xa5\xa3\xdf" "\x9a\x9d\xf1\x0d", ++ .expectedlen = 64, ++ .addtla = NULL, ++ .addtlb = NULL, ++ .addtllen = 0, ++ .pers = NULL, ++ .perslen = 0, ++ }, ++ { ++ .flags = DRBG_NOPR_CTRAES256, ++ .entropy = (unsigned char *) ++ "\x36\x40\x19\x40\xfa\x8b\x1f\xba\x91\xa1\x66\x1f" ++ "\x21\x1d\x78\xa0\xb9\x38\x9a\x74\xe5\xbc\xcf\xec" ++ "\xe8\xd7\x66\xaf\x1a\x6d\x3b\x14\x49\x6f\x25\xb0" ++ "\xf1\x30\x1b\x4f\x50\x1b\xe3\x03\x80\xa1\x37\xeb", ++ .entropylen = 48, ++ .expected = (unsigned char *) ++ "\x58\x62\xeb\x38\xbd\x55\x8d\xd9\x78\xa6\x96\xe6" ++ "\xdf\x16\x47\x82\xdd\xd8\x87\xe7\xe9\xa6\xc9\xf3" ++ "\xf1\xfb\xaf\xb7\x89\x41\xb5\x35\xa6\x49\x12\xdf" ++ "\xd2\x24\xc6\xdc\x74\x54\xe5\x25\x0b\x3d\x97\x16" ++ "\x5e\x16\x26\x0c\x2f\xaf\x1c\xc7\x73\x5c\xb7\x5f" "\xb4\xf0\x7e\x1d", ++ .expectedlen = 64, ++ .addtla = NULL, ++ .addtlb = NULL, ++ .addtllen = 0, ++ .pers = NULL, ++ .perslen = 0, ++ }, ++ { ++ .flags = DRBG_NOPR_CTRAES128, ++ .entropy = (unsigned char *) ++ "\x87\xe1\xc5\x32\x99\x7f\x57\xa3\x5c\x28\x6d\xe8" ++ "\x64\xbf\xf2\x64\xa3\x9e\x98\xdb\x6c\x10\x78\x7f", ++ .entropylen = 24, ++ .expected = (unsigned char *) ++ "\x2c\x14\x7e\x24\x11\x9a\xd8\xd4\xb2\xed\x61\xc1" ++ "\x53\xd0\x50\xc9\x24\xff\x59\x75\x15\xf1\x17\x3a" ++ "\x3d\xf4\x4b\x2c\x84\x28\xef\x89\x0e\xb9\xde\xf3" ++ "\xe4\x78\x04\xb2\xfd\x9b\x35\x7f\xe1\x3f\x8a\x3e" ++ "\x10\xc8\x67\x0a\xf9\xdf\x2d\x6c\x96\xfb\xb2\xb8" "\xcb\x2d\xd6\xb0", ++ .expectedlen = 64, ++ .addtla = NULL, ++ .addtlb = NULL, ++ .addtllen = 0, ++ .pers = NULL, ++ .perslen = 0, ++ }, ++ { ++ .flags = DRBG_NOPR_CTRAES128, ++ .entropy = (unsigned char *) ++ "\x71\xbd\xce\x35\x42\x7d\x20\xbf\x58\xcf\x17\x74" ++ "\xce\x72\xd8\x33\x34\x50\x2d\x8f\x5b\x14\xc4\xdd", ++ .entropylen = 24, ++ .expected = (unsigned char *) ++ "\x97\x33\xe8\x20\x12\xe2\x7b\xa1\x46\x8f\xf2\x34" ++ "\xb3\xc9\xb6\x6b\x20\xb2\x4f\xee\x27\xd8\x0b\x21" ++ "\x8c\xff\x63\x73\x69\x29\xfb\xf3\x85\xcd\x88\x8e" ++ "\x43\x2c\x71\x8b\xa2\x55\xd2\x0f\x1d\x7f\xe3\xe1" ++ "\x2a\xa3\xe9\x2c\x25\x89\xc7\x14\x52\x99\x56\xcc" "\xc3\xdf\xb3\x81", ++ .expectedlen = 64, ++ .addtla = (unsigned char *) ++ "\x66\xef\x42\xd6\x9a\x8c\x3d\x6d\x4a\x9e\x95\xa6" "\x91\x4d\x81\x56", ++ .addtlb = (unsigned char *) ++ "\xe3\x18\x83\xd9\x4b\x5e\xc4\xcc\xaa\x61\x2f\xbb" "\x4a\x55\xd1\xc6", ++ .addtllen = 16, ++ .pers = NULL, ++ .perslen = 0, ++ }, ++ { ++ .flags = DRBG_NOPR_CTRAES128, ++ .entropy = (unsigned char *) ++ "\xca\x4b\x1e\xfa\x75\xbd\x69\x36\x38\x73\xb8\xf9" ++ "\xdb\x4d\x35\x0e\x47\xbf\x6c\x37\x72\xfd\xf7\xa9", ++ .entropylen = 24, ++ .expected = (unsigned char *) ++ "\x59\xc3\x19\x79\x1b\xb1\xf3\x0e\xe9\x34\xae\x6e" ++ "\x8b\x1f\xad\x1f\x74\xca\x25\x45\x68\xb8\x7f\x75" ++ "\x12\xf8\xf2\xab\x4c\x23\x01\x03\x05\xe1\x70\xee" ++ "\x75\xd8\xcb\xeb\x23\x4c\x7a\x23\x6e\x12\x27\xdb" ++ "\x6f\x7a\xac\x3c\x44\xb7\x87\x4b\x65\x56\x74\x45" "\x34\x30\x0c\x3d", ++ .expectedlen = 64, ++ .addtla = NULL, ++ .addtlb = NULL, ++ .addtllen = 0, ++ .pers = (unsigned char *) ++ "\xeb\xaa\x60\x2c\x4d\xbe\x33\xff\x1b\xef\xbf\x0a" "\x0b\xc6\x97\x54", ++ .perslen = 16, ++ }, ++ { ++ .flags = DRBG_NOPR_CTRAES128, ++ .entropy = (unsigned char *) ++ "\xc0\x70\x1f\x92\x50\x75\x8f\xcd\xf2\xbe\x73\x98" ++ "\x80\xdb\x66\xeb\x14\x68\xb4\xa5\x87\x9c\x2d\xa6", ++ .entropylen = 24, ++ .expected = (unsigned char *) ++ "\x97\xc0\xc0\xe5\xa0\xcc\xf2\x4f\x33\x63\x48\x8a" ++ "\xdb\x13\x0a\x35\x89\xbf\x80\x65\x62\xee\x13\x95" ++ "\x7c\x33\xd3\x7d\xf4\x07\x77\x7a\x2b\x65\x0b\x5f" ++ "\x45\x5c\x13\xf1\x90\x77\x7f\xc5\x04\x3f\xcc\x1a" ++ "\x38\xf8\xcd\x1b\xbb\xd5\x57\xd1\x4a\x4c\x2e\x8a" "\x2b\x49\x1e\x5c", ++ .expectedlen = 64, ++ .addtla = (unsigned char *) ++ "\xf9\x01\xf8\x16\x7a\x1d\xff\xde\x8e\x3c\x83\xe2" "\x44\x85\xe7\xfe", ++ .addtlb = (unsigned char *) ++ "\x17\x1c\x09\x38\xc2\x38\x9f\x97\x87\x60\x55\xb4" "\x82\x16\x62\x7f", ++ .addtllen = 16, ++ .pers = (unsigned char *) ++ "\x80\x08\xae\xe8\xe9\x69\x40\xc5\x08\x73\xc7\x9f" "\x8e\xcf\xe0\x02", ++ .perslen = 16, ++ }, ++}; ++ ++struct drbg_flags ++{ ++ u_int32_t flags; ++}; ++ ++gpg_err_code_t ++gcry_drbg_cavs_test (struct gcry_drbg_test_vector *test, unsigned char *buf); ++extern gpg_err_code_t ++gcry_drbg_healthcheck_one (struct gcry_drbg_test_vector *test); ++ ++void builtin_test(void) ++{ ++ /* this must be larger than 128 as otherwise there is a crash */ ++#define OUTLEN 150 ++ char rndbuf[OUTLEN]; ++ char out[(OUTLEN * 2 + 1)]; ++ int i = 0; ++ int ret = 0; ++ int result = 0; ++ struct drbg_flags tests[] = ++ { ++ { .flags = DRBG_PR_HMACSHA1 }, ++ { .flags = DRBG_PR_HMACSHA256 }, ++ { .flags = DRBG_PR_HMACSHA384 }, ++ { .flags = DRBG_PR_HMACSHA512 }, ++ { .flags = DRBG_NOPR_HMACSHA1 }, ++ { .flags = DRBG_NOPR_HMACSHA256 }, ++ { .flags = DRBG_NOPR_HMACSHA384 }, ++ { .flags = DRBG_NOPR_HMACSHA512 }, ++ { .flags = DRBG_PR_HASHSHA1 }, ++ { .flags = DRBG_PR_HASHSHA256 }, ++ { .flags = DRBG_PR_HASHSHA384 }, ++ { .flags = DRBG_PR_HASHSHA512 }, ++ { .flags = DRBG_NOPR_HASHSHA1 }, ++ { .flags = DRBG_NOPR_HASHSHA256 }, ++ { .flags = DRBG_NOPR_HASHSHA384 }, ++ { .flags = DRBG_NOPR_HASHSHA512 }, ++ { .flags = DRBG_PR_CTRAES128 }, ++ { .flags = DRBG_PR_CTRAES192 }, ++ { .flags = DRBG_PR_CTRAES256 }, ++ { .flags = DRBG_NOPR_CTRAES128 }, ++ { .flags = DRBG_NOPR_CTRAES192 }, ++ { .flags = DRBG_NOPR_CTRAES256 }, ++ }; ++ ++ for(i = 0; ARRAY_SIZE(tests) > i; i++) ++ { ++ ret = gcry_control(GCRYCTL_DRBG_REINIT, tests[i].flags, NULL, 0); ++ if(0 == ret) ++ { ++ printf("Test PASS: enabling DRBG %d\n", i); ++ memset(rndbuf, 0, OUTLEN); ++ gcry_randomize(&rndbuf, OUTLEN, GCRY_STRONG_RANDOM); ++ memset(out, 0, sizeof(out)); ++ bin2hex(rndbuf, OUTLEN, out, sizeof(out), 0); ++ printf("Test PASS: gcry_randomize generated strong random bytes for DRBG %d: %s\n", i, out); ++ } ++ else ++ { ++ printf("Test FAIL: enabling DRBG %d\n", i); ++ result += ret; ++ } ++ } ++ ++ ret = gcry_control(GCRYCTL_DRBG_REINIT, 29, NULL, NULL); ++ if(0 == ret) ++ printf("Test FAIL: enabling unknown DRBG\n"); ++ else ++ printf("Test PASS: not enabling unknown DRBG\n"); ++ ++ for(i = 0; ARRAY_SIZE(drbg_test_nopr) > i; i++) ++ { ++ memset(rndbuf, 0, drbg_test_nopr[i].expectedlen); ++ ret = gcry_control(75, &drbg_test_nopr[i], NULL); ++ if(ret) ++ printf("CAVS test (nopr) FAILED %d, testdef %d\n", ret, i); ++ else ++ printf("CAVS test (nopr) PASSED, testdef %d\n", i); ++ result += ret; ++ } ++ ++ for(i = 0; ARRAY_SIZE(drbg_test_pr) > i; i++) ++ { ++ memset(rndbuf, 0, drbg_test_pr[i].expectedlen); ++ ret = gcry_control(75, &drbg_test_pr[i], NULL); ++ if(ret) ++ printf("CAVS test (pr) FAILED %d, testdef %d\n", ret, i); ++ else ++ printf("CAVS test (pr) PASSED, testdef %d\n", i); ++ result += ret; ++ } ++ ++ /* some failure catch tests */ ++ ++ /* there should be no SIGSEV -- if there is, test failed */ ++ gcry_randomize(NULL, ((1UL<<16) + 1), GCRY_STRONG_RANDOM); ++ printf("Test passed: not honoring large data request\n"); ++ ++ /* test automatic health check */ ++ memset(rndbuf, 0, 10); ++ ret = gcry_control(GCRYCTL_DRBG_REINIT, DRBG_NOPR_CTRAES128, NULL, NULL); ++ for (i = 0; i <= (1<<10); i++) ++ gcry_randomize(rndbuf, 10, GCRY_STRONG_RANDOM); ++ printf("Test passed: retest tested\n"); ++ ++ /* Test for max personalization / addtl info string length not possible*/ ++ ++ if(result) ++ printf("completion of all tests FAILED\n"); ++ else ++ printf("completion of all tests: PASSED\n"); ++ ++} ++ ++static void generate_test(struct gcry_drbg_test_vector *test) ++{ ++ unsigned char *buf; ++#define DATALEN 10 ++ union { ++ unsigned char data[DATALEN]; ++ unsigned int data_int; ++ } u; ++ ++ memset(u.data, 0, DATALEN); ++ ++ ++ if (test && test->flags) ++ { ++ if (gcry_control(GCRYCTL_DRBG_REINIT, test->flags, NULL)) ++ { ++ printf("Test FAIL: re-init DRBG with test entropy\n"); ++ return; ++ } ++ } ++ while (1) ++ { ++ unsigned int len = 0; ++ gcry_randomize(u.data, DATALEN, GCRY_STRONG_RANDOM); ++ len = u.data_int & 0xfffff; ++ buf = malloc(len); ++ if(!buf) { ++ fprintf(stderr, "Cannot allocate %u bytes\n", len); ++ return; ++ } ++ ++ gcry_randomize(buf, len, GCRY_STRONG_RANDOM); ++ write(1, buf, len); ++ free (buf); ++ } ++} ++ ++static inline void * ++drbg_malloc (size_t len) ++{ ++ void *buf; ++ buf = malloc (len); ++ if (buf) ++ memset (buf, 0, len); ++ return buf; ++} ++ ++void hex2bin_m(char *in, unsigned char **out, size_t *len) ++{ ++ size_t tmplen = 0; ++ unsigned char *tmp; ++ ++ if (!in) ++ return; ++ ++ tmplen = strlen(in)/2; ++ if (0 > tmplen) ++ return; ++ if (tmplen * 2 != strlen(in)) ++ { ++ printf("odd number of characters which should be a hex string!\n"); ++ return; ++ } ++ ++ tmp = drbg_malloc(tmplen); ++ hex2bin(in, strlen(in), tmp, tmplen); ++ *out = tmp; ++ *len = tmplen; ++} ++ ++static void usage(void) ++{ ++ fprintf(stderr, "\nlibgcrypt DRBG test application\n\n"); ++ fprintf(stderr, "Usage:\n"); ++ fprintf(stderr, "\t-b\tInvoke builtin tests\n"); ++ fprintf(stderr, "\t-g\tGenerate random bits in given chunk size\n"); ++ fprintf(stderr, "\nThe following options are for CAVS testing\n"); ++ fprintf(stderr, "\t-f\tSet the DRBG selection flags - see gcrypt.h\n"); ++ fprintf(stderr, "\t-e\tEntropy string in HEX\n"); ++ fprintf(stderr, "\t-y\t1st Entropy PR string in HEX\n"); ++ fprintf(stderr, "\t-z\t2nd Entropy PR string in HEX\n"); ++ fprintf(stderr, "\t-c\t1st Additional intput string in HEX\n"); ++ fprintf(stderr, "\t-c\t2nd Additional intput string in HEX\n"); ++ fprintf(stderr, "\t-p\tPersonalization string in HEX\n"); ++ fprintf(stderr, "\t-l\tLength of requested random string in bytes\n"); ++ exit(1); ++} ++ ++int ++main (int argc, char **argv) ++{ ++ int c = 0; ++ unsigned char *buf; ++ unsigned char *outbuf; ++ struct gcry_drbg_test_vector exttest; ++#define MAXDATA 256 ++ ++ memset(&exttest, 0, sizeof(struct gcry_drbg_test_vector)); ++ gcry_control (GCRYCTL_SET_VERBOSITY, 2); ++ gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0); ++ if (!gcry_check_version ("1.5.0")) ++ die ("Libgcrypt is not sufficient enough\n"); ++ ++ /*gcry_control (GCRYCTL_DISABLE_SECMEM, 0);*/ ++ gcry_control (GCRYCTL_INIT_SECMEM, 1); ++ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); ++ ++ while(1) ++ { ++ int opt_index = 0; ++ static struct option opts[] = ++ { ++ {"builtin", 0, 0, 0}, ++ {"gen", 0, 0, 0}, ++ {"flags", 1, 0, 0}, ++ {"entropy", 1, 0, 0}, ++ {"entpra", 1, 0, 0}, ++ {"entprb", 1, 0, 0}, ++ {"addtla", 1, 0, 0}, ++ {"addtlb", 1, 0, 0}, ++ {"pers", 1, 0, 0}, ++ {"len", 1, 0, 0}, ++ {0, 0, 0, 0} ++ }; ++ c = getopt_long(argc, argv, "bgf:e:y:z:c:d:p:l:", opts, &opt_index); ++ if(-1 == c) ++ break; ++ switch(c) ++ { ++ case 'b': ++ builtin_test(); ++ return 0; ++ case 'g': ++ generate_test(&exttest); ++ return 0; ++ case 'f': ++ exttest.flags = atoi(optarg); ++ break; ++ case 'e': ++ hex2bin_m(optarg, &exttest.entropy, &exttest.entropylen); ++ break; ++ case 'y': ++ hex2bin_m(optarg, &exttest.entpra, &exttest.entprlen); ++ break; ++ case 'z': ++ hex2bin_m(optarg, &exttest.entprb, &exttest.entprlen); ++ break; ++ case 'c': ++ hex2bin_m(optarg, &exttest.addtla, &exttest.addtllen); ++ break; ++ case 'd': ++ hex2bin_m(optarg, &exttest.addtlb, &exttest.addtllen); ++ break; ++ case 'p': ++ hex2bin_m(optarg, &exttest.pers, &exttest.perslen); ++ break; ++ case 'l': ++ exttest.expectedlen = atoi(optarg); ++ break; ++ default: ++ usage(); ++ } ++ } ++ ++ if (0 >= exttest.expectedlen) ++ usage(); ++ ++ buf = malloc(exttest.expectedlen); ++ if(!buf) { ++ fprintf(stderr, "Cannot allocate %li bytes\n", exttest.expectedlen); ++ return -1; ++ } ++ outbuf = malloc(exttest.expectedlen * 2 + 1); ++ if(!outbuf) { ++ fprintf(stderr, "Cannot allocate %li bytes\n", ++ (exttest.expectedlen*2+1)); ++ return -1; ++ } ++ memset(outbuf, 0, exttest.expectedlen * 2 + 1); ++ if (exttest.entropy) ++ gcry_control(75, &exttest, buf); ++ else ++ gcry_randomize(buf, exttest.expectedlen, GCRY_STRONG_RANDOM); ++ bin2hex(buf, exttest.expectedlen, ++ outbuf, exttest.expectedlen * 2 + 1, 0); ++ ++ printf("%s\n", outbuf); ++ ++ free(buf); ++ free(outbuf); ++ if(exttest.entropy) ++ free(exttest.entropy); ++ if(exttest.entpra) ++ free(exttest.entpra); ++ if(exttest.entprb) ++ free(exttest.entprb); ++ if(exttest.addtla) ++ free(exttest.addtla); ++ if(exttest.addtlb) ++ free(exttest.addtlb); ++ if(exttest.pers) ++ free(exttest.pers); ++ ++ gcry_control (GCRYCTL_TERM_SECMEM); ++ ++ return 0; ++} ++ +Index: libgcrypt-1.9.0/Makefile.am +=================================================================== +--- libgcrypt-1.9.0.orig/Makefile.am ++++ libgcrypt-1.9.0/Makefile.am +@@ -39,6 +39,14 @@ else + doc = + endif + ++bin_PROGRAMS = fipsdrv drbg_test ++ ++fipsdrv_SOURCES = tests/fipsdrv.c ++fipsdrv_LDADD = src/libgcrypt.la $(DL_LIBS) $(GPG_ERROR_LIBS) ++ ++drbg_test_CPPFLAGS = -I../src -I$(top_srcdir)/src ++drbg_test_SOURCES = src/gcrypt.h tests/drbg_test.c ++drbg_test_LDADD = src/libgcrypt.la $(DL_LIBS) $(GPG_ERROR_LIBS) + + DIST_SUBDIRS = m4 compat mpi cipher random src doc tests + SUBDIRS = compat mpi cipher random src $(doc) tests +@@ -51,6 +59,14 @@ EXTRA_DIST = autogen.sh autogen.rc READM + + DISTCLEANFILES = + ++bin_PROGRAMS = fipsdrv drbg_test ++ ++fipsdrv_SOURCES = tests/fipsdrv.c ++fipsdrv_LDADD = src/libgcrypt.la $(DL_LIBS) $(GPG_ERROR_LIBS) ++ ++drbg_test_CPPFLAGS = -I../src -I$(top_srcdir)/src ++drbg_test_SOURCES = src/gcrypt.h tests/drbg_test.c ++drbg_test_LDADD = src/libgcrypt.la $(DL_LIBS) $(GPG_ERROR_LIBS) + + # Add all the files listed in "distfiles" files to the distribution + dist-hook: gen-ChangeLog diff --git a/libgcrypt-1.4.1-rijndael_no_strict_aliasing.patch b/libgcrypt-1.4.1-rijndael_no_strict_aliasing.patch new file mode 100644 index 0000000..c069fc3 --- /dev/null +++ b/libgcrypt-1.4.1-rijndael_no_strict_aliasing.patch @@ -0,0 +1,17 @@ +Index: libgcrypt-1.9.0/cipher/Makefile.am +=================================================================== +--- libgcrypt-1.9.0.orig/cipher/Makefile.am ++++ libgcrypt-1.9.0/cipher/Makefile.am +@@ -155,6 +155,12 @@ tiger.o: $(srcdir)/tiger.c Makefile + tiger.lo: $(srcdir)/tiger.c Makefile + `echo $(LTCOMPILE) -c $< | $(o_flag_munging) ` + ++# rijndael.c needs -fno-strict-aliasing ++rijndael.o: $(srcdir)/rijndael.c ++ `echo $(COMPILE) -fno-strict-aliasing -c $(srcdir)/rijndael.c` ++ ++rijndael.lo: $(srcdir)/rijndael.c ++ `echo $(LTCOMPILE) -fno-strict-aliasing -c $(srcdir)/rijndael.c` + + # We need to disable instrumentation for these modules as they use cc as + # thin assembly front-end and do not tolerate in-between function calls diff --git a/libgcrypt-1.5.0-LIBGCRYPT_FORCE_FIPS_MODE-env.diff b/libgcrypt-1.5.0-LIBGCRYPT_FORCE_FIPS_MODE-env.diff new file mode 100644 index 0000000..51a320b --- /dev/null +++ b/libgcrypt-1.5.0-LIBGCRYPT_FORCE_FIPS_MODE-env.diff @@ -0,0 +1,27 @@ +From: draht@suse.com +Subject: LIBGCRYPT_FORCE_FIPS_MODE env + +environ LIBGCRYPT_FORCE_FIPS_MODE forces FIPS mode of libgcrypt + +Index: libgcrypt-1.5.2/src/fips.c +=================================================================== +--- libgcrypt-1.5.2.orig/src/fips.c ++++ libgcrypt-1.5.2/src/fips.c +@@ -123,6 +123,17 @@ _gcry_initialize_fips_mode (int force) + goto leave; + } + ++ /* for convenience, so that a process can run fips-enabled, but ++ not necessarily all of them, enable FIPS mode via environment ++ variable LIBGCRYPT_FORCE_FIPS_MODE. */ ++ ++ if (getenv("LIBGCRYPT_FORCE_FIPS_MODE") != NULL) ++ { ++ gcry_assert (!_gcry_no_fips_mode_required); ++ 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 diff --git a/libgcrypt-1.6.1-fips-cavs.patch b/libgcrypt-1.6.1-fips-cavs.patch new file mode 100644 index 0000000..8228b7e --- /dev/null +++ b/libgcrypt-1.6.1-fips-cavs.patch @@ -0,0 +1,1126 @@ +Index: libgcrypt-1.7.2/tests/cavs_driver.pl +=================================================================== +--- libgcrypt-1.7.2.orig/tests/cavs_driver.pl ++++ libgcrypt-1.7.2/tests/cavs_driver.pl +@@ -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,10 +305,20 @@ 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 +@@ -500,17 +560,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 +594,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 +1225,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 +1291,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 +1299,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 +1324,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; + +@@ -1503,21 +1593,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 +1617,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 +@@ -1658,12 +1901,16 @@ 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 $xp1 = ""; + my $xp2 = ""; + my $Xp = ""; +@@ -1700,7 +1947,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|KeyPair|PQGVer)/) { + if ($tmpline =~ /CBC/) { $mode="cbc"; } + elsif ($tmpline =~ /ECB/) { $mode="ecb"; } + elsif ($tmpline =~ /OFB/) { $mode="ofb"; } +@@ -1749,7 +1996,15 @@ sub parse($$) { + + if ($tt == 0) { + ##### Identify the test type +- if ($tmpline =~ /KeyGen RSA \(X9\.31\)/) { ++ if ($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 +2015,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 +2047,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 +2130,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 +@@ -1932,11 +2213,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 +2251,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); +@@ -2074,11 +2370,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 "") { +@@ -2141,6 +2436,74 @@ 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 > 0) { + die "Test case $tt not defined"; + } +@@ -2199,7 +2562,9 @@ 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; +Index: libgcrypt-1.7.2/tests/cavs_tests.sh +=================================================================== +--- libgcrypt-1.7.2.orig/tests/cavs_tests.sh ++++ libgcrypt-1.7.2/tests/cavs_tests.sh +@@ -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 + +Index: libgcrypt-1.7.2/tests/fipsdrv.c +=================================================================== +--- libgcrypt-1.7.2.orig/tests/fipsdrv.c ++++ libgcrypt-1.7.2/tests/fipsdrv.c +@@ -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.6.1-use-fipscheck.patch b/libgcrypt-1.6.1-use-fipscheck.patch new file mode 100644 index 0000000..a0f6ca1 --- /dev/null +++ b/libgcrypt-1.6.1-use-fipscheck.patch @@ -0,0 +1,81 @@ +--- + src/Makefile.in | 2 +- + src/fips.c | 39 ++++++++++++++++++++++++++++++++------- + 2 files changed, 33 insertions(+), 8 deletions(-) + +Index: libgcrypt-1.9.0/src/fips.c +=================================================================== +--- libgcrypt-1.9.0.orig/src/fips.c ++++ libgcrypt-1.9.0/src/fips.c +@@ -603,23 +603,49 @@ 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?"; ++ const char key[] = "orboDeJITITejsirpADONivirpUkvarP"; + +- if (!dladdr ("gcry_check_version", &info)) ++ 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 (); +@@ -627,7 +652,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 +@@ -636,7 +661,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 --git a/libgcrypt-1.8.3-fips-ctor.patch b/libgcrypt-1.8.3-fips-ctor.patch new file mode 100644 index 0000000..82dc5b1 --- /dev/null +++ b/libgcrypt-1.8.3-fips-ctor.patch @@ -0,0 +1,266 @@ +Index: libgcrypt-1.9.0/cipher/md.c +=================================================================== +--- libgcrypt-1.9.0.orig/cipher/md.c ++++ libgcrypt-1.9.0/cipher/md.c +@@ -564,11 +564,8 @@ md_enable (gcry_md_hd_t hd, int algorith + + if (!err && algorithm == GCRY_MD_MD5 && fips_mode ()) + { +- _gcry_inactivate_fips_mode ("MD5 used"); + if (_gcry_enforced_fips_mode () ) + { +- /* We should never get to here because we do not register +- MD5 in enforced fips mode. But better throw an error. */ + err = GPG_ERR_DIGEST_ALGO; + } + } +Index: libgcrypt-1.9.0/src/fips.c +=================================================================== +--- libgcrypt-1.9.0.orig/src/fips.c ++++ libgcrypt-1.9.0/src/fips.c +@@ -90,7 +90,31 @@ static void fips_new_state (enum module_ + #define loxdigit_p(p) !!strchr ("01234567890abcdef", *(p)) + + +- ++/* Initialize the FSM lock - this function may only ++ be called once and is intended to be run from the library ++ constructor */ ++void ++_gcry_initialize_fsm_lock (void) ++{ ++ gpg_error_t err; ++ /* Intitialize the lock to protect the FSM. */ ++ err = gpgrt_lock_init (&fsm_lock); ++ if (err) ++ { ++ /* If that fails we can't do anything but abort the ++ process. We need to use log_info so that the FSM won't ++ get involved. */ ++ log_info ("FATAL: failed to create the FSM lock in libgcrypt: %s\n", ++ gpg_strerror (err)); ++#ifdef HAVE_SYSLOG ++ syslog (LOG_USER|LOG_ERR, "Libgcrypt error: " ++ "creating FSM lock failed: %s - abort", ++ gpg_strerror (err)); ++#endif /*HAVE_SYSLOG*/ ++ abort (); ++ } ++} ++ + /* Check whether the OS is in FIPS mode and record that in a module + local variable. If FORCE is passed as true, fips mode will be + enabled anyway. Note: This function is not thread-safe and should +@@ -100,7 +124,6 @@ void + _gcry_initialize_fips_mode (int force) + { + static int done; +- gpg_error_t err; + + /* Make sure we are not accidentally called twice. */ + if (done) +@@ -190,24 +213,6 @@ _gcry_initialize_fips_mode (int force) + /* Yes, we are in FIPS mode. */ + FILE *fp; + +- /* Intitialize the lock to protect the FSM. */ +- err = gpgrt_lock_init (&fsm_lock); +- if (err) +- { +- /* If that fails we can't do anything but abort the +- process. We need to use log_info so that the FSM won't +- get involved. */ +- log_info ("FATAL: failed to create the FSM lock in libgcrypt: %s\n", +- gpg_strerror (err)); +-#ifdef HAVE_SYSLOG +- syslog (LOG_USER|LOG_ERR, "Libgcrypt error: " +- "creating FSM lock failed: %s - abort", +- gpg_strerror (err)); +-#endif /*HAVE_SYSLOG*/ +- abort (); +- } +- +- + /* If the FIPS force files exists, is readable and has a number + != 0 on its first line, we enable the enforced fips mode. */ + fp = fopen (FIPS_FORCE_FILE, "r"); +@@ -356,16 +361,20 @@ _gcry_fips_is_operational (void) + { + int result; + +- if (!fips_mode ()) ++ lock_fsm (); ++ if (current_state == STATE_POWERON && !fips_mode ()) ++ /* If we are at this point in POWERON state it means the FIPS ++ module installation was not completed. (/etc/system-fips ++ is not present.) */ + result = 1; + else + { +- lock_fsm (); +- if (current_state == STATE_INIT) ++ if (current_state == STATE_INIT || current_state == STATE_SELFTEST) + { +- /* If we are still in the INIT state, we need to run the +- selftests so that the FSM can eventually get into +- operational state. Given that we would need a 2-phase ++ /* If we are still in the INIT (or SELFTEST) state, ++ we need to run (or finish) the selftests so ++ that the FSM can eventually get into operational ++ state. Given that we would need a 2-phase + initialization of libgcrypt, but that has traditionally + not been enforced, we use this on demand self-test + checking. Note that Proper applications would do the +@@ -381,9 +390,11 @@ _gcry_fips_is_operational (void) + lock_fsm (); + } + +- result = (current_state == STATE_OPERATIONAL); +- unlock_fsm (); ++ result = (current_state == STATE_OPERATIONAL) || !fips_mode (); ++ /* We always run the selftests but ignore the result ++ in non-FIPS mode. */ + } ++ unlock_fsm (); + return result; + } + +@@ -729,9 +740,25 @@ _gcry_fips_run_selftests (int extended) + { + enum module_states result = STATE_ERROR; + gcry_err_code_t ec = GPG_ERR_SELFTEST_FAILED; ++ int in_poweron; + +- if (fips_mode ()) +- fips_new_state (STATE_SELFTEST); ++ lock_fsm (); ++ in_poweron = (current_state == STATE_POWERON); ++ unlock_fsm (); ++ ++ fips_new_state (STATE_SELFTEST); ++ ++ /* We first check the integrity of the binary. ++ If run from the constructor we are in POWERON state, ++ we return and finish the remaining selftests before ++ real use of the library. It will be in the POWERON ++ state meanwhile. */ ++ if (in_poweron) ++ if (check_binary_integrity ()) ++ goto leave; ++ ++ if (in_poweron) ++ return 0; + + if (run_cipher_selftests (extended)) + goto leave; +@@ -753,21 +780,12 @@ _gcry_fips_run_selftests (int extended) + if (run_pubkey_selftests (extended)) + goto leave; + +- if (fips_mode ()) +- { +- /* Now check the integrity of the binary. We do this this after +- having checked the HMAC code. */ +- if (check_binary_integrity ()) +- goto leave; +- } +- + /* All selftests passed. */ + result = STATE_OPERATIONAL; + ec = 0; + + leave: +- if (fips_mode ()) +- fips_new_state (result); ++ fips_new_state (result); + + return ec; + } +@@ -823,6 +841,7 @@ fips_new_state (enum module_states new_s + { + case STATE_POWERON: + if (new_state == STATE_INIT ++ || new_state == STATE_SELFTEST + || new_state == STATE_ERROR + || new_state == STATE_FATALERROR) + ok = 1; +@@ -837,6 +856,8 @@ fips_new_state (enum module_states new_s + + case STATE_SELFTEST: + if (new_state == STATE_OPERATIONAL ++ || new_state == STATE_INIT ++ || new_state == STATE_SELFTEST + || new_state == STATE_ERROR + || new_state == STATE_FATALERROR) + ok = 1; +Index: libgcrypt-1.9.0/src/global.c +=================================================================== +--- libgcrypt-1.9.0.orig/src/global.c ++++ libgcrypt-1.9.0/src/global.c +@@ -141,6 +141,29 @@ global_init (void) + } + + ++#ifndef FIPS_MODULE_PATH ++#define FIPS_MODULE_PATH "/etc/system-fips" ++#endif ++ ++void __attribute__ ((constructor)) _gcry_global_constructor (void) ++{ ++ int rv; ++ ++ /* We always need the FSM lock to be functional. */ ++ _gcry_initialize_fsm_lock (); ++ ++ rv = access (FIPS_MODULE_PATH, F_OK); ++ if (rv < 0 && errno != ENOENT) ++ rv = 0; ++ ++ if (!rv) ++ { ++ /* We run the integrity check at this point. The remaining ++ selftests are run before use of the library by application. */ ++ _gcry_fips_run_selftests (0); ++ } ++} ++ + /* 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 +@@ -672,9 +695,8 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, + + case GCRYCTL_FIPS_MODE_P: + if (fips_mode () +- && !_gcry_is_fips_mode_inactive () +- && !no_secure_memory) +- rc = GPG_ERR_GENERAL; /* Used as TRUE value */ ++ && !_gcry_is_fips_mode_inactive ()) ++ rc = GPG_ERR_GENERAL; /* Used as TRUE value */ + break; + + case GCRYCTL_FORCE_FIPS_MODE: +@@ -750,9 +772,9 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, + break; + + case GCRYCTL_SET_ENFORCED_FIPS_FLAG: +- if (!_gcry_global_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 (); + } +Index: libgcrypt-1.9.0/src/g10lib.h +=================================================================== +--- libgcrypt-1.9.0.orig/src/g10lib.h ++++ libgcrypt-1.9.0/src/g10lib.h +@@ -429,6 +429,8 @@ gpg_err_code_t _gcry_sexp_vextract_param + + extern int _gcry_no_fips_mode_required; + ++void _gcry_initialize_fsm_lock (void); ++ + void _gcry_initialize_fips_mode (int force); + + /* This macro returns true if fips mode is enabled. This is diff --git a/libgcrypt-1.8.4-allow_FSM_same_state.patch b/libgcrypt-1.8.4-allow_FSM_same_state.patch new file mode 100644 index 0000000..2c68219 --- /dev/null +++ b/libgcrypt-1.8.4-allow_FSM_same_state.patch @@ -0,0 +1,15 @@ +Index: libgcrypt-1.8.4/src/fips.c +=================================================================== +--- libgcrypt-1.8.4.orig/src/fips.c ++++ libgcrypt-1.8.4/src/fips.c +@@ -930,6 +930,10 @@ fips_new_state (enum module_states new_s + + } + ++ /* Allow a transition to the current state */ ++ if (current_state == new_state) ++ ok = 1; ++ + if (ok) + { + current_state = new_state; diff --git a/libgcrypt-1.8.4-fips-keygen.patch b/libgcrypt-1.8.4-fips-keygen.patch new file mode 100644 index 0000000..54e02d5 --- /dev/null +++ b/libgcrypt-1.8.4-fips-keygen.patch @@ -0,0 +1,66 @@ +Index: libgcrypt-1.9.1/cipher/dsa.c +=================================================================== +--- libgcrypt-1.9.1.orig/cipher/dsa.c ++++ libgcrypt-1.9.1/cipher/dsa.c +@@ -457,13 +457,22 @@ generate_fips186 (DSA_secret_key *sk, un + &prime_q, &prime_p, + r_counter, + r_seed, r_seedlen); +- else ++ 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; +@@ -859,13 +868,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; + } + +Index: libgcrypt-1.9.1/cipher/rsa.c +=================================================================== +--- libgcrypt-1.9.1.orig/cipher/rsa.c ++++ libgcrypt-1.9.1/cipher/rsa.c +@@ -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-fips_ctor_skip_integrity_check.patch b/libgcrypt-1.8.4-fips_ctor_skip_integrity_check.patch new file mode 100644 index 0000000..d5688cd --- /dev/null +++ b/libgcrypt-1.8.4-fips_ctor_skip_integrity_check.patch @@ -0,0 +1,32 @@ +Index: libgcrypt-1.8.4/src/global.c +=================================================================== +--- libgcrypt-1.8.4.orig/src/global.c ++++ libgcrypt-1.8.4/src/global.c +@@ -141,27 +141,10 @@ global_init (void) + } + + +-#ifndef FIPS_MODULE_PATH +-#define FIPS_MODULE_PATH "/etc/system-fips" +-#endif +- + void __attribute__ ((constructor)) _gcry_global_constructor (void) + { +- int rv; +- + /* We always need the FSM lock to be functional. */ + _gcry_initialize_fsm_lock (); +- +- rv = access (FIPS_MODULE_PATH, F_OK); +- if (rv < 0 && errno != ENOENT) +- rv = 0; +- +- if (!rv) +- { +- /* We run the integrity check at this point. The remaining +- selftests are run before use of the library by application. */ +- _gcry_fips_run_selftests (0); +- } + } + + /* This function is called by the macro fips_is_operational and makes diff --git a/libgcrypt-1.8.4-getrandom.patch b/libgcrypt-1.8.4-getrandom.patch new file mode 100644 index 0000000..ab069e3 --- /dev/null +++ b/libgcrypt-1.8.4-getrandom.patch @@ -0,0 +1,124 @@ +Index: libgcrypt-1.9.1/random/random-csprng.c +=================================================================== +--- libgcrypt-1.9.1.orig/random/random-csprng.c ++++ libgcrypt-1.9.1/random/random-csprng.c +@@ -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" +@@ -1202,6 +1206,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)) + { +Index: libgcrypt-1.9.1/random/random.c +=================================================================== +--- libgcrypt-1.9.1.orig/random/random.c ++++ libgcrypt-1.9.1/random/random.c +@@ -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 (;;) + { +Index: libgcrypt-1.9.1/random/rndlinux.c +=================================================================== +--- libgcrypt-1.9.1.orig/random/rndlinux.c ++++ libgcrypt-1.9.1/random/rndlinux.c +@@ -39,6 +39,7 @@ extern int getentropy (void *buf, size_t + #if defined(__linux__) || !defined(HAVE_GETENTROPY) + #ifdef HAVE_SYSCALL + # include ++# include + # ifdef __NR_getrandom + # define getentropy(buf,buflen) syscall (__NR_getrandom, buf, buflen, 0) + # endif +@@ -155,12 +156,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; +@@ -176,12 +177,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; +@@ -230,6 +231,17 @@ _gcry_rndlinux_gather_random (void (*add + { + if (fd_urandom == -1) + { ++#if defined(__linux__) && defined(HAVE_SYSCALL) && defined(__NR_getrandom) ++ 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; ++ else /* The syscall is not supported - fallback to /dev/urandom. */ ++#endif + fd_urandom = open_device (NAME_OF_DEV_URANDOM, (ever_opened & 2)); + ever_opened |= 2; + } +@@ -272,9 +284,7 @@ _gcry_rndlinux_gather_random (void (*add + _gcry_post_syscall (); + } + while (ret == -1 && errno == EINTR); +- if (ret == -1 && errno == ENOSYS) +- ; /* getentropy is not supported - fallback to pulling from fd. */ +- else ++ if (1) + { /* getentropy is supported. Some sanity checks. */ + if (ret == -1) + log_fatal ("unexpected error from getentropy: %s\n", diff --git a/libgcrypt-1.8.4-use_xfree.patch b/libgcrypt-1.8.4-use_xfree.patch new file mode 100644 index 0000000..0c921f9 --- /dev/null +++ b/libgcrypt-1.8.4-use_xfree.patch @@ -0,0 +1,39 @@ +Index: libgcrypt-1.8.4/src/hmac256.c +=================================================================== +--- libgcrypt-1.8.4.orig/src/hmac256.c ++++ libgcrypt-1.8.4/src/hmac256.c +@@ -69,6 +69,7 @@ typedef uint32_t u32; + + #ifdef STANDALONE + #define xtrymalloc(a) malloc((a)) ++#define xfree(a) free((a)) + #define gpg_err_set_errno(a) (errno = (a)) + #else + #include "g10lib.h" +@@ -341,7 +342,7 @@ _gcry_hmac256_new (const void *key, size + tmphd = _gcry_hmac256_new (NULL, 0); + if (!tmphd) + { +- free (hd); ++ xfree (hd); + return NULL; + } + _gcry_hmac256_update (tmphd, key, keylen); +@@ -373,7 +374,7 @@ _gcry_hmac256_release (hmac256_context_t + /* Note: We need to take care not to modify errno. */ + if (ctx->use_hmac) + my_wipememory (ctx->opad, 64); +- free (ctx); ++ xfree (ctx); + } + } + +@@ -489,7 +490,7 @@ _gcry_hmac256_file (void *result, size_t + while ( (nread = fread (buffer, 1, buffer_size, fp))) + _gcry_hmac256_update (hd, buffer, nread); + +- free (buffer); ++ xfree (buffer); + + if (ferror (fp)) + { diff --git a/libgcrypt-1.9.4.tar.bz2.sig b/libgcrypt-1.9.4.tar.bz2.sig new file mode 100644 index 0000000000000000000000000000000000000000..abfb42f4f26857a6a7a4878b4ed4d663b7cf883c GIT binary patch literal 119 zcmeAuWnmEGV2~A4WXWBXm$E!p!y#PSlPRcU`VKV*t6Qv0iAtqe3|yQ7Fp;_`4F5F0 zYnXlLa_N2BT40uS_TGwZTfNmH19bVbGBvi;eO~&6;h)yzRj)przRl5cN_O( +Date: Tue, 14 Dec 2021 20:03:06 +0200 +Subject: AES-GCM: Bulk implementation of AES-GCM acceleration for ppc64le + +* configure.ac: Added p10 assembly implementation file and assiciated file. +* cipher/Makefile.am: Added p10 assembly implementation file and associated +file. +* cipher/rijndael.c: Added p10 function. +* cipher/rijndael-p10le.c: New wrapper file for AES-GCM call. +* cipher/rijndael-gcm-p10le.s: New implementation of AES-GCM bulk function in +Power Assembly. +* src/g10lib.h: Added Power arch 3.1 definition for p10. +* src/hwf-ppc.c: Added Power arch 3.1 definition for p10. +* src/hwfeatures.c: Added Power arch 3.1 definition for p10. +-- + +GnuPG-bug-id: 5700 +Signed-off-by: Danny Tsen +[jk: fixes for C coding style] +[jk: prefix assembly functions with '_gcry_ppc10'] +[jk: add assert check for gcm_table size] +Signed-off-by: Jussi Kivilinna + +Index: libgcrypt-1.9.4/cipher/Makefile.am +=================================================================== +--- libgcrypt-1.9.4.orig/cipher/Makefile.am ++++ libgcrypt-1.9.4/cipher/Makefile.am +@@ -105,6 +105,7 @@ EXTRA_libcipher_la_SOURCES = \ + rijndael-armv8-ce.c rijndael-armv8-aarch32-ce.S \ + rijndael-armv8-aarch64-ce.S rijndael-aarch64.S \ + rijndael-ppc.c rijndael-ppc9le.c \ ++ rijndael-p10le.c rijndael-gcm-p10le.s \ + rijndael-ppc-common.h rijndael-ppc-functions.h \ + rijndael-s390x.c \ + rmd160.c \ +@@ -242,6 +243,12 @@ rijndael-ppc9le.o: $(srcdir)/rijndael-pp + rijndael-ppc9le.lo: $(srcdir)/rijndael-ppc9le.c Makefile + `echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + ++rijndael-p10le.o: $(srcdir)/rijndael-p10le.c Makefile ++ `echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` ++ ++rijndael-p10le.lo: $(srcdir)/rijndael-p10le.c Makefile ++ `echo $(LTCOMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` ++ + sha256-ppc.o: $(srcdir)/sha256-ppc.c Makefile + `echo $(COMPILE) $(ppc_vcrypto_cflags) -c $< | $(instrumentation_munging) ` + +Index: libgcrypt-1.9.4/cipher/rijndael-gcm-p10le.s +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/cipher/rijndael-gcm-p10le.s +@@ -0,0 +1,1401 @@ ++# Copyright 2021- IBM Inc. All rights reserved ++# ++# 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 . ++# ++#=================================================================================== ++# Written by Danny Tsen ++# ++# GHASH is based on the Karatsuba multiplication method. ++# ++# Xi xor X1 ++# ++# X1 * H^4 + X2 * H^3 + x3 * H^2 + X4 * H = ++# (X1.h * H4.h + xX.l * H4.l + X1 * H4) + ++# (X2.h * H3.h + X2.l * H3.l + X2 * H3) + ++# (X3.h * H2.h + X3.l * H2.l + X3 * H2) + ++# (X4.h * H.h + X4.l * H.l + X4 * H) ++# ++# Xi = v0 ++# H Poly = v2 ++# Hash keys = v3 - v14 ++# ( H.l, H, H.h) ++# ( H^2.l, H^2, H^2.h) ++# ( H^3.l, H^3, H^3.h) ++# ( H^4.l, H^4, H^4.h) ++# ++# v30 is IV ++# v31 - counter 1 ++# ++# AES used, ++# vs0 - vs14 for round keys ++# v15, v16, v17, v18, v19, v20, v21, v22 for 8 blocks (encrypted) ++# ++# This implementation uses stitched AES-GCM approach to improve overall performance. ++# AES is implemented with 8x blocks and GHASH is using 2 4x blocks. ++# ++# Current performance with 128 bit key using bench-slope on Power10[le] (3.89GHz): ++# ++# AES | nanosecs/byte mebibytes/sec cycles/byte ++# GCM enc | 0.169 ns/B 5643 MiB/s - c/B ++# GCM dec | 0.171 ns/B 5585 MiB/s - c/B ++# ++# =================================================================================== ++# ++ ++.machine "any" ++.abiversion 2 ++.text ++ ++# 4x loops ++# v15 - v18 - input states ++# vs1 - vs9 - round keys ++# ++.macro Loop_aes_middle4x ++ xxlor 19+32, 1, 1 ++ xxlor 20+32, 2, 2 ++ xxlor 21+32, 3, 3 ++ xxlor 22+32, 4, 4 ++ ++ vcipher 15, 15, 19 ++ vcipher 16, 16, 19 ++ vcipher 17, 17, 19 ++ vcipher 18, 18, 19 ++ ++ vcipher 15, 15, 20 ++ vcipher 16, 16, 20 ++ vcipher 17, 17, 20 ++ vcipher 18, 18, 20 ++ ++ vcipher 15, 15, 21 ++ vcipher 16, 16, 21 ++ vcipher 17, 17, 21 ++ vcipher 18, 18, 21 ++ ++ vcipher 15, 15, 22 ++ vcipher 16, 16, 22 ++ vcipher 17, 17, 22 ++ vcipher 18, 18, 22 ++ ++ xxlor 19+32, 5, 5 ++ xxlor 20+32, 6, 6 ++ xxlor 21+32, 7, 7 ++ xxlor 22+32, 8, 8 ++ ++ vcipher 15, 15, 19 ++ vcipher 16, 16, 19 ++ vcipher 17, 17, 19 ++ vcipher 18, 18, 19 ++ ++ vcipher 15, 15, 20 ++ vcipher 16, 16, 20 ++ vcipher 17, 17, 20 ++ vcipher 18, 18, 20 ++ ++ vcipher 15, 15, 21 ++ vcipher 16, 16, 21 ++ vcipher 17, 17, 21 ++ vcipher 18, 18, 21 ++ ++ vcipher 15, 15, 22 ++ vcipher 16, 16, 22 ++ vcipher 17, 17, 22 ++ vcipher 18, 18, 22 ++ ++ xxlor 23+32, 9, 9 ++ vcipher 15, 15, 23 ++ vcipher 16, 16, 23 ++ vcipher 17, 17, 23 ++ vcipher 18, 18, 23 ++.endm ++ ++# 8x loops ++# v15 - v22 - input states ++# vs1 - vs9 - round keys ++# ++.macro Loop_aes_middle8x ++ xxlor 23+32, 1, 1 ++ xxlor 24+32, 2, 2 ++ xxlor 25+32, 3, 3 ++ xxlor 26+32, 4, 4 ++ ++ vcipher 15, 15, 23 ++ vcipher 16, 16, 23 ++ vcipher 17, 17, 23 ++ vcipher 18, 18, 23 ++ vcipher 19, 19, 23 ++ vcipher 20, 20, 23 ++ vcipher 21, 21, 23 ++ vcipher 22, 22, 23 ++ ++ vcipher 15, 15, 24 ++ vcipher 16, 16, 24 ++ vcipher 17, 17, 24 ++ vcipher 18, 18, 24 ++ vcipher 19, 19, 24 ++ vcipher 20, 20, 24 ++ vcipher 21, 21, 24 ++ vcipher 22, 22, 24 ++ ++ vcipher 15, 15, 25 ++ vcipher 16, 16, 25 ++ vcipher 17, 17, 25 ++ vcipher 18, 18, 25 ++ vcipher 19, 19, 25 ++ vcipher 20, 20, 25 ++ vcipher 21, 21, 25 ++ vcipher 22, 22, 25 ++ ++ vcipher 15, 15, 26 ++ vcipher 16, 16, 26 ++ vcipher 17, 17, 26 ++ vcipher 18, 18, 26 ++ vcipher 19, 19, 26 ++ vcipher 20, 20, 26 ++ vcipher 21, 21, 26 ++ vcipher 22, 22, 26 ++ ++ xxlor 23+32, 5, 5 ++ xxlor 24+32, 6, 6 ++ xxlor 25+32, 7, 7 ++ xxlor 26+32, 8, 8 ++ ++ vcipher 15, 15, 23 ++ vcipher 16, 16, 23 ++ vcipher 17, 17, 23 ++ vcipher 18, 18, 23 ++ vcipher 19, 19, 23 ++ vcipher 20, 20, 23 ++ vcipher 21, 21, 23 ++ vcipher 22, 22, 23 ++ ++ vcipher 15, 15, 24 ++ vcipher 16, 16, 24 ++ vcipher 17, 17, 24 ++ vcipher 18, 18, 24 ++ vcipher 19, 19, 24 ++ vcipher 20, 20, 24 ++ vcipher 21, 21, 24 ++ vcipher 22, 22, 24 ++ ++ vcipher 15, 15, 25 ++ vcipher 16, 16, 25 ++ vcipher 17, 17, 25 ++ vcipher 18, 18, 25 ++ vcipher 19, 19, 25 ++ vcipher 20, 20, 25 ++ vcipher 21, 21, 25 ++ vcipher 22, 22, 25 ++ ++ vcipher 15, 15, 26 ++ vcipher 16, 16, 26 ++ vcipher 17, 17, 26 ++ vcipher 18, 18, 26 ++ vcipher 19, 19, 26 ++ vcipher 20, 20, 26 ++ vcipher 21, 21, 26 ++ vcipher 22, 22, 26 ++ ++ xxlor 23+32, 9, 9 ++ vcipher 15, 15, 23 ++ vcipher 16, 16, 23 ++ vcipher 17, 17, 23 ++ vcipher 18, 18, 23 ++ vcipher 19, 19, 23 ++ vcipher 20, 20, 23 ++ vcipher 21, 21, 23 ++ vcipher 22, 22, 23 ++.endm ++ ++# ++# Compute 4x hash values based on Karatsuba method. ++# ++ppc_aes_gcm_ghash: ++ vxor 15, 15, 0 ++ ++ xxlxor 29, 29, 29 ++ ++ vpmsumd 23, 12, 15 # H4.L * X.L ++ vpmsumd 24, 9, 16 ++ vpmsumd 25, 6, 17 ++ vpmsumd 26, 3, 18 ++ ++ vxor 23, 23, 24 ++ vxor 23, 23, 25 ++ vxor 23, 23, 26 # L ++ ++ vpmsumd 24, 13, 15 # H4.L * X.H + H4.H * X.L ++ vpmsumd 25, 10, 16 # H3.L * X1.H + H3.H * X1.L ++ vpmsumd 26, 7, 17 ++ vpmsumd 27, 4, 18 ++ ++ vxor 24, 24, 25 ++ vxor 24, 24, 26 ++ vxor 24, 24, 27 # M ++ ++ # sum hash and reduction with H Poly ++ vpmsumd 28, 23, 2 # reduction ++ ++ xxlor 29+32, 29, 29 ++ vsldoi 26, 24, 29, 8 # mL ++ vsldoi 29, 29, 24, 8 # mH ++ vxor 23, 23, 26 # mL + L ++ ++ vsldoi 23, 23, 23, 8 # swap ++ vxor 23, 23, 28 ++ ++ vpmsumd 24, 14, 15 # H4.H * X.H ++ vpmsumd 25, 11, 16 ++ vpmsumd 26, 8, 17 ++ vpmsumd 27, 5, 18 ++ ++ vxor 24, 24, 25 ++ vxor 24, 24, 26 ++ vxor 24, 24, 27 ++ ++ vxor 24, 24, 29 ++ ++ # sum hash and reduction with H Poly ++ vsldoi 27, 23, 23, 8 # swap ++ vpmsumd 23, 23, 2 ++ vxor 27, 27, 24 ++ vxor 23, 23, 27 ++ ++ xxlor 32, 23+32, 23+32 # update hash ++ ++ blr ++ ++# ++# Combine two 4x ghash ++# v15 - v22 - input blocks ++# ++.macro ppc_aes_gcm_ghash2_4x ++ # first 4x hash ++ vxor 15, 15, 0 # Xi + X ++ ++ xxlxor 29, 29, 29 ++ ++ vpmsumd 23, 12, 15 # H4.L * X.L ++ vpmsumd 24, 9, 16 ++ vpmsumd 25, 6, 17 ++ vpmsumd 26, 3, 18 ++ ++ vxor 23, 23, 24 ++ vxor 23, 23, 25 ++ vxor 23, 23, 26 # L ++ ++ vpmsumd 24, 13, 15 # H4.L * X.H + H4.H * X.L ++ vpmsumd 25, 10, 16 # H3.L * X1.H + H3.H * X1.L ++ vpmsumd 26, 7, 17 ++ vpmsumd 27, 4, 18 ++ ++ vxor 24, 24, 25 ++ vxor 24, 24, 26 ++ ++ # sum hash and reduction with H Poly ++ vpmsumd 28, 23, 2 # reduction ++ ++ xxlor 29+32, 29, 29 ++ ++ vxor 24, 24, 27 # M ++ vsldoi 26, 24, 29, 8 # mL ++ vsldoi 29, 29, 24, 8 # mH ++ vxor 23, 23, 26 # mL + L ++ ++ vsldoi 23, 23, 23, 8 # swap ++ vxor 23, 23, 28 ++ ++ vpmsumd 24, 14, 15 # H4.H * X.H ++ vpmsumd 25, 11, 16 ++ vpmsumd 26, 8, 17 ++ vpmsumd 27, 5, 18 ++ ++ vxor 24, 24, 25 ++ vxor 24, 24, 26 ++ vxor 24, 24, 27 # H ++ ++ vxor 24, 24, 29 # H + mH ++ ++ # sum hash and reduction with H Poly ++ vsldoi 27, 23, 23, 8 # swap ++ vpmsumd 23, 23, 2 ++ vxor 27, 27, 24 ++ vxor 27, 23, 27 # 1st Xi ++ ++ # 2nd 4x hash ++ vpmsumd 24, 9, 20 ++ vpmsumd 25, 6, 21 ++ vpmsumd 26, 3, 22 ++ vxor 19, 19, 27 # Xi + X ++ vpmsumd 23, 12, 19 # H4.L * X.L ++ ++ vxor 23, 23, 24 ++ vxor 23, 23, 25 ++ vxor 23, 23, 26 # L ++ ++ vpmsumd 24, 13, 19 # H4.L * X.H + H4.H * X.L ++ vpmsumd 25, 10, 20 # H3.L * X1.H + H3.H * X1.L ++ vpmsumd 26, 7, 21 ++ vpmsumd 27, 4, 22 ++ ++ vxor 24, 24, 25 ++ vxor 24, 24, 26 ++ ++ # sum hash and reduction with H Poly ++ vpmsumd 28, 23, 2 # reduction ++ ++ xxlor 29+32, 29, 29 ++ ++ vxor 24, 24, 27 # M ++ vsldoi 26, 24, 29, 8 # mL ++ vsldoi 29, 29, 24, 8 # mH ++ vxor 23, 23, 26 # mL + L ++ ++ vsldoi 23, 23, 23, 8 # swap ++ vxor 23, 23, 28 ++ ++ vpmsumd 24, 14, 19 # H4.H * X.H ++ vpmsumd 25, 11, 20 ++ vpmsumd 26, 8, 21 ++ vpmsumd 27, 5, 22 ++ ++ vxor 24, 24, 25 ++ vxor 24, 24, 26 ++ vxor 24, 24, 27 # H ++ ++ vxor 24, 24, 29 # H + mH ++ ++ # sum hash and reduction with H Poly ++ vsldoi 27, 23, 23, 8 # swap ++ vpmsumd 23, 23, 2 ++ vxor 27, 27, 24 ++ vxor 23, 23, 27 ++ ++ xxlor 32, 23+32, 23+32 # update hash ++ ++.endm ++ ++# ++# Compute update single hash ++# ++.macro ppc_update_hash_1x ++ vxor 28, 28, 0 ++ ++ vxor 19, 19, 19 ++ ++ vpmsumd 22, 3, 28 # L ++ vpmsumd 23, 4, 28 # M ++ vpmsumd 24, 5, 28 # H ++ ++ vpmsumd 27, 22, 2 # reduction ++ ++ vsldoi 25, 23, 19, 8 # mL ++ vsldoi 26, 19, 23, 8 # mH ++ vxor 22, 22, 25 # LL + LL ++ vxor 24, 24, 26 # HH + HH ++ ++ vsldoi 22, 22, 22, 8 # swap ++ vxor 22, 22, 27 ++ ++ vsldoi 20, 22, 22, 8 # swap ++ vpmsumd 22, 22, 2 # reduction ++ vxor 20, 20, 24 ++ vxor 22, 22, 20 ++ ++ vmr 0, 22 # update hash ++ ++.endm ++ ++# ++# libgcrypt: ++# _gcry_ppc10_aes_gcm_encrypt (const void *inp, void *out, size_t len, ++# const char *rk, unsigned char iv[16], void *Xip); ++# ++# r3 - inp ++# r4 - out ++# r5 - len ++# r6 - AES round keys ++# r7 - iv ++# r8 - HPoli, hash keys, Xi ++# ++# rounds is at offset 480 in rk ++# Xi is at 256 in gcm_table (Xip). ++# ++.global _gcry_ppc10_aes_gcm_encrypt ++.align 5 ++_gcry_ppc10_aes_gcm_encrypt: ++_gcry_ppc_aes_gcm_encrypt: ++ ++ stdu 1,-512(1) ++ mflr 0 ++ ++ std 14,112(1) ++ std 15,120(1) ++ std 16,128(1) ++ std 17,136(1) ++ std 18,144(1) ++ std 19,152(1) ++ std 20,160(1) ++ std 21,168(1) ++ li 9, 256 ++ stvx 20, 9, 1 ++ addi 9, 9, 16 ++ stvx 21, 9, 1 ++ addi 9, 9, 16 ++ stvx 22, 9, 1 ++ addi 9, 9, 16 ++ stvx 23, 9, 1 ++ addi 9, 9, 16 ++ stvx 24, 9, 1 ++ addi 9, 9, 16 ++ stvx 25, 9, 1 ++ addi 9, 9, 16 ++ stvx 26, 9, 1 ++ addi 9, 9, 16 ++ stvx 27, 9, 1 ++ addi 9, 9, 16 ++ stvx 28, 9, 1 ++ addi 9, 9, 16 ++ stvx 29, 9, 1 ++ addi 9, 9, 16 ++ stvx 30, 9, 1 ++ addi 9, 9, 16 ++ stvx 31, 9, 1 ++ std 0, 528(1) ++ ++ # Load Xi ++ li 10, 256 ++ lxvb16x 32, 10, 8 # load Xi ++ ++ # load Hash - h^4, h^3, h^2, h ++ lxvd2x 2+32, 0, 8 # H Poli ++ li 10, 16 ++ lxvd2x 3+32, 10, 8 # Hl ++ li 10, 32 ++ lxvd2x 4+32, 10, 8 # H ++ li 10, 48 ++ lxvd2x 5+32, 10, 8 # Hh ++ ++ li 10, 64 ++ lxvd2x 6+32, 10, 8 # H^2l ++ li 10, 80 ++ lxvd2x 7+32, 10, 8 # H^2 ++ li 10, 96 ++ lxvd2x 8+32, 10, 8 # H^2h ++ ++ li 10, 112 ++ lxvd2x 9+32, 10, 8 # H^3l ++ li 10, 128 ++ lxvd2x 10+32, 10, 8 # H^3 ++ li 10, 144 ++ lxvd2x 11+32, 10, 8 # H^3h ++ ++ li 10, 160 ++ lxvd2x 12+32, 10, 8 # H^4l ++ li 10, 176 ++ lxvd2x 13+32, 10, 8 # H^4 ++ li 10, 192 ++ lxvd2x 14+32, 10, 8 # H^4h ++ ++ # initialize ICB: GHASH( IV ), IV - r7 ++ lxvb16x 30+32, 0, 7 # load IV - v30 ++ ++ mr 12, 5 # length ++ li 11, 0 # block index ++ ++ # counter 1 ++ vxor 31, 31, 31 ++ vspltisb 22, 1 ++ vsldoi 31, 31, 22,1 # counter 1 ++ ++ # load round key to VSR ++ lxv 0, 0(6) ++ lxv 1, 0x10(6) ++ lxv 2, 0x20(6) ++ lxv 3, 0x30(6) ++ lxv 4, 0x40(6) ++ lxv 5, 0x50(6) ++ lxv 6, 0x60(6) ++ lxv 7, 0x70(6) ++ lxv 8, 0x80(6) ++ lxv 9, 0x90(6) ++ lxv 10, 0xa0(6) ++ ++ # load rounds - 10 (128), 12 (192), 14 (256) ++ lwz 9,480(6) ++ ++ # ++ # vxor state, state, w # addroundkey ++ xxlor 32+29, 0, 0 ++ vxor 15, 30, 29 # IV + round key - add round key 0 ++ ++ cmpdi 9, 10 ++ beq Loop_aes_gcm_8x ++ ++ # load 2 more round keys (v11, v12) ++ lxv 11, 0xb0(6) ++ lxv 12, 0xc0(6) ++ ++ cmpdi 9, 12 ++ beq Loop_aes_gcm_8x ++ ++ # load 2 more round keys (v11, v12, v13, v14) ++ lxv 13, 0xd0(6) ++ lxv 14, 0xe0(6) ++ cmpdi 9, 14 ++ beq Loop_aes_gcm_8x ++ ++ b aes_gcm_out ++ ++.align 5 ++Loop_aes_gcm_8x: ++ mr 14, 3 ++ mr 9, 4 ++ ++ # n blcoks ++ li 10, 128 ++ divdu 10, 5, 10 # n 128 bytes-blocks ++ cmpdi 10, 0 ++ beq Loop_last_block ++ ++ vaddudm 30, 30, 31 # IV + counter ++ vxor 16, 30, 29 ++ vaddudm 30, 30, 31 ++ vxor 17, 30, 29 ++ vaddudm 30, 30, 31 ++ vxor 18, 30, 29 ++ vaddudm 30, 30, 31 ++ vxor 19, 30, 29 ++ vaddudm 30, 30, 31 ++ vxor 20, 30, 29 ++ vaddudm 30, 30, 31 ++ vxor 21, 30, 29 ++ vaddudm 30, 30, 31 ++ vxor 22, 30, 29 ++ ++ mtctr 10 ++ ++ li 15, 16 ++ li 16, 32 ++ li 17, 48 ++ li 18, 64 ++ li 19, 80 ++ li 20, 96 ++ li 21, 112 ++ ++ lwz 10, 480(6) ++ ++Loop_8x_block: ++ ++ lxvb16x 15, 0, 14 # load block ++ lxvb16x 16, 15, 14 # load block ++ lxvb16x 17, 16, 14 # load block ++ lxvb16x 18, 17, 14 # load block ++ lxvb16x 19, 18, 14 # load block ++ lxvb16x 20, 19, 14 # load block ++ lxvb16x 21, 20, 14 # load block ++ lxvb16x 22, 21, 14 # load block ++ addi 14, 14, 128 ++ ++ Loop_aes_middle8x ++ ++ xxlor 23+32, 10, 10 ++ ++ cmpdi 10, 10 ++ beq Do_next_ghash ++ ++ # 192 bits ++ xxlor 24+32, 11, 11 ++ ++ vcipher 15, 15, 23 ++ vcipher 16, 16, 23 ++ vcipher 17, 17, 23 ++ vcipher 18, 18, 23 ++ vcipher 19, 19, 23 ++ vcipher 20, 20, 23 ++ vcipher 21, 21, 23 ++ vcipher 22, 22, 23 ++ ++ vcipher 15, 15, 24 ++ vcipher 16, 16, 24 ++ vcipher 17, 17, 24 ++ vcipher 18, 18, 24 ++ vcipher 19, 19, 24 ++ vcipher 20, 20, 24 ++ vcipher 21, 21, 24 ++ vcipher 22, 22, 24 ++ ++ xxlor 23+32, 12, 12 ++ ++ cmpdi 10, 12 ++ beq Do_next_ghash ++ ++ # 256 bits ++ xxlor 24+32, 13, 13 ++ ++ vcipher 15, 15, 23 ++ vcipher 16, 16, 23 ++ vcipher 17, 17, 23 ++ vcipher 18, 18, 23 ++ vcipher 19, 19, 23 ++ vcipher 20, 20, 23 ++ vcipher 21, 21, 23 ++ vcipher 22, 22, 23 ++ ++ vcipher 15, 15, 24 ++ vcipher 16, 16, 24 ++ vcipher 17, 17, 24 ++ vcipher 18, 18, 24 ++ vcipher 19, 19, 24 ++ vcipher 20, 20, 24 ++ vcipher 21, 21, 24 ++ vcipher 22, 22, 24 ++ ++ xxlor 23+32, 14, 14 ++ ++ cmpdi 10, 14 ++ beq Do_next_ghash ++ b aes_gcm_out ++ ++Do_next_ghash: ++ ++ # ++ # last round ++ vcipherlast 15, 15, 23 ++ vcipherlast 16, 16, 23 ++ ++ xxlxor 47, 47, 15 ++ stxvb16x 47, 0, 9 # store output ++ xxlxor 48, 48, 16 ++ stxvb16x 48, 15, 9 # store output ++ ++ vcipherlast 17, 17, 23 ++ vcipherlast 18, 18, 23 ++ ++ xxlxor 49, 49, 17 ++ stxvb16x 49, 16, 9 # store output ++ xxlxor 50, 50, 18 ++ stxvb16x 50, 17, 9 # store output ++ ++ vcipherlast 19, 19, 23 ++ vcipherlast 20, 20, 23 ++ ++ xxlxor 51, 51, 19 ++ stxvb16x 51, 18, 9 # store output ++ xxlxor 52, 52, 20 ++ stxvb16x 52, 19, 9 # store output ++ ++ vcipherlast 21, 21, 23 ++ vcipherlast 22, 22, 23 ++ ++ xxlxor 53, 53, 21 ++ stxvb16x 53, 20, 9 # store output ++ xxlxor 54, 54, 22 ++ stxvb16x 54, 21, 9 # store output ++ ++ addi 9, 9, 128 ++ ++ # ghash here ++ ppc_aes_gcm_ghash2_4x ++ ++ xxlor 27+32, 0, 0 ++ vaddudm 30, 30, 31 # IV + counter ++ vmr 29, 30 ++ vxor 15, 30, 27 # add round key ++ vaddudm 30, 30, 31 ++ vxor 16, 30, 27 ++ vaddudm 30, 30, 31 ++ vxor 17, 30, 27 ++ vaddudm 30, 30, 31 ++ vxor 18, 30, 27 ++ vaddudm 30, 30, 31 ++ vxor 19, 30, 27 ++ vaddudm 30, 30, 31 ++ vxor 20, 30, 27 ++ vaddudm 30, 30, 31 ++ vxor 21, 30, 27 ++ vaddudm 30, 30, 31 ++ vxor 22, 30, 27 ++ ++ addi 12, 12, -128 ++ addi 11, 11, 128 ++ ++ bdnz Loop_8x_block ++ ++ vmr 30, 29 ++ ++Loop_last_block: ++ cmpdi 12, 0 ++ beq aes_gcm_out ++ ++ # loop last few blocks ++ li 10, 16 ++ divdu 10, 12, 10 ++ ++ mtctr 10 ++ ++ lwz 10, 480(6) ++ ++ cmpdi 12, 16 ++ blt Final_block ++ ++.macro Loop_aes_middle_1x ++ xxlor 19+32, 1, 1 ++ xxlor 20+32, 2, 2 ++ xxlor 21+32, 3, 3 ++ xxlor 22+32, 4, 4 ++ ++ vcipher 15, 15, 19 ++ vcipher 15, 15, 20 ++ vcipher 15, 15, 21 ++ vcipher 15, 15, 22 ++ ++ xxlor 19+32, 5, 5 ++ xxlor 20+32, 6, 6 ++ xxlor 21+32, 7, 7 ++ xxlor 22+32, 8, 8 ++ ++ vcipher 15, 15, 19 ++ vcipher 15, 15, 20 ++ vcipher 15, 15, 21 ++ vcipher 15, 15, 22 ++ ++ xxlor 19+32, 9, 9 ++ vcipher 15, 15, 19 ++.endm ++ ++Next_rem_block: ++ lxvb16x 15, 0, 14 # load block ++ ++ Loop_aes_middle_1x ++ ++ xxlor 23+32, 10, 10 ++ ++ cmpdi 10, 10 ++ beq Do_next_1x ++ ++ # 192 bits ++ xxlor 24+32, 11, 11 ++ ++ vcipher 15, 15, 23 ++ vcipher 15, 15, 24 ++ ++ xxlor 23+32, 12, 12 ++ ++ cmpdi 10, 12 ++ beq Do_next_1x ++ ++ # 256 bits ++ xxlor 24+32, 13, 13 ++ ++ vcipher 15, 15, 23 ++ vcipher 15, 15, 24 ++ ++ xxlor 23+32, 14, 14 ++ ++ cmpdi 10, 14 ++ beq Do_next_1x ++ ++Do_next_1x: ++ vcipherlast 15, 15, 23 ++ ++ xxlxor 47, 47, 15 ++ stxvb16x 47, 0, 9 # store output ++ addi 14, 14, 16 ++ addi 9, 9, 16 ++ ++ vmr 28, 15 ++ ppc_update_hash_1x ++ ++ addi 12, 12, -16 ++ addi 11, 11, 16 ++ xxlor 19+32, 0, 0 ++ vaddudm 30, 30, 31 # IV + counter ++ vxor 15, 30, 19 # add round key ++ ++ bdnz Next_rem_block ++ ++ cmpdi 12, 0 ++ beq aes_gcm_out ++ ++Final_block: ++ Loop_aes_middle_1x ++ ++ xxlor 23+32, 10, 10 ++ ++ cmpdi 10, 10 ++ beq Do_final_1x ++ ++ # 192 bits ++ xxlor 24+32, 11, 11 ++ ++ vcipher 15, 15, 23 ++ vcipher 15, 15, 24 ++ ++ xxlor 23+32, 12, 12 ++ ++ cmpdi 10, 12 ++ beq Do_final_1x ++ ++ # 256 bits ++ xxlor 24+32, 13, 13 ++ ++ vcipher 15, 15, 23 ++ vcipher 15, 15, 24 ++ ++ xxlor 23+32, 14, 14 ++ ++ cmpdi 10, 14 ++ beq Do_final_1x ++ ++Do_final_1x: ++ vcipherlast 15, 15, 23 ++ ++ lxvb16x 15, 0, 14 # load last block ++ xxlxor 47, 47, 15 ++ ++ # create partial block mask ++ li 15, 16 ++ sub 15, 15, 12 # index to the mask ++ ++ vspltisb 16, -1 # first 16 bytes - 0xffff...ff ++ vspltisb 17, 0 # second 16 bytes - 0x0000...00 ++ li 10, 192 ++ stvx 16, 10, 1 ++ addi 10, 10, 16 ++ stvx 17, 10, 1 ++ ++ addi 10, 1, 192 ++ lxvb16x 16, 15, 10 # load partial block mask ++ xxland 47, 47, 16 ++ ++ vmr 28, 15 ++ ppc_update_hash_1x ++ ++ # * should store only the remaining bytes. ++ bl Write_partial_block ++ ++ b aes_gcm_out ++ ++# ++# Write partial block ++# r9 - output ++# r12 - remaining bytes ++# v15 - partial input data ++# ++Write_partial_block: ++ li 10, 192 ++ stxvb16x 15+32, 10, 1 # last block ++ ++ #add 10, 9, 11 # Output ++ addi 10, 9, -1 ++ addi 16, 1, 191 ++ ++ mtctr 12 # remaining bytes ++ li 15, 0 ++ ++Write_last_byte: ++ lbzu 14, 1(16) ++ stbu 14, 1(10) ++ bdnz Write_last_byte ++ blr ++ ++aes_gcm_out: ++ # out = state ++ li 10, 256 ++ stxvb16x 32, 10, 8 # write out Xi ++ add 3, 11, 12 # return count ++ ++ li 9, 256 ++ lvx 20, 9, 1 ++ addi 9, 9, 16 ++ lvx 21, 9, 1 ++ addi 9, 9, 16 ++ lvx 22, 9, 1 ++ addi 9, 9, 16 ++ lvx 23, 9, 1 ++ addi 9, 9, 16 ++ lvx 24, 9, 1 ++ addi 9, 9, 16 ++ lvx 25, 9, 1 ++ addi 9, 9, 16 ++ lvx 26, 9, 1 ++ addi 9, 9, 16 ++ lvx 27, 9, 1 ++ addi 9, 9, 16 ++ lvx 28, 9, 1 ++ addi 9, 9, 16 ++ lvx 29, 9, 1 ++ addi 9, 9, 16 ++ lvx 30, 9, 1 ++ addi 9, 9, 16 ++ lvx 31, 9, 1 ++ ++ ld 0, 528(1) ++ ld 14,112(1) ++ ld 15,120(1) ++ ld 16,128(1) ++ ld 17,136(1) ++ ld 18,144(1) ++ ld 19,152(1) ++ ld 20,160(1) ++ ld 21,168(1) ++ ++ mtlr 0 ++ addi 1, 1, 512 ++ blr ++ ++# ++# 8x Decrypt ++# ++.global _gcry_ppc10_aes_gcm_decrypt ++.align 5 ++_gcry_ppc10_aes_gcm_decrypt: ++_gcry_ppc_aes_gcm_decrypt: ++ ++ stdu 1,-512(1) ++ mflr 0 ++ ++ std 14,112(1) ++ std 15,120(1) ++ std 16,128(1) ++ std 17,136(1) ++ std 18,144(1) ++ std 19,152(1) ++ std 20,160(1) ++ std 21,168(1) ++ li 9, 256 ++ stvx 20, 9, 1 ++ addi 9, 9, 16 ++ stvx 21, 9, 1 ++ addi 9, 9, 16 ++ stvx 22, 9, 1 ++ addi 9, 9, 16 ++ stvx 23, 9, 1 ++ addi 9, 9, 16 ++ stvx 24, 9, 1 ++ addi 9, 9, 16 ++ stvx 25, 9, 1 ++ addi 9, 9, 16 ++ stvx 26, 9, 1 ++ addi 9, 9, 16 ++ stvx 27, 9, 1 ++ addi 9, 9, 16 ++ stvx 28, 9, 1 ++ addi 9, 9, 16 ++ stvx 29, 9, 1 ++ addi 9, 9, 16 ++ stvx 30, 9, 1 ++ addi 9, 9, 16 ++ stvx 31, 9, 1 ++ std 0, 528(1) ++ ++ # Load Xi ++ li 10, 256 ++ lxvb16x 32, 10, 8 # load Xi ++ ++ # load Hash - h^4, h^3, h^2, h ++ lxvd2x 2+32, 0, 8 # H Poli ++ li 10, 16 ++ lxvd2x 3+32, 10, 8 # Hl ++ li 10, 32 ++ lxvd2x 4+32, 10, 8 # H ++ li 10, 48 ++ lxvd2x 5+32, 10, 8 # Hh ++ ++ li 10, 64 ++ lxvd2x 6+32, 10, 8 # H^2l ++ li 10, 80 ++ lxvd2x 7+32, 10, 8 # H^2 ++ li 10, 96 ++ lxvd2x 8+32, 10, 8 # H^2h ++ ++ li 10, 112 ++ lxvd2x 9+32, 10, 8 # H^3l ++ li 10, 128 ++ lxvd2x 10+32, 10, 8 # H^3 ++ li 10, 144 ++ lxvd2x 11+32, 10, 8 # H^3h ++ ++ li 10, 160 ++ lxvd2x 12+32, 10, 8 # H^4l ++ li 10, 176 ++ lxvd2x 13+32, 10, 8 # H^4 ++ li 10, 192 ++ lxvd2x 14+32, 10, 8 # H^4h ++ ++ # initialize ICB: GHASH( IV ), IV - r7 ++ lxvb16x 30+32, 0, 7 # load IV - v30 ++ ++ mr 12, 5 # length ++ li 11, 0 # block index ++ ++ # counter 1 ++ vxor 31, 31, 31 ++ vspltisb 22, 1 ++ vsldoi 31, 31, 22,1 # counter 1 ++ ++ # load round key to VSR ++ lxv 0, 0(6) ++ lxv 1, 0x10(6) ++ lxv 2, 0x20(6) ++ lxv 3, 0x30(6) ++ lxv 4, 0x40(6) ++ lxv 5, 0x50(6) ++ lxv 6, 0x60(6) ++ lxv 7, 0x70(6) ++ lxv 8, 0x80(6) ++ lxv 9, 0x90(6) ++ lxv 10, 0xa0(6) ++ ++ # load rounds - 10 (128), 12 (192), 14 (256) ++ lwz 9,480(6) ++ ++ # ++ # vxor state, state, w # addroundkey ++ xxlor 32+29, 0, 0 ++ vxor 15, 30, 29 # IV + round key - add round key 0 ++ ++ cmpdi 9, 10 ++ beq Loop_aes_gcm_8x_dec ++ ++ # load 2 more round keys (v11, v12) ++ lxv 11, 0xb0(6) ++ lxv 12, 0xc0(6) ++ ++ cmpdi 9, 12 ++ beq Loop_aes_gcm_8x_dec ++ ++ # load 2 more round keys (v11, v12, v13, v14) ++ lxv 13, 0xd0(6) ++ lxv 14, 0xe0(6) ++ cmpdi 9, 14 ++ beq Loop_aes_gcm_8x_dec ++ ++ b aes_gcm_out ++ ++.align 5 ++Loop_aes_gcm_8x_dec: ++ mr 14, 3 ++ mr 9, 4 ++ ++ # n blcoks ++ li 10, 128 ++ divdu 10, 5, 10 # n 128 bytes-blocks ++ cmpdi 10, 0 ++ beq Loop_last_block_dec ++ ++ vaddudm 30, 30, 31 # IV + counter ++ vxor 16, 30, 29 ++ vaddudm 30, 30, 31 ++ vxor 17, 30, 29 ++ vaddudm 30, 30, 31 ++ vxor 18, 30, 29 ++ vaddudm 30, 30, 31 ++ vxor 19, 30, 29 ++ vaddudm 30, 30, 31 ++ vxor 20, 30, 29 ++ vaddudm 30, 30, 31 ++ vxor 21, 30, 29 ++ vaddudm 30, 30, 31 ++ vxor 22, 30, 29 ++ ++ mtctr 10 ++ ++ li 15, 16 ++ li 16, 32 ++ li 17, 48 ++ li 18, 64 ++ li 19, 80 ++ li 20, 96 ++ li 21, 112 ++ ++ lwz 10, 480(6) ++ ++Loop_8x_block_dec: ++ ++ lxvb16x 15, 0, 14 # load block ++ lxvb16x 16, 15, 14 # load block ++ lxvb16x 17, 16, 14 # load block ++ lxvb16x 18, 17, 14 # load block ++ lxvb16x 19, 18, 14 # load block ++ lxvb16x 20, 19, 14 # load block ++ lxvb16x 21, 20, 14 # load block ++ lxvb16x 22, 21, 14 # load block ++ addi 14, 14, 128 ++ ++ Loop_aes_middle8x ++ ++ xxlor 23+32, 10, 10 ++ ++ cmpdi 10, 10 ++ beq Do_last_aes_dec ++ ++ # 192 bits ++ xxlor 24+32, 11, 11 ++ ++ vcipher 15, 15, 23 ++ vcipher 16, 16, 23 ++ vcipher 17, 17, 23 ++ vcipher 18, 18, 23 ++ vcipher 19, 19, 23 ++ vcipher 20, 20, 23 ++ vcipher 21, 21, 23 ++ vcipher 22, 22, 23 ++ ++ vcipher 15, 15, 24 ++ vcipher 16, 16, 24 ++ vcipher 17, 17, 24 ++ vcipher 18, 18, 24 ++ vcipher 19, 19, 24 ++ vcipher 20, 20, 24 ++ vcipher 21, 21, 24 ++ vcipher 22, 22, 24 ++ ++ xxlor 23+32, 12, 12 ++ ++ cmpdi 10, 12 ++ beq Do_last_aes_dec ++ ++ # 256 bits ++ xxlor 24+32, 13, 13 ++ ++ vcipher 15, 15, 23 ++ vcipher 16, 16, 23 ++ vcipher 17, 17, 23 ++ vcipher 18, 18, 23 ++ vcipher 19, 19, 23 ++ vcipher 20, 20, 23 ++ vcipher 21, 21, 23 ++ vcipher 22, 22, 23 ++ ++ vcipher 15, 15, 24 ++ vcipher 16, 16, 24 ++ vcipher 17, 17, 24 ++ vcipher 18, 18, 24 ++ vcipher 19, 19, 24 ++ vcipher 20, 20, 24 ++ vcipher 21, 21, 24 ++ vcipher 22, 22, 24 ++ ++ xxlor 23+32, 14, 14 ++ ++ cmpdi 10, 14 ++ beq Do_last_aes_dec ++ b aes_gcm_out ++ ++Do_last_aes_dec: ++ ++ # ++ # last round ++ vcipherlast 15, 15, 23 ++ vcipherlast 16, 16, 23 ++ ++ xxlxor 47, 47, 15 ++ stxvb16x 47, 0, 9 # store output ++ xxlxor 48, 48, 16 ++ stxvb16x 48, 15, 9 # store output ++ ++ vcipherlast 17, 17, 23 ++ vcipherlast 18, 18, 23 ++ ++ xxlxor 49, 49, 17 ++ stxvb16x 49, 16, 9 # store output ++ xxlxor 50, 50, 18 ++ stxvb16x 50, 17, 9 # store output ++ ++ vcipherlast 19, 19, 23 ++ vcipherlast 20, 20, 23 ++ ++ xxlxor 51, 51, 19 ++ stxvb16x 51, 18, 9 # store output ++ xxlxor 52, 52, 20 ++ stxvb16x 52, 19, 9 # store output ++ ++ vcipherlast 21, 21, 23 ++ vcipherlast 22, 22, 23 ++ ++ xxlxor 53, 53, 21 ++ stxvb16x 53, 20, 9 # store output ++ xxlxor 54, 54, 22 ++ stxvb16x 54, 21, 9 # store output ++ ++ addi 9, 9, 128 ++ ++ xxlor 15+32, 15, 15 ++ xxlor 16+32, 16, 16 ++ xxlor 17+32, 17, 17 ++ xxlor 18+32, 18, 18 ++ xxlor 19+32, 19, 19 ++ xxlor 20+32, 20, 20 ++ xxlor 21+32, 21, 21 ++ xxlor 22+32, 22, 22 ++ ++ # ghash here ++ ppc_aes_gcm_ghash2_4x ++ ++ xxlor 27+32, 0, 0 ++ vaddudm 30, 30, 31 # IV + counter ++ vmr 29, 30 ++ vxor 15, 30, 27 # add round key ++ vaddudm 30, 30, 31 ++ vxor 16, 30, 27 ++ vaddudm 30, 30, 31 ++ vxor 17, 30, 27 ++ vaddudm 30, 30, 31 ++ vxor 18, 30, 27 ++ vaddudm 30, 30, 31 ++ vxor 19, 30, 27 ++ vaddudm 30, 30, 31 ++ vxor 20, 30, 27 ++ vaddudm 30, 30, 31 ++ vxor 21, 30, 27 ++ vaddudm 30, 30, 31 ++ vxor 22, 30, 27 ++ addi 12, 12, -128 ++ addi 11, 11, 128 ++ ++ bdnz Loop_8x_block_dec ++ ++ vmr 30, 29 ++ ++Loop_last_block_dec: ++ cmpdi 12, 0 ++ beq aes_gcm_out ++ ++ # loop last few blocks ++ li 10, 16 ++ divdu 10, 12, 10 ++ ++ mtctr 10 ++ ++ lwz 10,480(6) ++ ++ cmpdi 12, 16 ++ blt Final_block_dec ++ ++Next_rem_block_dec: ++ lxvb16x 15, 0, 14 # load block ++ ++ Loop_aes_middle_1x ++ ++ xxlor 23+32, 10, 10 ++ ++ cmpdi 10, 10 ++ beq Do_next_1x_dec ++ ++ # 192 bits ++ xxlor 24+32, 11, 11 ++ ++ vcipher 15, 15, 23 ++ vcipher 15, 15, 24 ++ ++ xxlor 23+32, 12, 12 ++ ++ cmpdi 10, 12 ++ beq Do_next_1x_dec ++ ++ # 256 bits ++ xxlor 24+32, 13, 13 ++ ++ vcipher 15, 15, 23 ++ vcipher 15, 15, 24 ++ ++ xxlor 23+32, 14, 14 ++ ++ cmpdi 10, 14 ++ beq Do_next_1x_dec ++ ++Do_next_1x_dec: ++ vcipherlast 15, 15, 23 ++ ++ xxlxor 47, 47, 15 ++ stxvb16x 47, 0, 9 # store output ++ addi 14, 14, 16 ++ addi 9, 9, 16 ++ ++ xxlor 28+32, 15, 15 ++ ppc_update_hash_1x ++ ++ addi 12, 12, -16 ++ addi 11, 11, 16 ++ xxlor 19+32, 0, 0 ++ vaddudm 30, 30, 31 # IV + counter ++ vxor 15, 30, 19 # add round key ++ ++ bdnz Next_rem_block_dec ++ ++ cmpdi 12, 0 ++ beq aes_gcm_out ++ ++Final_block_dec: ++ Loop_aes_middle_1x ++ ++ xxlor 23+32, 10, 10 ++ ++ cmpdi 10, 10 ++ beq Do_final_1x_dec ++ ++ # 192 bits ++ xxlor 24+32, 11, 11 ++ ++ vcipher 15, 15, 23 ++ vcipher 15, 15, 24 ++ ++ xxlor 23+32, 12, 12 ++ ++ cmpdi 10, 12 ++ beq Do_final_1x_dec ++ ++ # 256 bits ++ xxlor 24+32, 13, 13 ++ ++ vcipher 15, 15, 23 ++ vcipher 15, 15, 24 ++ ++ xxlor 23+32, 14, 14 ++ ++ cmpdi 10, 14 ++ beq Do_final_1x_dec ++ ++Do_final_1x_dec: ++ vcipherlast 15, 15, 23 ++ ++ lxvb16x 15, 0, 14 # load block ++ xxlxor 47, 47, 15 ++ ++ # create partial block mask ++ li 15, 16 ++ sub 15, 15, 12 # index to the mask ++ ++ vspltisb 16, -1 # first 16 bytes - 0xffff...ff ++ vspltisb 17, 0 # second 16 bytes - 0x0000...00 ++ li 10, 192 ++ stvx 16, 10, 1 ++ addi 10, 10, 16 ++ stvx 17, 10, 1 ++ ++ addi 10, 1, 192 ++ lxvb16x 16, 15, 10 # load block mask ++ xxland 47, 47, 16 ++ ++ xxlor 28+32, 15, 15 ++ ppc_update_hash_1x ++ ++ # * should store only the remaining bytes. ++ bl Write_partial_block ++ ++ b aes_gcm_out ++# +Index: libgcrypt-1.9.4/cipher/rijndael-p10le.c +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/cipher/rijndael-p10le.c +@@ -0,0 +1,119 @@ ++/* Rijndael (AES) for GnuPG - PowerPC Vector Crypto AES implementation ++ * Copyright 2021- IBM Inc. All rights reserved ++ * ++ * 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 ++ ++ ++extern size_t _gcry_ppc10_aes_gcm_encrypt (const void *inp, void *out, ++ size_t len, ++ const unsigned char *key, ++ unsigned char iv[16], void *Xip); ++extern size_t _gcry_ppc10_aes_gcm_decrypt (const void *inp, void *out, ++ size_t len, ++ const unsigned char *key, ++ unsigned char iv[16], void *Xip); ++ ++size_t ++_gcry_aes_p10le_gcm_crypt(gcry_cipher_hd_t c, void *outbuf_arg, ++ const void *inbuf_arg, size_t nblocks, int encrypt) ++{ ++ RIJNDAEL_context *ctx = (RIJNDAEL_context *) &c->context.c; ++ unsigned char *rk = (unsigned char *) ctx->u1.keyschedule; ++ unsigned char *gcm_table = (unsigned char *) c->u_mode.gcm.gcm_table; ++ unsigned char *iv = c->u_ctr.ctr; ++ unsigned char *Xi = c->u_mode.gcm.u_tag.tag; ++ int s = 0; ++ int ndone = 0; ++ int ctr_reset = 0; ++ size_t len = nblocks * GCRY_GCM_BLOCK_LEN; ++ u64 blocks_unused; ++ u64 nb = nblocks; ++ u64 next_ctr = 0; ++ unsigned char ctr_saved[12]; ++ unsigned char *inp = (unsigned char *) inbuf_arg; ++ unsigned char *out = (unsigned char *) outbuf_arg; ++ ++ /* ++ * This is what the aes-gcm asembly code expects some input parameters. ++ * ++ * - Number of rounds is at 480 offset from rk (rk->rounds) ++ * - Xi at 256 offset from gcm_table ++ */ ++ gcry_assert (sizeof(c->u_mode.gcm.gcm_table) >= 256 + 16); ++ buf_cpy (gcm_table+256, Xi, 16); ++ buf_cpy (ctr_saved, c->u_ctr.ctr, 12); ++ ++ while (nb) ++ { ++ blocks_unused = (u64) 0xffffffffU + 1 - (u64) buf_get_be32 (iv + 12); ++ if (nb > blocks_unused) ++ { ++ len = blocks_unused * GCRY_GCM_BLOCK_LEN; ++ nb -= blocks_unused; ++ next_ctr = blocks_unused; ++ ctr_reset = 1; ++ } ++ else ++ { ++ len = nb * GCRY_GCM_BLOCK_LEN; ++ next_ctr = nb; ++ nb = 0; ++ } ++ ++ if (encrypt) ++ s = _gcry_ppc10_aes_gcm_encrypt((const void *) inp, (void *) out, len, ++ (const unsigned char *) rk, iv, ++ (void *) gcm_table); ++ else ++ s = _gcry_ppc10_aes_gcm_decrypt((const void *) inp, (void *) out, len, ++ (const unsigned char *) rk, iv, ++ (void *) gcm_table); ++ ++ cipher_block_add(c->u_ctr.ctr, next_ctr, GCRY_GCM_BLOCK_LEN); ++ if (ctr_reset) ++ { ++ ctr_reset = 0; ++ inp += len; ++ out += len; ++ } ++ buf_cpy (c->u_ctr.ctr, ctr_saved, 12); ++ ndone += s; ++ } ++ buf_cpy (Xi, gcm_table+256, 16); ++ ++ /* ++ * Return number of blocks done. ++ */ ++ s = ndone / GCRY_GCM_BLOCK_LEN; ++ s = nblocks - s; ++ return ( s ); ++} ++ ++#endif /* USE_PPC_CRYPTO_WITH_PPC9LE */ +Index: libgcrypt-1.9.4/cipher/rijndael.c +=================================================================== +--- libgcrypt-1.9.4.orig/cipher/rijndael.c ++++ libgcrypt-1.9.4/cipher/rijndael.c +@@ -295,6 +295,10 @@ extern void _gcry_aes_ppc9le_xts_crypt ( + void *outbuf_arg, + const void *inbuf_arg, + size_t nblocks, int encrypt); ++ ++extern size_t _gcry_aes_p10le_gcm_crypt (gcry_cipher_hd_t c, void *outbuf_arg, ++ const void *inbuf_arg, ++ size_t nblocks, int encrypt); + #endif /*USE_PPC_CRYPTO_WITH_PPC9LE*/ + + #ifdef USE_S390X_CRYPTO +@@ -586,6 +590,8 @@ do_setkey (RIJNDAEL_context *ctx, const + bulk_ops->ocb_crypt = _gcry_aes_ppc9le_ocb_crypt; + bulk_ops->ocb_auth = _gcry_aes_ppc9le_ocb_auth; + bulk_ops->xts_crypt = _gcry_aes_ppc9le_xts_crypt; ++ if (hwfeatures & HWF_PPC_ARCH_3_10) /* for P10 */ ++ bulk_ops->gcm_crypt = _gcry_aes_p10le_gcm_crypt; + } + #endif + #ifdef USE_PPC_CRYPTO +Index: libgcrypt-1.9.4/configure.ac +=================================================================== +--- libgcrypt-1.9.4.orig/configure.ac ++++ libgcrypt-1.9.4/configure.ac +@@ -2597,6 +2597,12 @@ if test "$found" = "1" ; then + # Build with the crypto extension implementation + GCRYPT_CIPHERS="$GCRYPT_CIPHERS rijndael-ppc.lo" + GCRYPT_CIPHERS="$GCRYPT_CIPHERS rijndael-ppc9le.lo" ++ if test "$gcry_cv_gcc_inline_asm_ppc_altivec" = "yes" && ++ test "$gcry_cv_gcc_inline_asm_ppc_arch_3_00" = "yes" ; then ++ # Build with AES-GCM bulk implementation for P10 ++ GCRYPT_CIPHERS="$GCRYPT_CIPHERS rijndael-gcm-p10le.lo" ++ GCRYPT_CIPHERS="$GCRYPT_CIPHERS rijndael-p10le.lo" ++ fi + ;; + powerpc64-*-*) + # Big-Endian. +Index: libgcrypt-1.9.4/src/g10lib.h +=================================================================== +--- libgcrypt-1.9.4.orig/src/g10lib.h ++++ libgcrypt-1.9.4/src/g10lib.h +@@ -252,6 +252,7 @@ char **_gcry_strtokenize (const char *st + #define HWF_PPC_VCRYPTO (1 << 0) + #define HWF_PPC_ARCH_3_00 (1 << 1) + #define HWF_PPC_ARCH_2_07 (1 << 2) ++#define HWF_PPC_ARCH_3_10 (1 << 3) + + #elif defined(HAVE_CPU_ARCH_S390X) + +Index: libgcrypt-1.9.4/src/hwf-ppc.c +=================================================================== +--- libgcrypt-1.9.4.orig/src/hwf-ppc.c ++++ libgcrypt-1.9.4/src/hwf-ppc.c +@@ -92,6 +92,9 @@ struct feature_map_s + #ifndef PPC_FEATURE2_ARCH_3_00 + # define PPC_FEATURE2_ARCH_3_00 0x00800000 + #endif ++#ifndef PPC_FEATURE2_ARCH_3_10 ++# define PPC_FEATURE2_ARCH_3_10 0x00040000 ++#endif + + static const struct feature_map_s ppc_features[] = + { +Index: libgcrypt-1.9.4/src/hwfeatures.c +=================================================================== +--- libgcrypt-1.9.4.orig/src/hwfeatures.c ++++ libgcrypt-1.9.4/src/hwfeatures.c +@@ -72,6 +72,7 @@ static struct + { HWF_PPC_VCRYPTO, "ppc-vcrypto" }, + { HWF_PPC_ARCH_3_00, "ppc-arch_3_00" }, + { HWF_PPC_ARCH_2_07, "ppc-arch_2_07" }, ++ { HWF_PPC_ARCH_3_10, "ppc-arch_3_10" }, + #elif defined(HAVE_CPU_ARCH_S390X) + { HWF_S390X_MSA, "s390x-msa" }, + { HWF_S390X_MSA_4, "s390x-msa-4" }, diff --git a/libgcrypt-FIPS-GMAC_AES-benckmark.patch b/libgcrypt-FIPS-GMAC_AES-benckmark.patch new file mode 100644 index 0000000..d0fff97 --- /dev/null +++ b/libgcrypt-FIPS-GMAC_AES-benckmark.patch @@ -0,0 +1,13 @@ +Index: libgcrypt-1.8.2/tests/benchmark.c +=================================================================== +--- libgcrypt-1.8.2.orig/tests/benchmark.c ++++ libgcrypt-1.8.2/tests/benchmark.c +@@ -598,7 +598,7 @@ mac_bench ( const char *algoname ) + if (!algoname) + { + for (i=1; i < 600; i++) +- if (in_fips_mode && i == GCRY_MAC_HMAC_MD5) ++ if (in_fips_mode && (i == GCRY_MAC_HMAC_MD5 || i == GCRY_MAC_GMAC_AES)) + ; /* Don't use MD5 in fips mode. */ + else if ( !gcry_mac_test_algo (i) ) + mac_bench (gcry_mac_algo_name (i)); diff --git a/libgcrypt-FIPS-HMAC-short-keylen.patch b/libgcrypt-FIPS-HMAC-short-keylen.patch new file mode 100644 index 0000000..db73c2a --- /dev/null +++ b/libgcrypt-FIPS-HMAC-short-keylen.patch @@ -0,0 +1,203 @@ +From 76aad97dd312e83f2f9b8d086553f2b72ab6546f Mon Sep 17 00:00:00 2001 +From: NIIBE Yutaka +Date: Wed, 19 Jan 2022 11:41:40 +0900 +Subject: [PATCH 2/2] fips: Reject shorter key for HMAC in FIPS mode. + +* cipher/md.c (prepare_macpads): Reject < 112-bit key. +* cipher/kdf.c (selftest_pbkdf2): Remove selftest cases with shorter +key. +* cipher/mac-hmac.c (selftests_sha224, selftests_sha256): Likewise. +(selftests_sha384, selftests_sha512, selftests_sha3): Likewise. +* tests/basic.c (check_one_hmac) Handle an error when shorter key +is rejected. +(check_one_mac): Likewise. +* tests/t-kdf.c (check_pbkdf2, check_scrypt): Likewise. + +-- + +GnuPG-bug-id: 5512 +Signed-off-by: NIIBE Yutaka +--- + cipher/kdf.c | 76 ++--------------------------------------------- + cipher/mac-hmac.c | 67 ----------------------------------------- + cipher/md.c | 3 ++ + tests/basic.c | 29 +++++++++++++++--- + tests/t-kdf.c | 38 ++++++++++++++++++++---- + 5 files changed, 62 insertions(+), 151 deletions(-) + +Index: libgcrypt-1.9.4/cipher/kdf.c +=================================================================== +--- libgcrypt-1.9.4.orig/cipher/kdf.c ++++ libgcrypt-1.9.4/cipher/kdf.c +@@ -324,6 +324,10 @@ check_one (int algo, int hash_algo, + unsigned char key[512]; /* hardcoded to avoid allocation */ + size_t keysize = expectlen; + ++ /* Skip test with shoter passphrase in FIPS mode. */ ++ if (fips_mode () && passphraselen < 14) ++ return NULL; ++ + if (keysize > sizeof(key)) + return "invalid tests data"; + +Index: libgcrypt-1.9.4/cipher/mac-hmac.c +=================================================================== +--- libgcrypt-1.9.4.orig/cipher/mac-hmac.c ++++ libgcrypt-1.9.4/cipher/mac-hmac.c +@@ -241,6 +241,11 @@ check_one (int algo, + const unsigned char *digest; + + /* printf ("HMAC algo %d\n", algo); */ ++ ++ /* Skip test with shoter key in FIPS mode. */ ++ if (fips_mode () && keylen < 14) ++ return NULL; ++ + if (trunc) + { + if (_gcry_md_get_algo_dlen (algo) < expectlen) +Index: libgcrypt-1.9.4/cipher/md.c +=================================================================== +--- libgcrypt-1.9.4.orig/cipher/md.c ++++ libgcrypt-1.9.4/cipher/md.c +@@ -903,6 +903,9 @@ prepare_macpads (gcry_md_hd_t a, const u + { + GcryDigestEntry *r; + ++ if (fips_mode () && keylen < 14) ++ return GPG_ERR_INV_VALUE; ++ + if (!a->ctx->list) + return GPG_ERR_DIGEST_ALGO; /* Might happen if no algo is enabled. */ + +Index: libgcrypt-1.9.4/tests/basic.c +=================================================================== +--- libgcrypt-1.9.4.orig/tests/basic.c ++++ libgcrypt-1.9.4/tests/basic.c +@@ -12016,7 +12016,19 @@ check_one_hmac (int algo, const char *da + return; + } + +- gcry_md_setkey( hd, key, keylen ); ++ err = gcry_md_setkey( hd, key, keylen ); ++ if (err) ++ { ++ if (in_fips_mode) ++ { ++ if (verbose) ++ fprintf (stderr, ++ " shorter key (%d) rejected correctly in fips mode\n", ++ keylen); ++ } ++ gcry_md_close (hd); ++ return; ++ } + + gcry_md_write (hd, data, datalen); + +@@ -12420,9 +12432,18 @@ check_one_mac (int algo, const char *dat + clutter_vector_registers(); + err = gcry_mac_setkey (hd, key, keylen); + if (err) +- fail("algo %d, mac gcry_mac_setkey failed: %s\n", algo, gpg_strerror (err)); +- if (err) +- goto out; ++ { ++ if (in_fips_mode) ++ { ++ if (verbose) ++ fprintf (stderr, ++ " shorter key (%d) rejected correctly in fips mode\n", ++ keylen); ++ } ++ else ++ fail("algo %d, mac gcry_mac_setkey failed: %s\n", algo, gpg_strerror (err)); ++ goto out; ++ } + + if (ivlen && iv) + { +Index: libgcrypt-1.9.4/tests/t-kdf.c +=================================================================== +--- libgcrypt-1.9.4.orig/tests/t-kdf.c ++++ libgcrypt-1.9.4/tests/t-kdf.c +@@ -31,6 +31,8 @@ + #define PGM "t-kdf" + #include "t-common.h" + ++static int in_fips_mode; ++ + + static void + dummy_consumer (volatile char *buffer, size_t buflen) +@@ -858,8 +860,7 @@ check_openpgp (void) + if (tv[tvidx].disabled) + continue; + /* MD5 isn't supported in fips mode */ +- if (gcry_fips_mode_active() +- && tv[tvidx].hashalgo == GCRY_MD_MD5) ++ if (in_fips_mode && tv[tvidx].hashalgo == GCRY_MD_MD5) + continue; + if (verbose) + fprintf (stderr, "checking S2K test vector %d\n", tvidx); +@@ -1104,7 +1105,7 @@ check_pbkdf2 (void) + GCRY_KDF_PBKDF2, tv[tvidx].hashalgo, + tv[tvidx].salt, tv[tvidx].saltlen, + tv[tvidx].c, tv[tvidx].dklen, outbuf); +- if (gcry_fips_mode_active() && tvidx > 6) ++ if (in_fips_mode && tvidx > 6) + { + if (!err) + fail ("pbkdf2 test %d unexpectedly passed in FIPS mode: %s\n", +@@ -1112,7 +1113,17 @@ check_pbkdf2 (void) + continue; + } + if (err) +- fail ("pbkdf2 test %d failed: %s\n", tvidx, gpg_strerror (err)); ++ { ++ if (in_fips_mode && tv[tvidx].plen < 14) ++ { ++ if (verbose) ++ fprintf (stderr, ++ " shorter key (%u) rejected correctly in fips mode\n", ++ (unsigned int)tv[tvidx].plen); ++ } ++ else ++ fail ("pbkdf2 test %d failed: %s\n", tvidx, gpg_strerror (err)); ++ } + else if (memcmp (outbuf, tv[tvidx].dk, tv[tvidx].dklen)) + { + fail ("pbkdf2 test %d failed: mismatch\n", tvidx); +@@ -1209,7 +1220,17 @@ check_scrypt (void) + tv[tvidx].salt, tv[tvidx].saltlen, + tv[tvidx].parm_p, tv[tvidx].dklen, outbuf); + if (err) +- fail ("scrypt test %d failed: %s\n", tvidx, gpg_strerror (err)); ++ { ++ if (in_fips_mode && tv[tvidx].plen < 14) ++ { ++ if (verbose) ++ fprintf (stderr, ++ " shorter key (%u) rejected correctly in fips mode\n", ++ (unsigned int)tv[tvidx].plen); ++ } ++ else ++ fail ("scrypt test %d failed: %s\n", tvidx, gpg_strerror (err)); ++ } + else if (memcmp (outbuf, tv[tvidx].dk, tv[tvidx].dklen)) + { + fail ("scrypt test %d failed: mismatch\n", tvidx); +@@ -1281,7 +1302,12 @@ main (int argc, char **argv) + if (!gcry_check_version (GCRYPT_VERSION)) + die ("version mismatch\n"); + +- xgcry_control ((GCRYCTL_DISABLE_SECMEM, 0)); ++ if (gcry_fips_mode_active ()) ++ in_fips_mode = 1; ++ ++ if (!in_fips_mode) ++ xgcry_control ((GCRYCTL_DISABLE_SECMEM, 0)); ++ + xgcry_control ((GCRYCTL_INITIALIZATION_FINISHED, 0)); + if (debug) + xgcry_control ((GCRYCTL_SET_DEBUG_FLAGS, 1u, 0)); diff --git a/libgcrypt-FIPS-RSA-DSA-ECDSA-hashing-operation.patch b/libgcrypt-FIPS-RSA-DSA-ECDSA-hashing-operation.patch new file mode 100644 index 0000000..2e739de --- /dev/null +++ b/libgcrypt-FIPS-RSA-DSA-ECDSA-hashing-operation.patch @@ -0,0 +1,245 @@ +Index: libgcrypt-1.9.0/cipher/pubkey.c +=================================================================== +--- libgcrypt-1.9.0.orig/cipher/pubkey.c ++++ libgcrypt-1.9.0/cipher/pubkey.c +@@ -384,6 +384,33 @@ _gcry_pk_decrypt (gcry_sexp_t *r_plain, + } + + ++static gcry_err_code_t ++calculate_hash (gcry_md_hd_t hd, gcry_sexp_t* s_hash) ++{ ++ gcry_err_code_t rc; ++ const unsigned char *digest; ++ int algo; ++ ++ if (!hd) ++ return 0; ++ ++ rc = _gcry_pk_util_get_algo (*s_hash, &algo); ++ if (rc) ++ return rc; ++ ++ digest = _gcry_md_read(hd, algo); ++ if (!digest) ++ return GPG_ERR_DIGEST_ALGO; ++ ++ rc = _gcry_sexp_build (s_hash, NULL, ++ "(data (flags pkcs1)(hash %s %b))", ++ _gcry_md_algo_name(algo), ++ (int) _gcry_md_get_algo_dlen(algo), ++ digest); ++ ++ return rc; ++} ++ + + /* + Create a signature. +@@ -414,7 +441,8 @@ _gcry_pk_decrypt (gcry_sexp_t *r_plain, + Note that (hash algo) in R_SIG is not used. + */ + gcry_err_code_t +-_gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey) ++_gcry_pk_sign_md (gcry_sexp_t *r_sig, gcry_md_hd_t hd, gcry_sexp_t s_hash, ++ gcry_sexp_t s_skey) + { + gcry_err_code_t rc; + gcry_pk_spec_t *spec; +@@ -426,6 +454,10 @@ _gcry_pk_sign (gcry_sexp_t *r_sig, gcry_ + if (rc) + goto leave; + ++ rc = calculate_hash (hd, &s_hash); ++ if (rc) ++ goto leave; ++ + if (spec->sign) + rc = spec->sign (r_sig, s_hash, keyparms); + else +@@ -437,6 +469,13 @@ _gcry_pk_sign (gcry_sexp_t *r_sig, gcry_ + } + + ++gcry_err_code_t ++_gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey) ++{ ++ return _gcry_pk_sign_md (r_sig, NULL, s_hash, s_skey); ++} ++ ++ + /* + Verify a signature. + +@@ -445,7 +484,8 @@ _gcry_pk_sign (gcry_sexp_t *r_sig, gcry_ + as an S-Exp, sig is a S-Exp as returned from gcry_pk_sign and data + must be an S-Exp like the one in sign too. */ + gcry_err_code_t +-_gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey) ++_gcry_pk_verify_md (gcry_sexp_t s_sig, gcry_md_hd_t hd, gcry_sexp_t s_hash, ++ gcry_sexp_t s_pkey) + { + gcry_err_code_t rc; + gcry_pk_spec_t *spec; +@@ -455,6 +495,10 @@ _gcry_pk_verify (gcry_sexp_t s_sig, gcry + if (rc) + goto leave; + ++ rc = calculate_hash (hd, &s_hash); ++ if (rc) ++ goto leave; ++ + if (spec->verify) + rc = spec->verify (s_sig, s_hash, keyparms); + else +@@ -466,6 +510,13 @@ _gcry_pk_verify (gcry_sexp_t s_sig, gcry + } + + ++gcry_err_code_t ++_gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey) ++{ ++ return _gcry_pk_verify_md (s_sig, NULL, s_hash, s_pkey); ++} ++ ++ + /* + Test a key. + +Index: libgcrypt-1.9.0/cipher/pubkey-internal.h +=================================================================== +--- libgcrypt-1.9.0.orig/cipher/pubkey-internal.h ++++ libgcrypt-1.9.0/cipher/pubkey-internal.h +@@ -43,6 +43,8 @@ void _gcry_pk_util_free_encoding_ctx (st + gcry_err_code_t _gcry_pk_util_data_to_mpi (gcry_sexp_t input, + gcry_mpi_t *ret_mpi, + struct pk_encoding_ctx *ctx); ++gcry_err_code_t _gcry_pk_util_get_algo (gcry_sexp_t input, ++ int *algo); + + + +Index: libgcrypt-1.9.0/cipher/pubkey-util.c +=================================================================== +--- libgcrypt-1.9.0.orig/cipher/pubkey-util.c ++++ libgcrypt-1.9.0/cipher/pubkey-util.c +@@ -1158,3 +1158,50 @@ _gcry_pk_util_data_to_mpi (gcry_sexp_t i + + return rc; + } ++ ++ ++gcry_err_code_t ++_gcry_pk_util_get_algo (gcry_sexp_t input, int *algo) ++{ ++ gcry_err_code_t rc = 0; ++ gcry_sexp_t ldata, list = NULL; ++ const char *s; ++ size_t n; ++ int lalgo; ++ ++ ldata = sexp_find_token (input, "data", 0); ++ if (!ldata) ++ { ++ rc = GPG_ERR_INV_OBJ; ++ goto leave; ++ } ++ ++ list = sexp_find_token (ldata, "hash-algo", 0); ++ if (!list) ++ { ++ rc = GPG_ERR_INV_OBJ; ++ goto leave; ++ } ++ ++ s = sexp_nth_data (list, 1, &n); ++ if (!s) ++ { ++ rc = GPG_ERR_NO_OBJ; ++ goto leave; ++ } ++ ++ lalgo = get_hash_algo (s, n); ++ if (!lalgo) ++ { ++ rc = GPG_ERR_DIGEST_ALGO; ++ goto leave; ++ } ++ ++ *algo = lalgo; ++ ++ leave: ++ sexp_release (ldata); ++ sexp_release (list); ++ ++ return rc; ++} +Index: libgcrypt-1.9.0/src/g10lib.h +=================================================================== +--- libgcrypt-1.9.0.orig/src/g10lib.h ++++ libgcrypt-1.9.0/src/g10lib.h +@@ -299,6 +299,10 @@ gpg_err_code_t _gcry_generate_fips186_3_ + gpg_err_code_t _gcry_fips186_4_prime_check (const gcry_mpi_t x, + unsigned int bits); + ++gcry_err_code_t _gcry_pk_sign_md (gcry_sexp_t *r_sig, gcry_md_hd_t hd, ++ gcry_sexp_t s_hash, gcry_sexp_t s_skey); ++gcry_err_code_t _gcry_pk_verify_md (gcry_sexp_t s_sig, gcry_md_hd_t hd, ++ gcry_sexp_t s_hash, gcry_sexp_t s_pkey); + + /* Replacements of missing functions (missing-string.c). */ + #ifndef HAVE_STPCPY +Index: libgcrypt-1.9.0/src/visibility.c +=================================================================== +--- libgcrypt-1.9.0.orig/src/visibility.c ++++ libgcrypt-1.9.0/src/visibility.c +@@ -992,6 +992,18 @@ gcry_pk_decrypt (gcry_sexp_t *result, gc + } + + gcry_error_t ++gcry_pk_sign_md (gcry_sexp_t *result, gcry_md_hd_t hd, gcry_sexp_t data, ++ gcry_sexp_t skey) ++{ ++ if (!fips_is_operational ()) ++ { ++ *result = NULL; ++ return gpg_error (fips_not_operational ()); ++ } ++ return gpg_error (_gcry_pk_sign_md (result, hd, data, skey)); ++} ++ ++gcry_error_t + gcry_pk_sign (gcry_sexp_t *result, gcry_sexp_t data, gcry_sexp_t skey) + { + if (!fips_is_operational ()) +@@ -1003,6 +1015,15 @@ gcry_pk_sign (gcry_sexp_t *result, gcry_ + } + + gcry_error_t ++gcry_pk_verify_md (gcry_sexp_t sigval, gcry_md_hd_t hd, gcry_sexp_t data, ++ gcry_sexp_t pkey) ++{ ++ if (!fips_is_operational ()) ++ return gpg_error (fips_not_operational ()); ++ return gpg_error (_gcry_pk_verify_md (sigval, hd, data, pkey)); ++} ++ ++gcry_error_t + gcry_pk_verify (gcry_sexp_t sigval, gcry_sexp_t data, gcry_sexp_t pkey) + { + if (!fips_is_operational ()) +Index: libgcrypt-1.9.0/src/visibility.h +=================================================================== +--- libgcrypt-1.9.0.orig/src/visibility.h ++++ libgcrypt-1.9.0/src/visibility.h +@@ -360,8 +360,10 @@ MARK_VISIBLEX (_gcry_mpi_get_const) + #define gcry_pk_get_param _gcry_USE_THE_UNDERSCORED_FUNCTION + #define gcry_pk_get_nbits _gcry_USE_THE_UNDERSCORED_FUNCTION + #define gcry_pk_map_name _gcry_USE_THE_UNDERSCORED_FUNCTION ++#define gcry_pk_sign_md _gcry_USE_THE_UNDERSCORED_FUNCTION + #define gcry_pk_sign _gcry_USE_THE_UNDERSCORED_FUNCTION + #define gcry_pk_testkey _gcry_USE_THE_UNDERSCORED_FUNCTION ++#define gcry_pk_verify_md _gcry_USE_THE_UNDERSCORED_FUNCTION + #define gcry_pk_verify _gcry_USE_THE_UNDERSCORED_FUNCTION + #define gcry_pubkey_get_sexp _gcry_USE_THE_UNDERSCORED_FUNCTION + #define gcry_ecc_get_algo_keylen _gcry_USE_THE_UNDERSCORED_FUNCTION diff --git a/libgcrypt-FIPS-RSA-keylen-tests.patch b/libgcrypt-FIPS-RSA-keylen-tests.patch new file mode 100644 index 0000000..147fc39 --- /dev/null +++ b/libgcrypt-FIPS-RSA-keylen-tests.patch @@ -0,0 +1,585 @@ +From cc3571a1f2244bdf829d7d16dd546131711eb8a9 Mon Sep 17 00:00:00 2001 +From: NIIBE Yutaka +Date: Mon, 8 Nov 2021 13:57:18 +0900 +Subject: tests: Expect errors from algorithms not supported in + FIPS mode. + +* tests/basic.c (FLAG_NOFIPS): New. +(check_pubkey_sign): Pass and handle NOFIPS flag. +(check_pubkey_sign_ecdsa): Likewise. +(check_pubkey_crypt): Likewise. +(do_check_one_pubkey): Pass flags. +(check_pubkey): Mark explicitly algorithms expected not to work in +FIPS mode and make sure they fail. + +-- + +Co-authored-by: NIIBE Yutaka +Signed-off-by: Jakub Jelen +--- + tests/basic.c | 65 ++++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 46 insertions(+), 19 deletions(-) + +Index: libgcrypt-1.9.4/tests/basic.c +=================================================================== +--- libgcrypt-1.9.4.orig/tests/basic.c ++++ libgcrypt-1.9.4/tests/basic.c +@@ -55,9 +55,10 @@ typedef struct test_spec_pubkey + } + test_spec_pubkey_t; + +-#define FLAG_CRYPT (1 << 0) +-#define FLAG_SIGN (1 << 1) +-#define FLAG_GRIP (1 << 2) ++#define FLAG_CRYPT (1 << 0) ++#define FLAG_SIGN (1 << 1) ++#define FLAG_GRIP (1 << 2) ++#define FLAG_NOFIPS (1 << 3) + + static int in_fips_mode; + +@@ -13509,7 +13510,8 @@ verify_one_signature (gcry_sexp_t pkey, + /* Test the public key sign function using the private key SKEY. PKEY + is used for verification. */ + static void +-check_pubkey_sign (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo) ++check_pubkey_sign (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo, ++ int flags) + { + gcry_error_t rc; + gcry_sexp_t sig, badhash, hash; +@@ -13588,6 +13590,7 @@ check_pubkey_sign (int n, gcry_sexp_t sk + if (rc) + die ("converting data failed: %s\n", gpg_strerror (rc)); + ++ sig = NULL; + for (dataidx = 0; datas[dataidx].data; dataidx++) + { + if (datas[dataidx].algo && datas[dataidx].algo != algo) +@@ -13603,12 +13606,19 @@ check_pubkey_sign (int n, gcry_sexp_t sk + die ("converting data failed: %s\n", gpg_strerror (rc)); + + rc = gcry_pk_sign (&sig, hash, skey); ++ if (in_fips_mode && (flags & FLAG_NOFIPS)) ++ { ++ if (!rc) ++ fail ("gcry_pk_sign did not fail as expected in FIPS mode\n"); ++ goto next; ++ } + if (gcry_err_code (rc) != datas[dataidx].expected_rc) + fail ("gcry_pk_sign failed: %s\n", gpg_strerror (rc)); + + if (!rc) + verify_one_signature (pkey, hash, badhash, sig); + ++ next: + gcry_sexp_release (sig); + sig = NULL; + gcry_sexp_release (hash); +@@ -13622,7 +13632,8 @@ check_pubkey_sign (int n, gcry_sexp_t sk + /* Test the public key sign function using the private key SKEY. PKEY + is used for verification. This variant is only used for ECDSA. */ + static void +-check_pubkey_sign_ecdsa (int n, gcry_sexp_t skey, gcry_sexp_t pkey) ++check_pubkey_sign_ecdsa (int n, gcry_sexp_t skey, gcry_sexp_t pkey, ++ int flags) + { + gcry_error_t rc; + gcry_sexp_t sig, badhash, hash; +@@ -13704,6 +13715,7 @@ check_pubkey_sign_ecdsa (int n, gcry_sex + + nbits = gcry_pk_get_nbits (skey); + ++ sig = NULL; + for (dataidx = 0; datas[dataidx].data; dataidx++) + { + if (datas[dataidx].nbits != nbits) +@@ -13723,6 +13735,12 @@ check_pubkey_sign_ecdsa (int n, gcry_sex + die ("converting data failed: %s\n", gpg_strerror (rc)); + + rc = gcry_pk_sign (&sig, hash, skey); ++ if (in_fips_mode && (flags & FLAG_NOFIPS)) ++ { ++ if (!rc) ++ fail ("gcry_pk_sign did not fail as expected in FIPS mode\n"); ++ goto next; ++ } + if (gcry_err_code (rc) != datas[dataidx].expected_rc) + fail ("gcry_pk_sign failed: %s\n", gpg_strerror (rc)); + +@@ -13732,6 +13750,7 @@ check_pubkey_sign_ecdsa (int n, gcry_sex + if (!rc) + verify_one_signature (pkey, hash, badhash, sig); + ++ next: + gcry_sexp_release (sig); + sig = NULL; + gcry_sexp_release (badhash); +@@ -13743,7 +13762,8 @@ check_pubkey_sign_ecdsa (int n, gcry_sex + + + static void +-check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo) ++check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo, ++ int flags) + { + gcry_error_t rc; + gcry_sexp_t plain = NULL; +@@ -13876,6 +13896,12 @@ check_pubkey_crypt (int n, gcry_sexp_t s + die ("converting data failed: %s\n", gpg_strerror (rc)); + + rc = gcry_pk_encrypt (&ciph, data, pkey); ++ if (in_fips_mode && (flags & FLAG_NOFIPS)) ++ { ++ if (!rc) ++ fail ("gcry_pk_encrypt did not fail as expected in FIPS mode\n"); ++ goto next; ++ } + if (gcry_err_code (rc) != datas[dataidx].encrypt_expected_rc) + fail ("gcry_pk_encrypt failed: %s\n", gpg_strerror (rc)); + +@@ -13974,6 +14000,7 @@ check_pubkey_crypt (int n, gcry_sexp_t s + } + } + ++ next: + gcry_sexp_release (plain); + plain = NULL; + gcry_sexp_release (ciph); +@@ -14005,17 +14032,17 @@ static void + do_check_one_pubkey (int n, gcry_sexp_t skey, gcry_sexp_t pkey, + const unsigned char *grip, int algo, int flags) + { +- if (flags & FLAG_SIGN) ++ if ((flags & FLAG_SIGN)) + { + if (algo == GCRY_PK_ECDSA) +- check_pubkey_sign_ecdsa (n, skey, pkey); ++ check_pubkey_sign_ecdsa (n, skey, pkey, flags); + else +- check_pubkey_sign (n, skey, pkey, algo); ++ check_pubkey_sign (n, skey, pkey, algo, flags); + } +- if (flags & FLAG_CRYPT) +- check_pubkey_crypt (n, skey, pkey, algo); +- if (grip && (flags & FLAG_GRIP)) +- check_pubkey_grip (n, grip, skey, pkey, algo); ++ if ((flags & FLAG_CRYPT)) ++ check_pubkey_crypt (n, skey, pkey, algo, flags); ++ if (grip && (flags & FLAG_GRIP)) ++ check_pubkey_grip (n, grip, skey, pkey, algo); + } + + static void +@@ -14089,7 +14116,7 @@ check_pubkey (void) + { + static const test_spec_pubkey_t pubkeys[] = { + { +- GCRY_PK_RSA, FLAG_CRYPT | FLAG_SIGN | FLAG_GRIP, ++ GCRY_PK_RSA, FLAG_CRYPT | FLAG_SIGN | FLAG_GRIP | FLAG_NOFIPS, /* 1k RSA */ + { + "(private-key\n" + " (rsa\n" +@@ -14228,7 +14255,7 @@ check_pubkey (void) + "\x47\xdd\x69\x55\xdb\x3a\xac\x89\x6e\x40"} + }, + { +- GCRY_PK_ELG, FLAG_SIGN | FLAG_CRYPT | FLAG_GRIP, ++ GCRY_PK_ELG, FLAG_SIGN | FLAG_CRYPT | FLAG_GRIP | FLAG_NOFIPS, + { + "(private-key\n" + " (ELG\n" +@@ -14360,7 +14387,7 @@ check_pubkey (void) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" } + }, + { /* GOST R 34.10-2001/2012 test 256 bit. */ +- GCRY_PK_ECDSA, FLAG_SIGN, ++ GCRY_PK_ECDSA, FLAG_SIGN | FLAG_NOFIPS, + { + "(private-key\n" + " (ecc\n" +@@ -14382,7 +14409,7 @@ check_pubkey (void) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" } + }, + { /* GOST R 34.10-2012 test 512 bit. */ +- GCRY_PK_ECDSA, FLAG_SIGN, ++ GCRY_PK_ECDSA, FLAG_SIGN | FLAG_NOFIPS, + { + "(private-key\n" + " (ecc\n" +@@ -14433,7 +14460,7 @@ check_pubkey (void) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" } + }, + { /* sm2 test */ +- GCRY_PK_ECDSA, FLAG_SIGN, ++ GCRY_PK_ECDSA, FLAG_SIGN | FLAG_NOFIPS, + { + "(private-key\n" + " (ecc\n" +From 66119e0c1a024f7cf059393c3db827eb338339b0 Mon Sep 17 00:00:00 2001 +From: NIIBE Yutaka +Date: Thu, 11 Nov 2021 13:03:58 +0900 +Subject: tests:pubkey: Replace RSA key to one of 2k. + +* tests/pubkey.c (sample_private_key_1): Use 2k key from basic.c. +(sample_private_key_1_1): Likewise. +(sample_private_key_1_2): Likewise. + +-- + +GnuPG-bug-id: 5512 +Signed-off-by: NIIBE Yutaka +--- + tests/pubkey.c | 126 ++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 88 insertions(+), 38 deletions(-) + +diff --git a/tests/pubkey.c b/tests/pubkey.c +index 8a482dc3..51ef0f51 100644 +--- a/tests/pubkey.c ++++ b/tests/pubkey.c +@@ -36,21 +36,40 @@ static int in_fips_mode; + static const char sample_private_key_1[] = + "(private-key\n" + " (openpgp-rsa\n" +-" (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa" +- "2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291" +- "ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7" +- "891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)\n" ++" (n #009F56231A3D82E3E7D613D59D53E9AB921BEF9F08A782AED0B6E46ADBC853EC" ++" 7C71C422435A3CD8FA0DB9EFD55CD3295BADC4E8E2E2B94E15AE82866AB8ADE8" ++" 7E469FAE76DC3577DE87F1F419C4EB41123DFAF8D16922D5EDBAD6E9076D5A1C" ++" 958106F0AE5E2E9193C6B49124C64C2A241C4075D4AF16299EB87A6585BAE917" ++" DEF27FCDD165764D069BC18D16527B29DAAB549F7BBED4A7C6A842D203ED6613" ++" 6E2411744E432CD26D940132F25874483DCAEECDFD95744819CBCF1EA810681C" ++" 42907EBCB1C7EAFBE75C87EC32C5413EA10476545D3FC7B2ADB1B66B7F200918" ++" 664B0E5261C2895AA28B0DE321E921B3F877172CCCAB81F43EF98002916156F6" ++" CB#)\n" + " (e #010001#)\n" +-" (d #046129F2489D71579BE0A75FE029BD6CDB574EBF57EA8A5B0FDA942CAB943B11" +- "7D7BB95E5D28875E0F9FC5FCC06A72F6D502464DABDED78EF6B716177B83D5BD" +- "C543DC5D3FED932E59F5897E92E6F58A0F33424106A3B6FA2CBF877510E4AC21" +- "C3EE47851E97D12996222AC3566D4CCB0B83D164074ABF7DE655FC2446DA1781#)\n" +-" (p #00e861b700e17e8afe6837e7512e35b6ca11d0ae47d8b85161c67baf64377213" +- "fe52d772f2035b3ca830af41d8a4120e1c1c70d12cc22f00d28d31dd48a8d424f1#)\n" +-" (q #00f7a7ca5367c661f8e62df34f0d05c10c88e5492348dd7bddc942c9a8f369f9" +- "35a07785d2db805215ed786e4285df1658eed3ce84f469b81b50d358407b4ad361#)\n" +-" (u #304559a9ead56d2309d203811a641bb1a09626bc8eb36fffa23c968ec5bd891e" +- "ebbafc73ae666e01ba7c8990bae06cc2bbe10b75e69fcacb353a6473079d8e9b#)\n" ++" (d #07EF82500C403899934FE993AC5A36F14FF2DF38CF1EF315F205EE4C83EDAA19" ++" 8890FC23DE9AA933CAFB37B6A8A8DBA675411958337287310D3FF2F1DDC0CB93" ++" 7E70F57F75F833C021852B631D2B9A520E4431A03C5C3FCB5742DCD841D9FB12" ++" 771AA1620DCEC3F1583426066ED9DC3F7028C5B59202C88FDF20396E2FA0EC4F" ++" 5A22D9008F3043673931BC14A5046D6327398327900867E39CC61B2D1AFE2F48" ++" EC8E1E3861C68D257D7425F4E6F99ABD77D61F10CA100EFC14389071831B33DD" ++" 69CC8EABEF860D1DC2AAA84ABEAE5DFC91BC124DAF0F4C8EF5BBEA436751DE84" ++" 3A8063E827A024466F44C28614F93B0732A100D4A0D86D532FE1E22C7725E401" ++" #)\n" ++" (p #00C29D438F115825779631CD665A5739367F3E128ADC29766483A46CA80897E0" ++" 79B32881860B8F9A6A04C2614A904F6F2578DAE13EA67CD60AE3D0AA00A1FF9B" ++" 441485E44B2DC3D0B60260FBFE073B5AC72FAF67964DE15C8212C389D20DB9CF" ++" 54AF6AEF5C4196EAA56495DD30CF709F499D5AB30CA35E086C2A1589D6283F17" ++" 83#)\n" ++" (q #00D1984135231CB243FE959C0CBEF551EDD986AD7BEDF71EDF447BE3DA27AF46" ++" 79C974A6FA69E4D52FE796650623DE70622862713932AA2FD9F2EC856EAEAA77" ++" 88B4EA6084DC81C902F014829B18EA8B2666EC41586818E0589E18876065F97E" ++" 8D22CE2DA53A05951EC132DCEF41E70A9C35F4ACC268FFAC2ADF54FA1DA110B9" ++" 19#)\n" ++" (u #67CF0FD7635205DD80FA814EE9E9C267C17376BF3209FB5D1BC42890D2822A04" ++" 479DAF4D5B6ED69D0F8D1AF94164D07F8CD52ECEFE880641FA0F41DDAB1785E4" ++" A37A32F997A516480B4CD4F6482B9466A1765093ED95023CA32D5EDC1E34CEE9" ++" AF595BC51FE43C4BF810FA225AF697FB473B83815966188A4312C048B885E3F7" ++" #)\n" + " )\n" + ")\n"; + +@@ -58,15 +77,25 @@ static const char sample_private_key_1[] = + static const char sample_private_key_1_1[] = + "(private-key\n" + " (openpgp-rsa\n" +-" (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa" +- "2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291" +- "ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7" +- "891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)\n" ++" (n #009F56231A3D82E3E7D613D59D53E9AB921BEF9F08A782AED0B6E46ADBC853EC" ++" 7C71C422435A3CD8FA0DB9EFD55CD3295BADC4E8E2E2B94E15AE82866AB8ADE8" ++" 7E469FAE76DC3577DE87F1F419C4EB41123DFAF8D16922D5EDBAD6E9076D5A1C" ++" 958106F0AE5E2E9193C6B49124C64C2A241C4075D4AF16299EB87A6585BAE917" ++" DEF27FCDD165764D069BC18D16527B29DAAB549F7BBED4A7C6A842D203ED6613" ++" 6E2411744E432CD26D940132F25874483DCAEECDFD95744819CBCF1EA810681C" ++" 42907EBCB1C7EAFBE75C87EC32C5413EA10476545D3FC7B2ADB1B66B7F200918" ++" 664B0E5261C2895AA28B0DE321E921B3F877172CCCAB81F43EF98002916156F6" ++" CB#)\n" + " (e #010001#)\n" +-" (d #046129F2489D71579BE0A75FE029BD6CDB574EBF57EA8A5B0FDA942CAB943B11" +- "7D7BB95E5D28875E0F9FC5FCC06A72F6D502464DABDED78EF6B716177B83D5BD" +- "C543DC5D3FED932E59F5897E92E6F58A0F33424106A3B6FA2CBF877510E4AC21" +- "C3EE47851E97D12996222AC3566D4CCB0B83D164074ABF7DE655FC2446DA1781#)\n" ++" (d #07EF82500C403899934FE993AC5A36F14FF2DF38CF1EF315F205EE4C83EDAA19" ++" 8890FC23DE9AA933CAFB37B6A8A8DBA675411958337287310D3FF2F1DDC0CB93" ++" 7E70F57F75F833C021852B631D2B9A520E4431A03C5C3FCB5742DCD841D9FB12" ++" 771AA1620DCEC3F1583426066ED9DC3F7028C5B59202C88FDF20396E2FA0EC4F" ++" 5A22D9008F3043673931BC14A5046D6327398327900867E39CC61B2D1AFE2F48" ++" EC8E1E3861C68D257D7425F4E6F99ABD77D61F10CA100EFC14389071831B33DD" ++" 69CC8EABEF860D1DC2AAA84ABEAE5DFC91BC124DAF0F4C8EF5BBEA436751DE84" ++" 3A8063E827A024466F44C28614F93B0732A100D4A0D86D532FE1E22C7725E401" ++" #)\n" + " )\n" + ")\n"; + +@@ -75,29 +104,50 @@ static const char sample_private_key_1_1[] = + static const char sample_private_key_1_2[] = + "(private-key\n" + " (openpgp-rsa\n" +-" (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa" +- "2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291" +- "ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7" +- "891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)\n" ++" (n #009F56231A3D82E3E7D613D59D53E9AB921BEF9F08A782AED0B6E46ADBC853EC" ++" 7C71C422435A3CD8FA0DB9EFD55CD3295BADC4E8E2E2B94E15AE82866AB8ADE8" ++" 7E469FAE76DC3577DE87F1F419C4EB41123DFAF8D16922D5EDBAD6E9076D5A1C" ++" 958106F0AE5E2E9193C6B49124C64C2A241C4075D4AF16299EB87A6585BAE917" ++" DEF27FCDD165764D069BC18D16527B29DAAB549F7BBED4A7C6A842D203ED6613" ++" 6E2411744E432CD26D940132F25874483DCAEECDFD95744819CBCF1EA810681C" ++" 42907EBCB1C7EAFBE75C87EC32C5413EA10476545D3FC7B2ADB1B66B7F200918" ++" 664B0E5261C2895AA28B0DE321E921B3F877172CCCAB81F43EF98002916156F6" ++" CB#)\n" + " (e #010001#)\n" +-" (d #046129F2489D71579BE0A75FE029BD6CDB574EBF57EA8A5B0FDA942CAB943B11" +- "7D7BB95E5D28875E0F9FC5FCC06A72F6D502464DABDED78EF6B716177B83D5BD" +- "C543DC5D3FED932E59F5897E92E6F58A0F33424106A3B6FA2CBF877510E4AC21" +- "C3EE47851E97D12996222AC3566D4CCB0B83D164074ABF7DE655FC2446DA1781#)\n" +-" (p #00e861b700e17e8afe6837e7512e35b6ca11d0ae47d8b85161c67baf64377213" +- "fe52d772f2035b3ca830af41d8a4120e1c1c70d12cc22f00d28d31dd48a8d424f1#)\n" +-" (u #304559a9ead56d2309d203811a641bb1a09626bc8eb36fffa23c968ec5bd891e" +- "ebbafc73ae666e01ba7c8990bae06cc2bbe10b75e69fcacb353a6473079d8e9b#)\n" ++" (d #07EF82500C403899934FE993AC5A36F14FF2DF38CF1EF315F205EE4C83EDAA19" ++" 8890FC23DE9AA933CAFB37B6A8A8DBA675411958337287310D3FF2F1DDC0CB93" ++" 7E70F57F75F833C021852B631D2B9A520E4431A03C5C3FCB5742DCD841D9FB12" ++" 771AA1620DCEC3F1583426066ED9DC3F7028C5B59202C88FDF20396E2FA0EC4F" ++" 5A22D9008F3043673931BC14A5046D6327398327900867E39CC61B2D1AFE2F48" ++" EC8E1E3861C68D257D7425F4E6F99ABD77D61F10CA100EFC14389071831B33DD" ++" 69CC8EABEF860D1DC2AAA84ABEAE5DFC91BC124DAF0F4C8EF5BBEA436751DE84" ++" 3A8063E827A024466F44C28614F93B0732A100D4A0D86D532FE1E22C7725E401" ++" #)\n" ++" (p #00C29D438F115825779631CD665A5739367F3E128ADC29766483A46CA80897E0" ++" 79B32881860B8F9A6A04C2614A904F6F2578DAE13EA67CD60AE3D0AA00A1FF9B" ++" 441485E44B2DC3D0B60260FBFE073B5AC72FAF67964DE15C8212C389D20DB9CF" ++" 54AF6AEF5C4196EAA56495DD30CF709F499D5AB30CA35E086C2A1589D6283F17" ++" 83#)\n" ++" (u #67CF0FD7635205DD80FA814EE9E9C267C17376BF3209FB5D1BC42890D2822A04" ++" 479DAF4D5B6ED69D0F8D1AF94164D07F8CD52ECEFE880641FA0F41DDAB1785E4" ++" A37A32F997A516480B4CD4F6482B9466A1765093ED95023CA32D5EDC1E34CEE9" ++" AF595BC51FE43C4BF810FA225AF697FB473B83815966188A4312C048B885E3F7" ++" #)\n" + " )\n" + ")\n"; + + static const char sample_public_key_1[] = + "(public-key\n" + " (rsa\n" +-" (n #00e0ce96f90b6c9e02f3922beada93fe50a875eac6bcc18bb9a9cf2e84965caa" +- "2d1ff95a7f542465c6c0c19d276e4526ce048868a7a914fd343cc3a87dd74291" +- "ffc565506d5bbb25cbac6a0e2dd1f8bcaab0d4a29c2f37c950f363484bf269f7" +- "891440464baf79827e03a36e70b814938eebdc63e964247be75dc58b014b7ea251#)\n" ++" (n #009F56231A3D82E3E7D613D59D53E9AB921BEF9F08A782AED0B6E46ADBC853EC" ++" 7C71C422435A3CD8FA0DB9EFD55CD3295BADC4E8E2E2B94E15AE82866AB8ADE8" ++" 7E469FAE76DC3577DE87F1F419C4EB41123DFAF8D16922D5EDBAD6E9076D5A1C" ++" 958106F0AE5E2E9193C6B49124C64C2A241C4075D4AF16299EB87A6585BAE917" ++" DEF27FCDD165764D069BC18D16527B29DAAB549F7BBED4A7C6A842D203ED6613" ++" 6E2411744E432CD26D940132F25874483DCAEECDFD95744819CBCF1EA810681C" ++" 42907EBCB1C7EAFBE75C87EC32C5413EA10476545D3FC7B2ADB1B66B7F200918" ++" 664B0E5261C2895AA28B0DE321E921B3F877172CCCAB81F43EF98002916156F6" ++" CB#)\n" + " (e #010001#)\n" + " )\n" + ")\n"; +-- +2.33.1 + +From 1481607cb9db977468a75f9f4638dc1cf3ade007 Mon Sep 17 00:00:00 2001 +From: NIIBE Yutaka +Date: Thu, 11 Nov 2021 13:44:40 +0900 +Subject: tests:pkcs1v2: Skip tests with small keys in FIPS + mode. + +* tests/pkcs1v2.c (in_fips_mode): New. +(check_oaep): Skip when key size is less than 2048 in FIPS mode. +(check_pss, check_v15crypt, check_v15sign): Likewise. + +-- + +GnuPG-bug-id: 5512 +Signed-off-by: NIIBE Yutaka +--- + tests/pkcs1v2.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 75 insertions(+), 3 deletions(-) + +diff --git a/tests/pkcs1v2.c b/tests/pkcs1v2.c +index 968d3fea..f26e779b 100644 +--- a/tests/pkcs1v2.c ++++ b/tests/pkcs1v2.c +@@ -36,6 +36,8 @@ + #include "t-common.h" + + ++static int in_fips_mode; ++ + static void + show_sexp (const char *prefix, gcry_sexp_t a) + { +@@ -147,6 +149,18 @@ check_oaep (void) + gcry_free (rsa_e); + gcry_free (rsa_d); + ++ if (in_fips_mode) ++ { ++ unsigned int nbits = gcry_pk_get_nbits (pub_key); ++ ++ if (nbits < 2048) ++ { ++ if (verbose > 1) ++ info ("... skipped\n"); ++ goto next; ++ } ++ } ++ + for (mno = 0; mno < DIM (tbl[0].m); mno++) + { + void *mesg, *seed, *encr; +@@ -225,6 +239,7 @@ check_oaep (void) + ciph = NULL; + } + ++ next: + gcry_sexp_release (sec_key); + gcry_sexp_release (pub_key); + } +@@ -269,6 +284,18 @@ check_pss (void) + gcry_free (rsa_e); + gcry_free (rsa_d); + ++ if (in_fips_mode) ++ { ++ unsigned int nbits = gcry_pk_get_nbits (pub_key); ++ ++ if (nbits < 2048) ++ { ++ if (verbose > 1) ++ info ("... skipped\n"); ++ goto next; ++ } ++ } ++ + for (mno = 0; mno < DIM (tbl[0].m); mno++) + { + void *mesg, *salt, *sign; +@@ -347,6 +374,7 @@ check_pss (void) + sigtmpl = NULL; + } + ++ next: + gcry_sexp_release (sec_key); + gcry_sexp_release (pub_key); + } +@@ -391,6 +419,18 @@ check_v15crypt (void) + gcry_free (rsa_e); + gcry_free (rsa_d); + ++ if (in_fips_mode) ++ { ++ unsigned int nbits = gcry_pk_get_nbits (pub_key); ++ ++ if (nbits < 2048) ++ { ++ if (verbose > 1) ++ info ("... skipped\n"); ++ goto next; ++ } ++ } ++ + for (mno = 0; mno < DIM (tbl[0].m); mno++) + { + void *mesg, *seed, *encr; +@@ -469,6 +509,7 @@ check_v15crypt (void) + ciph = NULL; + } + ++ next: + gcry_sexp_release (sec_key); + gcry_sexp_release (pub_key); + } +@@ -513,6 +554,18 @@ check_v15sign (void) + gcry_free (rsa_e); + gcry_free (rsa_d); + ++ if (in_fips_mode) ++ { ++ unsigned int nbits = gcry_pk_get_nbits (pub_key); ++ ++ if (nbits < 2048) ++ { ++ if (verbose > 1) ++ info ("... skipped\n"); ++ goto next; ++ } ++ } ++ + for (mno = 0; mno < DIM (tbl[0].m); mno++) + { + void *mesg, *sign; +@@ -583,6 +636,7 @@ check_v15sign (void) + sigtmpl = NULL; + } + ++ next: + gcry_sexp_release (sec_key); + gcry_sexp_release (pub_key); + } +@@ -597,6 +651,7 @@ main (int argc, char **argv) + int run_pss = 0; + int run_v15c = 0; + int run_v15s = 0; ++ int use_fips = 0; + + if (argc) + { argc--; argv++; } +@@ -625,6 +680,11 @@ main (int argc, char **argv) + die_on_error = 1; + argc--; argv++; + } ++ else if (!strcmp (*argv, "--fips")) ++ { ++ use_fips = 1; ++ argc--; argv++; ++ } + else if (!strcmp (*argv, "--oaep")) + { + run_oaep = 1; +@@ -651,9 +711,21 @@ main (int argc, char **argv) + run_oaep = run_pss = run_v15c = run_v15s = 1; + + xgcry_control ((GCRYCTL_SET_VERBOSITY, (int)verbose)); +- xgcry_control ((GCRYCTL_DISABLE_SECMEM, 0)); +- if (!gcry_check_version ("1.5.0")) +- die ("version mismatch\n"); ++ ++ if (use_fips) ++ xgcry_control ((GCRYCTL_FORCE_FIPS_MODE, 0)); ++ ++ /* Check that we test exactly our version - including the patchlevel. */ ++ if (strcmp (GCRYPT_VERSION, gcry_check_version (NULL))) ++ die ("version mismatch; pgm=%s, library=%s\n", ++ GCRYPT_VERSION,gcry_check_version (NULL)); ++ ++ if ( gcry_fips_mode_active () ) ++ in_fips_mode = 1; ++ ++ if (!in_fips_mode) ++ xgcry_control ((GCRYCTL_DISABLE_SECMEM, 0)); ++ + xgcry_control ((GCRYCTL_INITIALIZATION_FINISHED, 0)); + if (debug) + xgcry_control ((GCRYCTL_SET_DEBUG_FLAGS, 1u, 0)); +-- +2.33.1 + diff --git a/libgcrypt-FIPS-RSA-keylen.patch b/libgcrypt-FIPS-RSA-keylen.patch new file mode 100644 index 0000000..6c1034d --- /dev/null +++ b/libgcrypt-FIPS-RSA-keylen.patch @@ -0,0 +1,250 @@ +From 40d63d09b2d06631f4d2c3d1b167a620d50c99f8 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Fri, 5 Nov 2021 14:19:23 +0100 +Subject: [PATCH 198/200] rsa: Check keylen constraints for key operations. + +* cipher/rsa.c (rsa_check_keysize): New. +(generate_fips): Factor out the bits check. +(rsa_encrypt): Add checking key length. +(rsa_decrypt, rsa_sign, rsa_verify): Likewise. +-- + +GnuPG-bug-id: 5512 +Co-authored-by: NIIBE Yutaka +Signed-off-by: Jakub Jelen +--- + cipher/rsa.c | 58 ++++++++++++++++++++++++++++++++++++++-------------- + 1 file changed, 43 insertions(+), 15 deletions(-) + +Index: libgcrypt-1.9.4/cipher/rsa.c +=================================================================== +--- libgcrypt-1.9.4.orig/cipher/rsa.c ++++ libgcrypt-1.9.4/cipher/rsa.c +@@ -301,14 +301,6 @@ generate_std (RSA_secret_key *sk, unsign + gcry_mpi_t f; + gcry_random_level_t random_level; + +- if (fips_mode ()) +- { +- if (nbits < 1024) +- return GPG_ERR_INV_VALUE; +- if (transient_key) +- return GPG_ERR_INV_VALUE; +- } +- + /* The random quality depends on the transient_key flag. */ + random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM; + +@@ -437,6 +429,17 @@ generate_std (RSA_secret_key *sk, unsign + } + + ++/* Check the RSA key length is acceptable for key generation or usage */ ++static gpg_err_code_t ++rsa_check_keysize (unsigned int nbits) ++{ ++ if (fips_mode() && nbits < 2048) ++ return GPG_ERR_INV_VALUE; ++ ++ return GPG_ERR_NO_ERROR; ++} ++ ++ + /**************** + * Generate a key pair with a key of size NBITS. + * USE_E = 0 let Libcgrypt decide what exponent to use. +@@ -466,12 +469,15 @@ generate_fips (RSA_secret_key *sk, unsig + unsigned int pbits = nbits/2; + unsigned int i; + int pqswitch; +- gpg_err_code_t ec = GPG_ERR_NO_PRIME; ++ gpg_err_code_t ec; + + if (nbits < 1024 || (nbits & 0x1FF)) + return GPG_ERR_INV_VALUE; +- if (fips_mode() && nbits < 2048) +- return GPG_ERR_INV_VALUE; ++ ec = rsa_check_keysize (nbits); ++ if (ec) ++ return ec; ++ ++ ec = GPG_ERR_NO_PRIME; + + /* The random quality depends on the transient_key flag. */ + random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM; +@@ -1360,9 +1366,13 @@ rsa_encrypt (gcry_sexp_t *r_ciph, gcry_s + gcry_mpi_t data = NULL; + RSA_public_key pk = {NULL, NULL}; + gcry_mpi_t ciph = NULL; ++ unsigned int nbits = rsa_get_nbits (keyparms); ++ ++ rc = rsa_check_keysize (nbits); ++ if (rc) ++ return rc; + +- _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT, +- rsa_get_nbits (keyparms)); ++ _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT, nbits); + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); +@@ -1432,9 +1442,13 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_ + gcry_mpi_t plain = NULL; + unsigned char *unpad = NULL; + size_t unpadlen = 0; ++ unsigned int nbits = rsa_get_nbits (keyparms); + +- _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, +- rsa_get_nbits (keyparms)); ++ rc = rsa_check_keysize (nbits); ++ if (rc) ++ return rc; ++ ++ _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, nbits); + + /* Extract the data. */ + rc = _gcry_pk_util_preparse_encval (s_data, rsa_names, &l1, &ctx); +@@ -1477,7 +1491,7 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_ + mpi_fdiv_r (data, data, sk.n); + + /* Allocate MPI for the plaintext. */ +- plain = mpi_snew (ctx.nbits); ++ plain = mpi_snew (nbits); + + /* We use blinding by default to mitigate timing attacks which can + be practically mounted over the network as shown by Brumley and +@@ -1485,7 +1499,7 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_ + if ((ctx.flags & PUBKEY_FLAG_NO_BLINDING)) + secret (plain, data, &sk); + else +- secret_blinded (plain, data, &sk, ctx.nbits); ++ secret_blinded (plain, data, &sk, nbits); + + if (DBG_CIPHER) + log_printmpi ("rsa_decrypt res", plain); +@@ -1494,7 +1508,7 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_ + switch (ctx.encoding) + { + case PUBKEY_ENC_PKCS1: +- rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, ctx.nbits, plain); ++ rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, nbits, plain); + mpi_free (plain); + plain = NULL; + if (!rc) +@@ -1503,7 +1517,7 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_ + + case PUBKEY_ENC_OAEP: + rc = _gcry_rsa_oaep_decode (&unpad, &unpadlen, +- ctx.nbits, ctx.hash_algo, ++ nbits, ctx.hash_algo, + plain, ctx.label, ctx.labellen); + mpi_free (plain); + plain = NULL; +@@ -1548,9 +1562,13 @@ rsa_sign (gcry_sexp_t *r_sig, gcry_sexp_ + RSA_public_key pk; + gcry_mpi_t sig = NULL; + gcry_mpi_t result = NULL; ++ unsigned int nbits = rsa_get_nbits (keyparms); ++ ++ rc = rsa_check_keysize (nbits); ++ if (rc) ++ return rc; + +- _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN, +- rsa_get_nbits (keyparms)); ++ _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN, nbits); + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); +@@ -1588,7 +1606,7 @@ rsa_sign (gcry_sexp_t *r_sig, gcry_sexp_ + if ((ctx.flags & PUBKEY_FLAG_NO_BLINDING)) + secret (sig, data, &sk); + else +- secret_blinded (sig, data, &sk, ctx.nbits); ++ secret_blinded (sig, data, &sk, nbits); + if (DBG_CIPHER) + log_printmpi ("rsa_sign res", sig); + +@@ -1650,9 +1668,13 @@ rsa_verify (gcry_sexp_t s_sig, gcry_sexp + gcry_mpi_t data = NULL; + RSA_public_key pk = { NULL, NULL }; + gcry_mpi_t result = NULL; ++ unsigned int nbits = rsa_get_nbits (keyparms); ++ ++ rc = rsa_check_keysize (nbits); ++ if (rc) ++ return rc; + +- _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY, +- rsa_get_nbits (keyparms)); ++ _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY, nbits); + + /* Extract the data. */ + rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx); +Index: libgcrypt-1.9.4/tests/basic.c +=================================================================== +--- libgcrypt-1.9.4.orig/tests/basic.c ++++ libgcrypt-1.9.4/tests/basic.c +@@ -14172,6 +14172,62 @@ check_pubkey (void) + "\x4a\xa6\xf9\xeb\x23\xbf\xa9\x12\x2d\x5b" } + }, + { ++ GCRY_PK_RSA, FLAG_CRYPT | FLAG_SIGN | FLAG_GRIP, /* 2k RSA */ ++ { ++ "(private-key" ++ " (rsa" ++ " (n #009F56231A3D82E3E7D613D59D53E9AB921BEF9F08A782AED0B6E46ADBC853EC" ++ " 7C71C422435A3CD8FA0DB9EFD55CD3295BADC4E8E2E2B94E15AE82866AB8ADE8" ++ " 7E469FAE76DC3577DE87F1F419C4EB41123DFAF8D16922D5EDBAD6E9076D5A1C" ++ " 958106F0AE5E2E9193C6B49124C64C2A241C4075D4AF16299EB87A6585BAE917" ++ " DEF27FCDD165764D069BC18D16527B29DAAB549F7BBED4A7C6A842D203ED6613" ++ " 6E2411744E432CD26D940132F25874483DCAEECDFD95744819CBCF1EA810681C" ++ " 42907EBCB1C7EAFBE75C87EC32C5413EA10476545D3FC7B2ADB1B66B7F200918" ++ " 664B0E5261C2895AA28B0DE321E921B3F877172CCCAB81F43EF98002916156F6" ++ " CB#)\n" ++ " (e #010001#)\n" ++ " (d #07EF82500C403899934FE993AC5A36F14FF2DF38CF1EF315F205EE4C83EDAA19" ++ " 8890FC23DE9AA933CAFB37B6A8A8DBA675411958337287310D3FF2F1DDC0CB93" ++ " 7E70F57F75F833C021852B631D2B9A520E4431A03C5C3FCB5742DCD841D9FB12" ++ " 771AA1620DCEC3F1583426066ED9DC3F7028C5B59202C88FDF20396E2FA0EC4F" ++ " 5A22D9008F3043673931BC14A5046D6327398327900867E39CC61B2D1AFE2F48" ++ " EC8E1E3861C68D257D7425F4E6F99ABD77D61F10CA100EFC14389071831B33DD" ++ " 69CC8EABEF860D1DC2AAA84ABEAE5DFC91BC124DAF0F4C8EF5BBEA436751DE84" ++ " 3A8063E827A024466F44C28614F93B0732A100D4A0D86D532FE1E22C7725E401" ++ " #)\n" ++ " (p #00C29D438F115825779631CD665A5739367F3E128ADC29766483A46CA80897E0" ++ " 79B32881860B8F9A6A04C2614A904F6F2578DAE13EA67CD60AE3D0AA00A1FF9B" ++ " 441485E44B2DC3D0B60260FBFE073B5AC72FAF67964DE15C8212C389D20DB9CF" ++ " 54AF6AEF5C4196EAA56495DD30CF709F499D5AB30CA35E086C2A1589D6283F17" ++ " 83#)\n" ++ " (q #00D1984135231CB243FE959C0CBEF551EDD986AD7BEDF71EDF447BE3DA27AF46" ++ " 79C974A6FA69E4D52FE796650623DE70622862713932AA2FD9F2EC856EAEAA77" ++ " 88B4EA6084DC81C902F014829B18EA8B2666EC41586818E0589E18876065F97E" ++ " 8D22CE2DA53A05951EC132DCEF41E70A9C35F4ACC268FFAC2ADF54FA1DA110B9" ++ " 19#)\n" ++ " (u #67CF0FD7635205DD80FA814EE9E9C267C17376BF3209FB5D1BC42890D2822A04" ++ " 479DAF4D5B6ED69D0F8D1AF94164D07F8CD52ECEFE880641FA0F41DDAB1785E4" ++ " A37A32F997A516480B4CD4F6482B9466A1765093ED95023CA32D5EDC1E34CEE9" ++ " AF595BC51FE43C4BF810FA225AF697FB473B83815966188A4312C048B885E3F7" ++ " #)))\n", ++ ++ "(public-key\n" ++ " (rsa\n" ++ " (n #009F56231A3D82E3E7D613D59D53E9AB921BEF9F08A782AED0B6E46ADBC853EC" ++ " 7C71C422435A3CD8FA0DB9EFD55CD3295BADC4E8E2E2B94E15AE82866AB8ADE8" ++ " 7E469FAE76DC3577DE87F1F419C4EB41123DFAF8D16922D5EDBAD6E9076D5A1C" ++ " 958106F0AE5E2E9193C6B49124C64C2A241C4075D4AF16299EB87A6585BAE917" ++ " DEF27FCDD165764D069BC18D16527B29DAAB549F7BBED4A7C6A842D203ED6613" ++ " 6E2411744E432CD26D940132F25874483DCAEECDFD95744819CBCF1EA810681C" ++ " 42907EBCB1C7EAFBE75C87EC32C5413EA10476545D3FC7B2ADB1B66B7F200918" ++ " 664B0E5261C2895AA28B0DE321E921B3F877172CCCAB81F43EF98002916156F6" ++ " CB#)\n" ++ " (e #010001#)))\n", ++ ++ "\xe0\x08\x98\x9b\xb6\x44\xa2\x9a\x83\x37" ++ "\x47\xdd\x69\x55\xdb\x3a\xac\x89\x6e\x40"} ++ }, ++ { + GCRY_PK_ELG, FLAG_SIGN | FLAG_CRYPT | FLAG_GRIP, + { + "(private-key\n" diff --git a/libgcrypt-FIPS-SLI-pk.patch b/libgcrypt-FIPS-SLI-pk.patch new file mode 100644 index 0000000..ab59a52 --- /dev/null +++ b/libgcrypt-FIPS-SLI-pk.patch @@ -0,0 +1,160 @@ +Index: libgcrypt-1.9.4/src/fips.c +=================================================================== +--- libgcrypt-1.9.4.orig/src/fips.c ++++ libgcrypt-1.9.4/src/fips.c +@@ -32,6 +32,7 @@ + + #include "g10lib.h" + #include "cipher-proto.h" ++#include "cipher.h" + #include "hmac256.h" + + +@@ -482,6 +483,78 @@ _gcry_fips_indicator_kdf (va_list arg_pt + default: + return GPG_ERR_NOT_SUPPORTED; + } ++} ++ ++ ++/* FIPS approved curves, extracted from: ++ * cipher/ecc-curves.c:curve_aliases[] and domain_parms[]. */ ++static const struct ++{ ++ const char *name; /* Our name. */ ++ const char *other; /* Other name. */ ++} fips_approved_curve[] = ++ { ++ /* "NIST P-192" is non-approved if FIPS 140-3 */ ++ /* { "NIST P-192", "1.2.840.10045.3.1.1" }, /\* X9.62 OID *\/ */ ++ /* { "NIST P-192", "prime192v1" }, /\* X9.62 name. *\/ */ ++ /* { "NIST P-192", "secp192r1" }, /\* SECP name. *\/ */ ++ /* { "NIST P-192", "nistp192" }, /\* rfc5656. *\/ */ ++ ++ { "NIST P-224", "secp224r1" }, ++ { "NIST P-224", "1.3.132.0.33" }, /* SECP OID. */ ++ { "NIST P-224", "nistp224" }, /* rfc5656. */ ++ ++ { "NIST P-256", "1.2.840.10045.3.1.7" }, /* From NIST SP 800-78-1. */ ++ { "NIST P-256", "prime256v1" }, ++ { "NIST P-256", "secp256r1" }, ++ { "NIST P-256", "nistp256" }, /* rfc5656. */ ++ ++ { "NIST P-384", "secp384r1" }, ++ { "NIST P-384", "1.3.132.0.34" }, ++ { "NIST P-384", "nistp384" }, /* rfc5656. */ ++ ++ { "NIST P-521", "secp521r1" }, ++ { "NIST P-521", "1.3.132.0.35" }, ++ { "NIST P-521", "nistp521" }, /* rfc5656. */ ++ { NULL, NULL} ++ }; ++ ++int ++_gcry_fips_indicator_pk (va_list arg_ptr) ++{ ++ enum gcry_pk_algos alg = va_arg (arg_ptr, enum gcry_pk_algos); ++ enum pk_operation oper; ++ const char *curve_name; ++ ++ switch (alg) ++ { ++ case GCRY_PK_RSA: ++ case GCRY_PK_RSA_E: ++ case GCRY_PK_RSA_S: ++ oper = va_arg (arg_ptr, enum pk_operation); ++ switch (oper) ++ { ++ case PUBKEY_OP_ENCRYPT: ++ case PUBKEY_OP_DECRYPT: ++ return GPG_ERR_NOT_SUPPORTED; ++ default: ++ return GPG_ERR_NO_ERROR; ++ } ++ case GCRY_PK_ECC: ++ case GCRY_PK_ECDH: ++ case GCRY_PK_ECDSA: ++ curve_name = va_arg (arg_ptr, const char *); ++ for (int idx = 0; fips_approved_curve[idx].name; ++idx) ++ { ++ /* Check for the usual name and an alias. */ ++ if (!strcmp (curve_name, fips_approved_curve[idx].name) || ++ !strcmp (curve_name, fips_approved_curve[idx].other)) ++ return GPG_ERR_NO_ERROR; ++ } ++ return GPG_ERR_NOT_SUPPORTED; ++ default: ++ return GPG_ERR_NOT_SUPPORTED; ++ } + } + + +Index: libgcrypt-1.9.4/src/gcrypt.h.in +=================================================================== +--- libgcrypt-1.9.4.orig/src/gcrypt.h.in ++++ libgcrypt-1.9.4/src/gcrypt.h.in +@@ -336,7 +336,8 @@ enum gcry_ctl_cmds + GCRYCTL_AUTO_EXPAND_SECMEM = 78, + GCRYCTL_SET_ALLOW_WEAK_KEY = 79, + GCRYCTL_FIPS_SERVICE_INDICATOR_CIPHER = 81, +- GCRYCTL_FIPS_SERVICE_INDICATOR_KDF = 82 ++ GCRYCTL_FIPS_SERVICE_INDICATOR_KDF = 82, ++ GCRYCTL_FIPS_SERVICE_INDICATOR_PK = 83 + }; + + /* Perform various operations defined by CMD. */ +Index: libgcrypt-1.9.4/doc/gcrypt.texi +=================================================================== +--- libgcrypt-1.9.4.orig/doc/gcrypt.texi ++++ libgcrypt-1.9.4/doc/gcrypt.texi +@@ -975,6 +975,18 @@ certification. If the KDF is approved, t + @code{GPG_ERR_NO_ERROR}. Otherwise @code{GPG_ERR_NOT_SUPPORTED} + is returned. + ++@item GCRYCTL_FIPS_SERVICE_INDICATOR_PK; Arguments: enum gcry_pk_algos ++[, enum pk_operation (only for GCRY_PK_RSA)] [, const char * (only for ++GCRY_PK_ECC, GCRY_PK_ECDH or GCRY_PK_ECDSA)] ++ ++Check if the given asymmetric cipher is approved under the current FIPS ++140-3 certification. For GCRY_PK_RSA, an additional parameter for the ++operation mode @code{enum pk_operation} is required. For GCRY_PK_ECC, ++GCRY_PK_ECDH and GCRY_PK_ECDSA, the additional parameter is the curve ++name or its alias as @code{const char *}. If the combination is ++approved, this function returns @code{GPG_ERR_NO_ERROR}. Otherwise ++@code{GPG_ERR_NOT_SUPPORTED} is returned. ++ + @end table + + @end deftypefun +Index: libgcrypt-1.9.4/src/g10lib.h +=================================================================== +--- libgcrypt-1.9.4.orig/src/g10lib.h ++++ libgcrypt-1.9.4/src/g10lib.h +@@ -489,6 +489,7 @@ void _gcry_fips_signal_error (const char + + int _gcry_fips_indicator_cipher (va_list arg_ptr); + int _gcry_fips_indicator_kdf (va_list arg_ptr); ++int _gcry_fips_indicator_pk (va_list arg_ptr); + + int _gcry_fips_is_operational (void); + +Index: libgcrypt-1.9.4/src/global.c +=================================================================== +--- libgcrypt-1.9.4.orig/src/global.c ++++ libgcrypt-1.9.4/src/global.c +@@ -768,6 +768,15 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, + rc = _gcry_fips_indicator_kdf (arg_ptr); + break; + ++ case GCRYCTL_FIPS_SERVICE_INDICATOR_PK: ++ /* Get FIPS Service Indicator for a given asymmetric algorithm. For ++ * GCRY_PK_RSA, an additional parameter for the operation mode is ++ * required. For ECC, ECDH and ECDSA, the additional parameter is the ++ * curve name or its alias. Returns GPG_ERR_NO_ERROR if the ++ * algorithm is allowed or GPG_ERR_NOT_SUPPORTED otherwise. */ ++ rc = _gcry_fips_indicator_pk (arg_ptr); ++ break; ++ + case PRIV_CTL_INIT_EXTRNG_TEST: /* Init external random test. */ + rc = GPG_ERR_NOT_SUPPORTED; + break; diff --git a/libgcrypt-FIPS-Zeroize-hmac.patch b/libgcrypt-FIPS-Zeroize-hmac.patch new file mode 100644 index 0000000..dce2548 --- /dev/null +++ b/libgcrypt-FIPS-Zeroize-hmac.patch @@ -0,0 +1,35 @@ +Index: libgcrypt-1.9.4/src/fips.c +=================================================================== +--- libgcrypt-1.9.4.orig/src/fips.c ++++ libgcrypt-1.9.4/src/fips.c +@@ -905,6 +905,10 @@ check_binary_integrity (void) + char *fname = NULL; + const char key[] = "orboDeJITITejsirpADONivirpUkvarP"; + ++ /* A buffer of 64 bytes plus one for a LF and one to ++ * detect garbage. */ ++ unsigned char buffer[64+1+1]; ++ + if (get_library_path ("libgcrypt.so.20", "gcry_check_version", libpath, sizeof(libpath))) + err = gpg_error_from_syserror (); + else +@@ -927,9 +931,6 @@ check_binary_integrity (void) + err = gpg_error_from_syserror (); + else + { +- /* A buffer of 64 bytes plus one for a LF and one to +- detect garbage. */ +- unsigned char buffer[64+1+1]; + const unsigned char *s; + int n; + +@@ -957,6 +958,9 @@ check_binary_integrity (void) + } + } + } ++ /* Zeroize digest and buffer */ ++ memset (digest, 0, sizeof(digest)); ++ memset (buffer, 0, sizeof(buffer)); + reporter ("binary", 0, fname, err? gpg_strerror (err):NULL); + #ifdef HAVE_SYSLOG + if (err) diff --git a/libgcrypt-FIPS-disable-3DES.patch b/libgcrypt-FIPS-disable-3DES.patch new file mode 100644 index 0000000..ec6363f --- /dev/null +++ b/libgcrypt-FIPS-disable-3DES.patch @@ -0,0 +1,52 @@ +Index: libgcrypt-1.9.4/cipher/des.c +=================================================================== +--- libgcrypt-1.9.4.orig/cipher/des.c ++++ libgcrypt-1.9.4/cipher/des.c +@@ -1498,7 +1498,7 @@ static gcry_cipher_oid_spec_t oids_tripl + + gcry_cipher_spec_t _gcry_cipher_spec_tripledes = + { +- GCRY_CIPHER_3DES, {0, 1}, ++ GCRY_CIPHER_3DES, {0, 0}, + "3DES", NULL, oids_tripledes, 8, 192, sizeof (struct _tripledes_ctx), + do_tripledes_setkey, do_tripledes_encrypt, do_tripledes_decrypt, + NULL, NULL, +Index: libgcrypt-1.9.4/cipher/mac-cmac.c +=================================================================== +--- libgcrypt-1.9.4.orig/cipher/mac-cmac.c ++++ libgcrypt-1.9.4/cipher/mac-cmac.c +@@ -458,7 +458,7 @@ gcry_mac_spec_t _gcry_mac_type_spec_cmac + #endif + #if USE_DES + gcry_mac_spec_t _gcry_mac_type_spec_cmac_tripledes = { +- GCRY_MAC_CMAC_3DES, {0, 1}, "CMAC_3DES", ++ GCRY_MAC_CMAC_3DES, {0, 0}, "CMAC_3DES", + &cmac_ops + }; + #endif +Index: libgcrypt-1.9.4/src/fips.c +=================================================================== +--- libgcrypt-1.9.4.orig/src/fips.c ++++ libgcrypt-1.9.4/src/fips.c +@@ -493,6 +493,10 @@ run_cipher_selftests (int extended) + + for (idx=0; algos[idx]; idx++) + { ++ /* Skip non-approved cipher in FIPS mode */ ++ if (fips_mode() && algos[idx] == GCRY_CIPHER_3DES) ++ continue; ++ + err = _gcry_cipher_selftest (algos[idx], extended, reporter); + reporter ("cipher", algos[idx], NULL, + err? gpg_strerror (err):NULL); +@@ -558,6 +562,10 @@ run_mac_selftests (int extended) + + for (idx=0; algos[idx]; idx++) + { ++ /* Skip non-approved MAC algorithm in FIPS mode */ ++ if (fips_mode() && algos[idx] == GCRY_MAC_CMAC_3DES) ++ continue; ++ + err = _gcry_mac_selftest (algos[idx], extended, reporter); + reporter ("mac", algos[idx], NULL, + err? gpg_strerror (err):NULL); diff --git a/libgcrypt-FIPS-disable-DSA.patch b/libgcrypt-FIPS-disable-DSA.patch new file mode 100644 index 0000000..b518c8e --- /dev/null +++ b/libgcrypt-FIPS-disable-DSA.patch @@ -0,0 +1,44 @@ +From ea362090fc11caa28643153fc6444442243c8765 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Wed, 8 Dec 2021 09:52:02 +0900 +Subject: [PATCH 0937/1000] fips: Disable DSA in FIPS mode. + +* cipher/dsa.c (run_selftests): Disable DSA spec in FIPS mode. +* src/fips.c (run_pubkey_selftests): Skip DSA power-on selftests. +-- + +GnuPG-bug-id: 5710 +Signed-off-by: Jakub Jelen +--- + cipher/dsa.c | 2 +- + src/fips.c | 1 - + 2 files changed, 1 insertion(+), 2 deletions(-) + +diff --git a/cipher/dsa.c b/cipher/dsa.c +index d5b00912..e559f9f5 100644 +--- a/cipher/dsa.c ++++ b/cipher/dsa.c +@@ -1441,7 +1441,7 @@ run_selftests (int algo, int extended, selftest_report_func_t report) + + gcry_pk_spec_t _gcry_pubkey_spec_dsa = + { +- GCRY_PK_DSA, { 0, 1 }, ++ GCRY_PK_DSA, { 0, 0 }, + GCRY_PK_USAGE_SIGN, + "DSA", dsa_names, + "pqgy", "pqgyx", "", "rs", "pqgy", +diff --git a/src/fips.c b/src/fips.c +index 0ab7fecc..bcadc5f2 100644 +--- a/src/fips.c ++++ b/src/fips.c +@@ -522,7 +522,6 @@ run_pubkey_selftests (int extended) + static int algos[] = + { + GCRY_PK_RSA, +- GCRY_PK_DSA, + GCRY_PK_ECC, + 0 + }; +-- +2.34.1 + diff --git a/libgcrypt-FIPS-fix-gcry_mpi_sub_ui.patch b/libgcrypt-FIPS-fix-gcry_mpi_sub_ui.patch new file mode 100644 index 0000000..83ec82d --- /dev/null +++ b/libgcrypt-FIPS-fix-gcry_mpi_sub_ui.patch @@ -0,0 +1,230 @@ +From d5bf106468e6c6b0f33b193abf04590e4e9fc011 Mon Sep 17 00:00:00 2001 +From: Jussi Kivilinna +Date: Tue, 30 Nov 2021 22:04:16 +0200 +Subject: [PATCH 487/500] gcry_mpi_sub_ui: fix subtracting from negative value + +* mpi/mpi-add.c (_gcry_mpi_sub_ui): Set output sign bit when 'u' +is negative. +* tests/mpitests.c (test_add): Additional tests for mpi_add_ui; Check +test output and fail if output does not match expected. +(test_sub): Additional tests for mpi_sub_ui; Check test output and fail +if output does not match expected. +(test_mul): Additional tests for mpi_mul_ui; Check test output and fail +if output does not match expected. +-- + +Reported-by: Guido Vranken +Signed-off-by: Jussi Kivilinna +--- + mpi/mpi-add.c | 1 + + tests/mpitests.c | 119 ++++++++++++++++++++++++++++++++++++++++++++--- + 2 files changed, 113 insertions(+), 7 deletions(-) + +diff --git a/mpi/mpi-add.c b/mpi/mpi-add.c +index 53f476e0..38dd352f 100644 +--- a/mpi/mpi-add.c ++++ b/mpi/mpi-add.c +@@ -191,6 +191,7 @@ _gcry_mpi_sub_ui(gcry_mpi_t w, gcry_mpi_t u, unsigned long v ) + cy = _gcry_mpih_add_1(wp, up, usize, v); + wp[usize] = cy; + wsize = usize + cy; ++ wsign = 1; + } + else { /* The signs are different. Need exact comparison to determine + * which operand to subtract from which. */ +diff --git a/tests/mpitests.c b/tests/mpitests.c +index 96e01551..48ea18b2 100644 +--- a/tests/mpitests.c ++++ b/tests/mpitests.c +@@ -378,7 +378,8 @@ test_add (void) + gcry_mpi_t two; + gcry_mpi_t ff; + gcry_mpi_t result; +- unsigned char* pc; ++ gcry_mpi_t minusfive; ++ char *pc; + + gcry_mpi_scan(&one, GCRYMPI_FMT_USG, ones, sizeof(ones), NULL); + gcry_mpi_scan(&two, GCRYMPI_FMT_USG, twos, sizeof(twos), NULL); +@@ -386,21 +387,47 @@ test_add (void) + result = gcry_mpi_new(0); + + gcry_mpi_add(result, one, two); +- gcry_mpi_aprint(GCRYMPI_FMT_HEX, &pc, NULL, result); ++ gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); + if (debug) + gcry_log_debug ("Result of one plus two:\n%s\n", pc); ++ if (strcmp (pc, "030303030303030303030303030303030303030303030303" ++ "030303030303030303030303030303030303030303030303") != 0) ++ fail ("mpi_add failed at line %d", __LINE__); + gcry_free(pc); + + gcry_mpi_add(result, ff, one); +- gcry_mpi_aprint(GCRYMPI_FMT_HEX, &pc, NULL, result); ++ gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); + if (debug) + gcry_log_debug ("Result of ff plus one:\n%s\n", pc); ++ if (strcmp (pc, "010101010101010101010101010101010101010101010101" ++ "01010101010101010101010101010101010101010101010100") != 0) ++ fail ("mpi_add failed at line %d", __LINE__); ++ gcry_free(pc); ++ ++ gcry_mpi_scan(&minusfive, GCRYMPI_FMT_HEX, "-5", 0, NULL); ++ gcry_mpi_add_ui (result, minusfive, 2); ++ ++ gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); ++ if (debug) ++ gcry_log_debug ("Result of minus five plus two:\n%s\n", pc); ++ if (strcmp (pc, "-03") != 0) ++ fail ("mpi_add_ui failed at line %d", __LINE__); ++ gcry_free(pc); ++ ++ gcry_mpi_add_ui (result, result, 3); ++ ++ gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); ++ if (debug) ++ gcry_log_debug ("Result of minus three plus three:\n%s\n", pc); ++ if (strcmp (pc, "00") != 0) ++ fail ("mpi_add_ui failed at line %d", __LINE__); + gcry_free(pc); + + gcry_mpi_release(one); + gcry_mpi_release(two); + gcry_mpi_release(ff); + gcry_mpi_release(result); ++ gcry_mpi_release(minusfive); + return 1; + } + +@@ -408,24 +435,76 @@ test_add (void) + static int + test_sub (void) + { ++ gcry_mpi_t zero; + gcry_mpi_t one; + gcry_mpi_t two; ++ gcry_mpi_t five; + gcry_mpi_t result; +- unsigned char* pc; ++ gcry_mpi_t minusfive; ++ char *pc; + + gcry_mpi_scan(&one, GCRYMPI_FMT_USG, ones, sizeof(ones), NULL); + gcry_mpi_scan(&two, GCRYMPI_FMT_USG, twos, sizeof(twos), NULL); + result = gcry_mpi_new(0); + gcry_mpi_sub(result, two, one); + +- gcry_mpi_aprint(GCRYMPI_FMT_HEX, &pc, NULL, result); ++ gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); + if (debug) + gcry_log_debug ("Result of two minus one:\n%s\n", pc); ++ if (strcmp (pc, "010101010101010101010101010101010101010101010101" ++ "010101010101010101010101010101010101010101010101") != 0) ++ fail ("mpi_sub failed at line %d", __LINE__); ++ gcry_free(pc); ++ ++ zero = gcry_mpi_new(0); ++ five = gcry_mpi_new(0); ++ minusfive = gcry_mpi_new(0); ++ gcry_mpi_set_ui (zero, 0); ++ gcry_mpi_set_ui (one, 1); ++ gcry_mpi_set_ui (two, 2); ++ gcry_mpi_set_ui (five, 5); ++ gcry_mpi_sub (minusfive, zero, five); ++ ++ gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, minusfive); ++ if (debug) ++ gcry_log_debug ("Result of zero minus five:\n%s\n", pc); ++ if (strcmp (pc, "-05") != 0) ++ fail ("mpi_sub failed at line %d", __LINE__); ++ gcry_free(pc); ++ ++ gcry_mpi_sub_ui (result, five, 2); ++ ++ gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); ++ if (debug) ++ gcry_log_debug ("Result of five minus two:\n%s\n", pc); ++ if (strcmp (pc, "03") != 0) ++ fail ("mpi_sub_ui failed at line %d", __LINE__); ++ gcry_free(pc); ++ ++ gcry_mpi_sub_ui (result, one, 10); ++ ++ gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); ++ if (debug) ++ gcry_log_debug ("Result of one minus ten:\n%s\n", pc); ++ if (strcmp (pc, "-09") != 0) ++ fail ("mpi_sub_ui failed at line %d", __LINE__); ++ gcry_free(pc); ++ ++ gcry_mpi_sub_ui (result, minusfive, 2); ++ ++ gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); ++ if (debug) ++ gcry_log_debug ("Result of minus five minus two:\n%s\n", pc); ++ if (strcmp (pc, "-07") != 0) ++ fail ("mpi_sub_ui failed at line %d", __LINE__); + gcry_free(pc); + + gcry_mpi_release(one); + gcry_mpi_release(two); + gcry_mpi_release(result); ++ gcry_mpi_release(zero); ++ gcry_mpi_release(five); ++ gcry_mpi_release(minusfive); + return 1; + } + +@@ -436,21 +515,47 @@ test_mul (void) + gcry_mpi_t two; + gcry_mpi_t three; + gcry_mpi_t result; +- unsigned char* pc; ++ gcry_mpi_t minusfive; ++ char *pc; + + gcry_mpi_scan(&two, GCRYMPI_FMT_USG, twos, sizeof(twos), NULL); + gcry_mpi_scan(&three, GCRYMPI_FMT_USG, threes, sizeof(threes), NULL); + result = gcry_mpi_new(0); + gcry_mpi_mul(result, two, three); + +- gcry_mpi_aprint(GCRYMPI_FMT_HEX, &pc, NULL, result); ++ gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); + if (debug) + gcry_log_debug ("Result of two mul three:\n%s\n", pc); ++ if (strcmp (pc, "060C12181E242A30363C42484E545A60666C72787E848A90" ++ "969CA2A8AEB4BAC0C6CCD2D8DEE4EAF0F6FD03090F151B21" ++ "1B150F0902FCF6F0EAE4DED8D2CCC6C0BAB4AEA8A29C9690" ++ "8A847E78726C66605A544E48423C36302A241E18120C06") != 0) ++ fail ("mpi_mul failed at line %d", __LINE__); ++ gcry_free(pc); ++ ++ gcry_mpi_scan(&minusfive, GCRYMPI_FMT_HEX, "-5", 0, NULL); ++ gcry_mpi_mul_ui (result, minusfive, 3); ++ ++ gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); ++ if (debug) ++ gcry_log_debug ("Result of minus five mul three:\n%s\n", pc); ++ if (strcmp (pc, "-0F") != 0) ++ fail ("mpi_mul_ui failed at line %d", __LINE__); ++ gcry_free(pc); ++ ++ gcry_mpi_mul_ui (result, result, 0); ++ ++ gcry_mpi_aprint(GCRYMPI_FMT_HEX, (unsigned char **)&pc, NULL, result); ++ if (debug) ++ gcry_log_debug ("Result of minus fifteen mul zero:\n%s\n", pc); ++ if (strcmp (pc, "00") != 0) ++ fail ("mpi_mul_ui failed at line %d", __LINE__); + gcry_free(pc); + + gcry_mpi_release(two); + gcry_mpi_release(three); + gcry_mpi_release(result); ++ gcry_mpi_release(minusfive); + return 1; + } + +-- +2.33.1 + diff --git a/libgcrypt-FIPS-fix-regression-tests.patch b/libgcrypt-FIPS-fix-regression-tests.patch new file mode 100644 index 0000000..39f8795 --- /dev/null +++ b/libgcrypt-FIPS-fix-regression-tests.patch @@ -0,0 +1,448 @@ +Index: libgcrypt-1.9.4/cipher/pubkey.c +=================================================================== +--- libgcrypt-1.9.4.orig/cipher/pubkey.c ++++ libgcrypt-1.9.4/cipher/pubkey.c +@@ -224,7 +224,7 @@ check_pubkey_algo (int algo, unsigned us + gcry_pk_spec_t *spec; + + spec = spec_from_algo (algo); +- if (spec) ++ if (spec && !spec->flags.disabled) + { + if (((use & GCRY_PK_USAGE_SIGN) + && (! (spec->use & GCRY_PK_USAGE_SIGN))) +From 44c7c41af21c668826280abfee1257853020ba2d Mon Sep 17 00:00:00 2001 +From: NIIBE Yutaka +Date: Mon, 16 Aug 2021 12:41:11 +0900 +Subject: [PATCH 161/200] tests: Skip tests when FIPS for keygrip computations. + +* tests/keygrip.c (check): Skip non-FIPS curves when FIPS. +(main): Check if FIPS is enabled. + +-- + +GnuPG-bug-id: 5520 +Signed-off-by: NIIBE Yutaka +--- + tests/keygrip.c | 37 ++++++++++++++++++++++++++++--------- + 1 file changed, 28 insertions(+), 9 deletions(-) + +diff --git a/tests/keygrip.c b/tests/keygrip.c +index cfccc06e..49bd71bc 100644 +--- a/tests/keygrip.c ++++ b/tests/keygrip.c +@@ -33,6 +33,9 @@ + + static int repetitions; + ++/* Whether fips mode was active at startup. */ ++static int in_fips_mode; ++ + + + static void +@@ -54,6 +57,7 @@ static struct + int algo; + const char *key; + const unsigned char grip[20]; ++ int skip_when_fips; + } key_grips[] = + { + { +@@ -155,7 +159,8 @@ static struct + /* */"436DD11A1756AFE56CD93408410FCDA9" + /* */"BA95024EB613BD481A14FCFEC27A448A#)))", + "\x52\xBA\xD4\xB4\xA3\x2D\x32\xA1\xDD\x06" +- "\x5E\x99\x0B\xF1\xAB\xC1\x13\x3D\x84\xD4" ++ "\x5E\x99\x0B\xF1\xAB\xC1\x13\x3D\x84\xD4", ++ 1 + }, + { /* Compressed form of above. */ + GCRY_PK_ECC, +@@ -165,7 +170,8 @@ static struct + " (q #022ECD8679930BE2DB4AD42B8600BA3F80" + /* */"2D4D539BFF2F69B83EC9B7BBAA7F3406#)))", + "\x52\xBA\xD4\xB4\xA3\x2D\x32\xA1\xDD\x06" +- "\x5E\x99\x0B\xF1\xAB\xC1\x13\x3D\x84\xD4" ++ "\x5E\x99\x0B\xF1\xAB\xC1\x13\x3D\x84\xD4", ++ 1 + }, + { + GCRY_PK_ECC, +@@ -177,7 +183,8 @@ static struct + /* */"9EBBA41915313417BA54218EB0569C59" + /* */"0B156C76DBCAB6E84575E6EF68CE7B87#)))", + "\x99\x38\x6A\x82\x41\x96\x29\x9C\x89\x74" +- "\xD6\xE1\xBF\x43\xAC\x9B\x9A\x12\xE7\x3F" ++ "\xD6\xE1\xBF\x43\xAC\x9B\x9A\x12\xE7\x3F", ++ 1 + }, + { /* Compressed form of above. */ + GCRY_PK_ECC, +@@ -187,7 +194,8 @@ static struct + " (q #035B784CA008EE64AB3D85017EE0D2BE87" + /* */"558762C7300E0C8E06B1F9AF7C031458#)))", + "\x99\x38\x6A\x82\x41\x96\x29\x9C\x89\x74" +- "\xD6\xE1\xBF\x43\xAC\x9B\x9A\x12\xE7\x3F" ++ "\xD6\xE1\xBF\x43\xAC\x9B\x9A\x12\xE7\x3F", ++ 1 + }, + { /* Ed25519 standard */ + GCRY_PK_ECC, +@@ -199,7 +207,8 @@ static struct + " 47BD24842905C049257673B3F5249524E0A41FAA17B25B818D0F97E625F1A1D0#)" + " ))", + "\x0C\xCA\xB2\xFD\x48\x9A\x33\x40\x2C\xE8" +- "\xE0\x4A\x1F\xB2\x45\xEA\x80\x3D\x0A\xF1" ++ "\xE0\x4A\x1F\xB2\x45\xEA\x80\x3D\x0A\xF1", ++ 1 + }, + { /* Ed25519+EdDSA */ + GCRY_PK_ECC, +@@ -209,7 +218,8 @@ static struct + " (q #773E72848C1FD5F9652B29E2E7AF79571A04990E96F2016BF4E0EC1890C2B7DB#)" + " ))", + "\x9D\xB6\xC6\x4A\x38\x83\x0F\x49\x60\x70" +- "\x17\x89\x47\x55\x20\xBE\x8C\x82\x1F\x47" ++ "\x17\x89\x47\x55\x20\xBE\x8C\x82\x1F\x47", ++ 1 + }, + { /* Ed25519+EdDSA (with compression prefix) */ + GCRY_PK_ECC, +@@ -220,7 +230,8 @@ static struct + " 773E72848C1FD5F9652B29E2E7AF79571A04990E96F2016BF4E0EC1890C2B7DB#)" + " ))", + "\x9D\xB6\xC6\x4A\x38\x83\x0F\x49\x60\x70" +- "\x17\x89\x47\x55\x20\xBE\x8C\x82\x1F\x47" ++ "\x17\x89\x47\x55\x20\xBE\x8C\x82\x1F\x47", ++ 1 + }, + { /* Ed25519+EdDSA (same but uncompressed)*/ + GCRY_PK_ECC, +@@ -232,7 +243,8 @@ static struct + " 5bb7c29018ece0f46b01f2960e99041a5779afe7e2292b65f9d51f8c84723e77#)" + " ))", + "\x9D\xB6\xC6\x4A\x38\x83\x0F\x49\x60\x70" +- "\x17\x89\x47\x55\x20\xBE\x8C\x82\x1F\x47" ++ "\x17\x89\x47\x55\x20\xBE\x8C\x82\x1F\x47", ++ 1 + }, + { /* Cv25519 */ + GCRY_PK_ECC, +@@ -243,7 +255,8 @@ static struct + " 918C1733127F6BF2646FAE3D081A18AE77111C903B906310B077505EFFF12740#)" + " ))", + "\x0F\x89\xA5\x65\xD3\xEA\x18\x7C\xE8\x39" +- "\x33\x23\x98\xF5\xD4\x80\x67\x7D\xF4\x9C" ++ "\x33\x23\x98\xF5\xD4\x80\x67\x7D\xF4\x9C", ++ 1 + }, + { /* Random key */ + GCRY_PK_RSA, +@@ -280,6 +293,9 @@ check (void) + + for (i = 0; i < (sizeof (key_grips) / sizeof (*key_grips)); i++) + { ++ if (in_fips_mode && key_grips[i].skip_when_fips) ++ continue; ++ + if (gcry_pk_test_algo (key_grips[i].algo)) + { + if (verbose) +@@ -379,6 +395,9 @@ main (int argc, char **argv) + if (debug) + xgcry_control ((GCRYCTL_SET_DEBUG_FLAGS, 1u, 0)); + ++ if (gcry_fips_mode_active ()) ++ in_fips_mode = 1; ++ + check (); + + return 0; +-- +2.33.0 + +From 3026148331523ec7ca81031339b5629431cafa23 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Tue, 13 Jul 2021 09:20:18 +0200 +Subject: tests: Expect curves 25519/448 to fail in FIPS mode + +* tests/t-cv25519.c (test_cv_hl): Expect the operation to fail in FIPS + mode. + (test_cv_x25519, test_it): Ditto. + (main) Detect FIPS mode. +* tests/t-ed25519.c (one_test): Expect the operation to fail in FIPS + mode. + (main) Detect FIPS mode. +* tests/t-ed448.c (one_test): Expect the operation to fail in FIPS + mode. + (main) Detect FIPS mode. +* tests/t-x448.c (test_cv_hl): Expect the operation to fail in FIPS + mode. + (test_cv_x448, test_cv): Ditto. + (main) Detect FIPS mode. +-- +The ed25519, ed448, cv25519 and cv448 curves are not available in FIPS +mode. Some of the tests already skipped these, but it is always better +to make sure thy are failing, rather than just skipping these. + +Signed-off-by: Jakub Jelen +--- + tests/t-cv25519.c | 37 +++++++++++++++++++++++++++++++++++-- + tests/t-ed25519.c | 18 ++++++++++++++---- + tests/t-ed448.c | 18 ++++++++++++++---- + tests/t-x448.c | 41 +++++++++++++++++++++++++++++++++++++---- + 4 files changed, 100 insertions(+), 14 deletions(-) + +diff --git a/tests/t-cv25519.c b/tests/t-cv25519.c +index 0de50a02..b4126f4c 100644 +--- a/tests/t-cv25519.c ++++ b/tests/t-cv25519.c +@@ -33,6 +33,7 @@ + #include "t-common.h" + #define N_TESTS 18 + ++static int in_fips_mode = 0; + + static void + print_mpi (const char *text, gcry_mpi_t a) +@@ -188,7 +189,17 @@ test_cv_hl (int testno, const char *k_str, const char *u_str, + xfree (buffer); + buffer = NULL; + +- if ((err = gcry_pk_encrypt (&s_result, s_data, s_pk))) ++ err = gcry_pk_encrypt (&s_result, s_data, s_pk); ++ if (in_fips_mode) ++ { ++ if (!err) ++ fail ("gcry_pk_encrypt is not expected to work in FIPS mode for test %d", ++ testno); ++ if (verbose > 1) ++ info ("not executed in FIPS mode\n"); ++ goto leave; ++ } ++ if (err) + fail ("gcry_pk_encrypt failed for test %d: %s", testno, + gpg_strerror (err)); + +@@ -281,7 +292,17 @@ test_cv_x25519 (int testno, const char *k_str, const char *u_str, + goto leave; + } + +- if ((err = gcry_ecc_mul_point (algo, result, scalar, point))) ++ err = gcry_ecc_mul_point (algo, result, scalar, point); ++ if (in_fips_mode) ++ { ++ if (!err) ++ fail ("gcry_ecc_mul_point is not expected to work in FIPS mode for test %d", ++ testno); ++ if (verbose > 1) ++ info ("not executed in FIPS mode\n"); ++ goto leave; ++ } ++ if (err) + fail ("gcry_ecc_mul_point failed for test %d: %s", testno, + gpg_strerror (err)); + +@@ -335,6 +356,15 @@ test_it (int testno, const char *k_str, int iter, const char *result_str) + info ("Running test %d: iteration=%d\n", testno, iter); + + gcry_mpi_ec_new (&ctx, NULL, "Curve25519"); ++ if (in_fips_mode) ++ { ++ if (ctx) ++ fail ("gcry_mpi_ec_new should fail in FIPS mode for test %d", ++ testno); ++ if (verbose > 1) ++ info ("not executed in FIPS mode\n"); ++ return; ++ } + Q = gcry_mpi_point_new (0); + + if (!(buffer = hex2buffer (k_str, &buflen)) || buflen != 32) +@@ -640,6 +670,9 @@ main (int argc, char **argv) + xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0)); + xgcry_control ((GCRYCTL_INITIALIZATION_FINISHED, 0)); + ++ if (gcry_fips_mode_active ()) ++ in_fips_mode = 1; ++ + start_timer (); + check_cv25519 (); + stop_timer (); +diff --git a/tests/t-ed25519.c b/tests/t-ed25519.c +index a5271c25..567bc797 100644 +--- a/tests/t-ed25519.c ++++ b/tests/t-ed25519.c +@@ -36,6 +36,7 @@ + static int sign_with_pk; + static int no_verify; + static int custom_data_file; ++static int in_fips_mode = 0; + + + static void +@@ -271,7 +272,17 @@ one_test (int testno, const char *sk, const char *pk, + goto leave; + } + +- if ((err = gcry_pk_sign (&s_sig, s_msg, s_sk))) ++ err = gcry_pk_sign (&s_sig, s_msg, s_sk); ++ if (in_fips_mode) ++ { ++ if (!err) ++ fail ("gcry_pk_sign is not expected to work in FIPS mode for test %d", ++ testno); ++ if (verbose > 1) ++ info ("not executed in FIPS mode\n"); ++ goto leave; ++ } ++ if (err) + fail ("gcry_pk_sign failed for test %d: %s", testno, gpg_strerror (err)); + if (debug) + show_sexp ("sig=", s_sig); +@@ -481,9 +492,8 @@ main (int argc, char **argv) + xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0)); + xgcry_control ((GCRYCTL_INITIALIZATION_FINISHED, 0)); + +- /* Ed25519 isn't supported in fips mode */ +- if (gcry_fips_mode_active()) +- return 77; ++ if (gcry_fips_mode_active ()) ++ in_fips_mode = 1; + + start_timer (); + check_ed25519 (fname); +diff --git a/tests/t-ed448.c b/tests/t-ed448.c +index 1f445ffc..f38cd10c 100644 +--- a/tests/t-ed448.c ++++ b/tests/t-ed448.c +@@ -36,6 +36,7 @@ + static int sign_with_pk; + static int no_verify; + static int custom_data_file; ++static int in_fips_mode = 0; + + + static void +@@ -302,7 +303,17 @@ one_test (int testno, int ph, const char *sk, const char *pk, + } + } + +- if ((err = gcry_pk_sign (&s_sig, s_msg, s_sk))) ++ err = gcry_pk_sign (&s_sig, s_msg, s_sk); ++ if (in_fips_mode) ++ { ++ if (!err) ++ fail ("gcry_pk_sign is not expected to work in FIPS mode for test %d", ++ testno); ++ if (verbose > 1) ++ info ("not executed in FIPS mode\n"); ++ goto leave; ++ } ++ if (err) + fail ("gcry_pk_sign failed for test %d: %s", testno, gpg_strerror (err)); + if (debug) + show_sexp ("sig=", s_sig); +@@ -521,9 +532,8 @@ main (int argc, char **argv) + xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0)); + xgcry_control ((GCRYCTL_INITIALIZATION_FINISHED, 0)); + +- /* Ed448 isn't supported in fips mode */ +- if (gcry_fips_mode_active()) +- return 77; ++ if (gcry_fips_mode_active ()) ++ in_fips_mode = 1; + + start_timer (); + check_ed448 (fname); +diff --git a/tests/t-x448.c b/tests/t-x448.c +index 5c3cbeb9..cc4b10fc 100644 +--- a/tests/t-x448.c ++++ b/tests/t-x448.c +@@ -34,6 +34,7 @@ + #include "t-common.h" + #define N_TESTS 9 + ++static int in_fips_mode = 0; + + static void + print_mpi (const char *text, gcry_mpi_t a) +@@ -179,8 +180,18 @@ test_cv_hl (int testno, const char *k_str, const char *u_str, + xfree (buffer); + buffer = NULL; + +- if ((err = gcry_pk_encrypt (&s_result, s_data, s_pk))) +- fail ("gcry_pk_encrypt failed for test %d: %s", testno, ++ err = gcry_pk_encrypt (&s_result, s_data, s_pk); ++ if (in_fips_mode) ++ { ++ if (!err) ++ fail ("gcry_pk_encrypt is not expected to work in FIPS mode for test %d", ++ testno); ++ if (verbose > 1) ++ info ("not executed in FIPS mode\n"); ++ goto leave; ++ } ++ if (err) ++ fail ("gcry_pk_encrypt goto leavefailed for test %d: %s", testno, + gpg_strerror (err)); + + s_tmp = gcry_sexp_find_token (s_result, "s", 0); +@@ -257,7 +268,17 @@ test_cv_x448 (int testno, const char *k_str, const char *u_str, + goto leave; + } + +- if ((err = gcry_ecc_mul_point (GCRY_ECC_CURVE448, result, scalar, point))) ++ err = gcry_ecc_mul_point (GCRY_ECC_CURVE448, result, scalar, point); ++ if (in_fips_mode) ++ { ++ if (err != GPG_ERR_NOT_SUPPORTED) ++ fail ("gcry_ecc_mul_point is not expected to work in FIPS mode for test %d: %s", ++ testno, gpg_strerror (err)); ++ if (verbose > 1) ++ info ("not executed in FIPS mode\n"); ++ goto leave; ++ } ++ if (err) + fail ("gcry_ecc_mul_point failed for test %d: %s", testno, + gpg_strerror (err)); + +@@ -296,7 +317,7 @@ test_cv (int testno, const char *k_str, const char *u_str, + static void + test_it (int testno, const char *k_str, int iter, const char *result_str) + { +- gcry_ctx_t ctx; ++ gcry_ctx_t ctx = NULL; + gpg_error_t err; + void *buffer = NULL; + size_t buflen; +@@ -311,6 +332,15 @@ test_it (int testno, const char *k_str, int iter, const char *result_str) + info ("Running test %d: iteration=%d\n", testno, iter); + + gcry_mpi_ec_new (&ctx, NULL, "X448"); ++ if (in_fips_mode) ++ { ++ if (ctx) ++ fail ("gcry_mpi_ec_new should fail in FIPS mode for test %d", ++ testno); ++ if (verbose > 1) ++ info ("not executed in FIPS mode\n"); ++ return; ++ } + Q = gcry_mpi_point_new (0); + + if (!(buffer = hex2buffer (k_str, &buflen)) || buflen != 56) +@@ -583,6 +613,9 @@ main (int argc, char **argv) + xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0)); + xgcry_control ((GCRYCTL_INITIALIZATION_FINISHED, 0)); + ++ if (gcry_fips_mode_active ()) ++ in_fips_mode = 1; ++ + start_timer (); + check_x448 (); + stop_timer (); +-- +2.33.0 + diff --git a/libgcrypt-FIPS-hw-optimizations.patch b/libgcrypt-FIPS-hw-optimizations.patch new file mode 100644 index 0000000..34f7ef0 --- /dev/null +++ b/libgcrypt-FIPS-hw-optimizations.patch @@ -0,0 +1,31 @@ +From 70e6cec07d86332f1aaf7a69bec75c7138306f6a Mon Sep 17 00:00:00 2001 +From: NIIBE Yutaka +Date: Thu, 29 Jul 2021 14:20:14 +0900 +Subject: [PATCH] hwfeatures: Enable hardware support also in FIPS mode. + +* src/hwfeatures.c (_gcry_detect_hw_features): Remove skipping in FIPS +mode. + +-- + +Reported-by: Jakub Jelen +GnuPG-bug-id: 5508 +Signed-off-by: NIIBE Yutaka +--- + src/hwfeatures.c | 3 --- + 1 file changed, 3 deletions(-) + +Index: libgcrypt-1.9.4/src/hwfeatures.c +=================================================================== +--- libgcrypt-1.9.4.orig/src/hwfeatures.c ++++ libgcrypt-1.9.4/src/hwfeatures.c +@@ -213,9 +213,6 @@ _gcry_detect_hw_features (void) + { + hw_features = 0; + +- if (fips_mode ()) +- return; /* Hardware support is not to be evaluated. */ +- + parse_hwf_deny_file (); + + #if defined (HAVE_CPU_ARCH_X86) diff --git a/libgcrypt-FIPS-kdf-leylength.patch b/libgcrypt-FIPS-kdf-leylength.patch new file mode 100644 index 0000000..633cc30 --- /dev/null +++ b/libgcrypt-FIPS-kdf-leylength.patch @@ -0,0 +1,39 @@ +Index: libgcrypt-1.9.4/src/fips.c +=================================================================== +--- libgcrypt-1.9.4.orig/src/fips.c ++++ libgcrypt-1.9.4/src/fips.c +@@ -475,10 +475,15 @@ int + _gcry_fips_indicator_kdf (va_list arg_ptr) + { + enum gcry_kdf_algos alg = va_arg (arg_ptr, enum gcry_kdf_algos); ++ unsigned int keylen = 0; + + switch (alg) + { + case GCRY_KDF_PBKDF2: ++ keylen = va_arg (arg_ptr, unsigned int); ++ if (keylen < 112) { ++ return GPG_ERR_NOT_SUPPORTED; ++ } + return GPG_ERR_NO_ERROR; + default: + return GPG_ERR_NOT_SUPPORTED; +Index: libgcrypt-1.9.4/doc/gcrypt.texi +=================================================================== +--- libgcrypt-1.9.4.orig/doc/gcrypt.texi ++++ libgcrypt-1.9.4/doc/gcrypt.texi +@@ -983,10 +983,12 @@ algorithm supports different key sizes). + this function returns @code{GPS_ERR_NO_ERROR}. Otherwise @code{GPG_ERR_NOT_SUPPORTED} + is returned. + +-@item GCRYCTL_FIPS_SERVICE_INDICATOR_KDF; Arguments: enum gcry_kdf_algos ++@item GCRYCTL_FIPS_SERVICE_INDICATOR_KDF; Arguments: enum gcry_kdf_algos [, unsigned int] + + Check if the given KDF is approved under the current FIPS 140-3 +-certification. If the KDF is approved, this function returns @code{GPG_ERR_NO_ERROR}. ++certification. The second parameter provides the keylength in bits. ++Keylength values of less that 112 bits are considered non-approved. ++If the KDF is approved, this function returns @code{GPG_ERR_NO_ERROR}. + Otherwise @code{GPG_ERR_NOT_SUPPORTED} is returned. + + @item GCRYCTL_FIPS_SERVICE_INDICATOR_PK; Arguments: enum gcry_pk_algos diff --git a/libgcrypt-FIPS-module-version.patch b/libgcrypt-FIPS-module-version.patch new file mode 100644 index 0000000..ffaf541 --- /dev/null +++ b/libgcrypt-FIPS-module-version.patch @@ -0,0 +1,89 @@ +From c74fde0c3f6114c594332fb28a09c7b817969231 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Fri, 17 Sep 2021 17:11:30 +0200 +Subject: [PATCH 187/200] Allow passing FIPS module version + +* README: Document new --with-fips-module-version=version switch +* configure.ac: Implementation of the --with-fips-module-version +* src/global.c (print_config): Print FIPS module version from above +-- +Signed-off-by: Jakub Jelen + +Moved the module version to a 3rd field to keep the semantics of that +line. + +Signed-off-by: Werner Koch +GnuPG-bug-id: 1600 +--- + README | 4 ++++ + configure.ac | 7 +++++++ + src/global.c | 16 +++++++++++++--- + 3 files changed, 24 insertions(+), 3 deletions(-) + +Index: libgcrypt-1.9.4/README +=================================================================== +--- libgcrypt-1.9.4.orig/README ++++ libgcrypt-1.9.4/README +@@ -165,6 +165,10 @@ + against a HMAC checksum. This works only in FIPS + mode and on systems providing the dladdr function. + ++ --with-fips-module-version=version ++ Specify a string used as a module version for FIPS ++ certification purposes. ++ + --disable-padlock-support + Disable support for the PadLock engine of VIA + processors. The default is to use PadLock if +Index: libgcrypt-1.9.4/configure.ac +=================================================================== +--- libgcrypt-1.9.4.orig/configure.ac ++++ libgcrypt-1.9.4/configure.ac +@@ -599,6 +599,12 @@ if test "$use_hmac_binary_check" = yes ; + [Define to support an HMAC based integrity check]) + fi + ++# Implementation of the --with-fips-module-version. ++AC_ARG_WITH(fips-module-version, ++ [ --with-fips-module-version=VERSION], ++ fips_module_version="$withval", fips_module_version="" ) ++AC_DEFINE_UNQUOTED(FIPS_MODULE_VERSION, "$fips_module_version", ++ [Define FIPS module version for certification]) + + # Implementation of the --disable-jent-support switch. + AC_MSG_CHECKING([whether jitter entropy support is requested]) +@@ -3266,6 +3272,7 @@ GCRY_MSG_WRAP([Enabled pubkey algorithms + GCRY_MSG_SHOW([Random number generator: ],[$random]) + GCRY_MSG_SHOW([Try using jitter entropy: ],[$jentsupport]) + GCRY_MSG_SHOW([Using linux capabilities: ],[$use_capabilities]) ++GCRY_MSG_SHOW([FIPS module version: ],[$fips_module_version]) + GCRY_MSG_SHOW([Try using Padlock crypto: ],[$padlocksupport]) + GCRY_MSG_SHOW([Try using AES-NI crypto: ],[$aesnisupport]) + GCRY_MSG_SHOW([Try using Intel SHAEXT: ],[$shaextsupport]) +Index: libgcrypt-1.9.4/src/global.c +=================================================================== +--- libgcrypt-1.9.4.orig/src/global.c ++++ libgcrypt-1.9.4/src/global.c +@@ -379,10 +379,19 @@ print_config (const char *what, gpgrt_st + { + /* We use y/n instead of 1/0 for the stupid reason that + * Emacsen's compile error parser would accidentally flag that +- * line when printed during "make check" as an error. */ +- gpgrt_fprintf (fp, "fips-mode:%c:%c:\n", ++ * line when printed during "make check" as an error. The ++ * second field is obsolete and thus empty (used to be used for ++ * a so-called enforced-fips-mode). The third field has an ++ * option static string describing the module versions; this is ++ * an optional configure option. */ ++ gpgrt_fprintf (fp, "fips-mode:%c::%s:\n", + fips_mode ()? 'y':'n', +- _gcry_enforced_fips_mode ()? 'y':'n' ); ++#ifdef FIPS_MODULE_VERSION ++ fips_mode () ? FIPS_MODULE_VERSION : "" ++#else ++ "" ++#endif /* FIPS_MODULE_VERSION */ ++ ); + } + + if (!what || !strcmp (what, "rng-type")) diff --git a/libgcrypt-FIPS-rndjent_poll.patch b/libgcrypt-FIPS-rndjent_poll.patch new file mode 100644 index 0000000..f51a10a --- /dev/null +++ b/libgcrypt-FIPS-rndjent_poll.patch @@ -0,0 +1,114 @@ +Index: libgcrypt-1.9.4/random/rndlinux.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/rndlinux.c ++++ libgcrypt-1.9.4/random/rndlinux.c +@@ -141,7 +141,7 @@ _gcry_rndlinux_gather_random (void (*add + volatile pid_t apid; + int fd; + int n; +- byte buffer[768]; ++ byte buffer[256]; + size_t n_hw; + size_t want = length; + size_t last_so_far = 0; +@@ -196,26 +196,43 @@ _gcry_rndlinux_gather_random (void (*add + my_pid = apid; + } + ++ if (fips_mode()) ++ { ++ if (level >= GCRY_VERY_STRONG_RANDOM) ++ { ++ size_t n; + +- /* First read from a hardware source. Note that _gcry_rndhw_poll_slow lets +- it account only for up to 50% (or 25% for RDRAND) of the requested +- bytes. */ +- n_hw = _gcry_rndhw_poll_slow (add, origin, length); +- if (length > 1) +- length -= n_hw; +- +- /* When using a blocking random generator try to get some entropy +- * from the jitter based RNG. In this case we take up to 50% of the +- * remaining requested bytes. */ +- if (level >= GCRY_VERY_STRONG_RANDOM) +- { +- n_hw = _gcry_rndjent_poll (add, origin, length/2); +- if (n_hw > length/2) +- n_hw = length/2; ++ n = _gcry_rndjent_poll (add, origin, length); ++ if (n == 0) ++ log_fatal ("unexpected error from rndjent: %s\n", ++ strerror (errno)); ++ if (n > length) ++ n = length; ++ if (length > 1) ++ length -= n; ++ } ++ } ++ else ++ { ++ /* First read from a hardware source. Note that _gcry_rndhw_poll_slow lets ++ it account only for up to 50% (or 25% for RDRAND) of the requested ++ bytes. */ ++ n_hw = _gcry_rndhw_poll_slow (add, origin, length); + if (length > 1) + length -= n_hw; +- } + ++ /* When using a blocking random generator try to get some entropy ++ * from the jitter based RNG. In this case we take up to 50% of the ++ * remaining requested bytes. */ ++ if (level >= GCRY_VERY_STRONG_RANDOM) ++ { ++ n_hw = _gcry_rndjent_poll (add, origin, length/2); ++ if (n_hw > length/2) ++ n_hw = length/2; ++ if (length > 1) ++ length -= n_hw; ++ } ++ } + + /* Open the requested device. The first time a device is to be + opened we fail with a fatal error if the device does not exists. +@@ -283,8 +301,6 @@ _gcry_rndlinux_gather_random (void (*add + do + { + nbytes = length < sizeof(buffer)? length : sizeof(buffer); +- if (nbytes > 256) +- nbytes = 256; + _gcry_pre_syscall (); + ret = getentropy (buffer, nbytes); + _gcry_post_syscall (); +Index: libgcrypt-1.9.4/random/rndjent.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/rndjent.c ++++ libgcrypt-1.9.4/random/rndjent.c +@@ -279,13 +279,24 @@ _gcry_rndjent_poll (void (*add)(const vo + if (!jent_rng_is_initialized) + { + /* Auto-initialize. */ +- jent_rng_is_initialized = 1; + jent_entropy_collector_free (jent_rng_collector); + jent_rng_collector = NULL; + if ( !(_gcry_random_read_conf () & RANDOM_CONF_DISABLE_JENT)) + { +- if (!jent_entropy_init ()) +- jent_rng_collector = jent_entropy_collector_alloc (1, 0); ++ if (!jent_entropy_init_ex (1, 0)) ++ { ++ jent_rng_collector = jent_entropy_collector_alloc (1, 0); ++ jent_rng_is_initialized = 1; ++ } ++ } ++ } ++ ++ if (!jent_rng_collector) ++ { ++ if (!jent_entropy_init_ex (1, 0)) ++ { ++ jent_rng_collector = jent_entropy_collector_alloc (1, 0); ++ jent_rng_is_initialized = 1; + } + } + diff --git a/libgcrypt-FIPS-service-indicators.patch b/libgcrypt-FIPS-service-indicators.patch new file mode 100644 index 0000000..1152fdd --- /dev/null +++ b/libgcrypt-FIPS-service-indicators.patch @@ -0,0 +1,375 @@ +Index: libgcrypt-1.9.4/src/fips.c +=================================================================== +--- libgcrypt-1.9.4.orig/src/fips.c ++++ libgcrypt-1.9.4/src/fips.c +@@ -437,6 +437,54 @@ _gcry_fips_test_operational (void) + } + + ++int ++_gcry_fips_indicator_cipher (va_list arg_ptr) ++{ ++ enum gcry_cipher_algos alg = va_arg (arg_ptr, enum gcry_cipher_algos); ++ enum gcry_cipher_modes mode; ++ ++ switch (alg) ++ { ++ case GCRY_CIPHER_AES: ++ case GCRY_CIPHER_AES192: ++ case GCRY_CIPHER_AES256: ++ mode = va_arg (arg_ptr, enum gcry_cipher_modes); ++ switch (mode) ++ { ++ case GCRY_CIPHER_MODE_ECB: ++ case GCRY_CIPHER_MODE_CBC: ++ case GCRY_CIPHER_MODE_CFB: ++ case GCRY_CIPHER_MODE_CFB8: ++ case GCRY_CIPHER_MODE_OFB: ++ case GCRY_CIPHER_MODE_CTR: ++ case GCRY_CIPHER_MODE_CCM: ++ case GCRY_CIPHER_MODE_GCM: ++ case GCRY_CIPHER_MODE_XTS: ++ return GPG_ERR_NO_ERROR; ++ default: ++ return GPG_ERR_NOT_SUPPORTED; ++ } ++ default: ++ return GPG_ERR_NOT_SUPPORTED; ++ } ++} ++ ++ ++int ++_gcry_fips_indicator_kdf (va_list arg_ptr) ++{ ++ enum gcry_kdf_algos alg = va_arg (arg_ptr, enum gcry_kdf_algos); ++ ++ switch (alg) ++ { ++ case GCRY_KDF_PBKDF2: ++ return GPG_ERR_NO_ERROR; ++ default: ++ return GPG_ERR_NOT_SUPPORTED; ++ } ++} ++ ++ + /* This is a test on whether the library is in the error or + operational state. */ + int +Index: libgcrypt-1.9.4/src/g10lib.h +=================================================================== +--- libgcrypt-1.9.4.orig/src/g10lib.h ++++ libgcrypt-1.9.4/src/g10lib.h +@@ -487,6 +487,9 @@ void _gcry_fips_signal_error (const char + _gcry_fips_signal_error (__FILE__, __LINE__, NULL, 1, (a)) + #endif + ++int _gcry_fips_indicator_cipher (va_list arg_ptr); ++int _gcry_fips_indicator_kdf (va_list arg_ptr); ++ + int _gcry_fips_is_operational (void); + + /* Return true if the library is in the operational state. */ +Index: libgcrypt-1.9.4/src/gcrypt.h.in +=================================================================== +--- libgcrypt-1.9.4.orig/src/gcrypt.h.in ++++ libgcrypt-1.9.4/src/gcrypt.h.in +@@ -334,7 +334,9 @@ enum gcry_ctl_cmds + GCRYCTL_GET_TAGLEN = 76, + GCRYCTL_REINIT_SYSCALL_CLAMP = 77, + GCRYCTL_AUTO_EXPAND_SECMEM = 78, +- GCRYCTL_SET_ALLOW_WEAK_KEY = 79 ++ GCRYCTL_SET_ALLOW_WEAK_KEY = 79, ++ GCRYCTL_FIPS_SERVICE_INDICATOR_CIPHER = 81, ++ GCRYCTL_FIPS_SERVICE_INDICATOR_KDF = 82 + }; + + /* Perform various operations defined by CMD. */ +Index: libgcrypt-1.9.4/src/global.c +=================================================================== +--- libgcrypt-1.9.4.orig/src/global.c ++++ libgcrypt-1.9.4/src/global.c +@@ -755,6 +755,19 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, + rc = _gcry_fips_run_selftests (1); + break; + ++ case GCRYCTL_FIPS_SERVICE_INDICATOR_CIPHER: ++ /* Get FIPS Service Indicator for a given symmetric algorithm and ++ * optional mode. Returns GPG_ERR_NO_ERROR if algorithm is allowed or ++ * GPG_ERR_NOT_SUPPORTED otherwise */ ++ rc = _gcry_fips_indicator_cipher (arg_ptr); ++ break; ++ ++ case GCRYCTL_FIPS_SERVICE_INDICATOR_KDF: ++ /* Get FIPS Service Indicator for a given KDF. Returns GPG_ERR_NO_ERROR ++ * if algorithm is allowed or GPG_ERR_NOT_SUPPORTED otherwise */ ++ rc = _gcry_fips_indicator_kdf (arg_ptr); ++ break; ++ + case PRIV_CTL_INIT_EXTRNG_TEST: /* Init external random test. */ + rc = GPG_ERR_NOT_SUPPORTED; + break; +Index: libgcrypt-1.9.4/tests/basic.c +=================================================================== +--- libgcrypt-1.9.4.orig/tests/basic.c ++++ libgcrypt-1.9.4/tests/basic.c +@@ -6383,6 +6383,16 @@ do_check_ocb_cipher (int inplace) + assert (tv[tidx].taglen <= ciphlen); + assert (tv[tidx].taglen <= sizeof tag); + ++ /* Verify the FIPS indicator marks this as non-approved */ ++ if (in_fips_mode) ++ { ++ err = gcry_control (GCRYCTL_FIPS_SERVICE_INDICATOR_CIPHER, ++ tv[tidx].algo, GCRY_CIPHER_MODE_OCB); ++ if (gpg_err_code (err) != GPG_ERR_NOT_SUPPORTED) ++ fail ("cipher-ocb, gcry_control did not fail as expected (tv %d): %s\n", ++ tidx, gpg_strerror (err)); ++ } ++ + err = gcry_cipher_open (&hde, tv[tidx].algo, GCRY_CIPHER_MODE_OCB, 0); + if (!err) + err = gcry_cipher_open (&hdd, tv[tidx].algo, GCRY_CIPHER_MODE_OCB, 0); +@@ -6644,6 +6654,16 @@ check_ocb_cipher_largebuf_split (int alg + memcpy(inbuf + i, hash, 16); + } + ++ /* Verify the FIPS indicator marks this as non-approved */ ++ if (in_fips_mode) ++ { ++ err = gcry_control (GCRYCTL_FIPS_SERVICE_INDICATOR_CIPHER, ++ algo, GCRY_CIPHER_MODE_OCB); ++ if (gpg_err_code (err) != GPG_ERR_NOT_SUPPORTED) ++ fail ("cipher-ocb, gcry_control did not fail as expected (large, algo %d): %s\n", ++ algo, gpg_strerror (err)); ++ } ++ + err = gcry_cipher_open (&hde, algo, GCRY_CIPHER_MODE_OCB, 0); + if (!err) + err = gcry_cipher_open (&hdd, algo, GCRY_CIPHER_MODE_OCB, 0); +@@ -6842,7 +6862,17 @@ check_ocb_cipher_checksum (int algo, int + blk[byteidx] |= 1 << bitpos; + } + +- err = gcry_cipher_open (&hde, algo, GCRY_CIPHER_MODE_OCB, 0); ++ /* Verify the FIPS indicator marks this as non-approved */ ++ if (in_fips_mode) ++ { ++ err = gcry_control (GCRYCTL_FIPS_SERVICE_INDICATOR_CIPHER, ++ algo, GCRY_CIPHER_MODE_OCB); ++ if (gpg_err_code (err) != GPG_ERR_NOT_SUPPORTED) ++ fail ("cipher-ocb, gcry_control did not fail as expected (checksum, algo %d): %s\n", ++ algo, gpg_strerror (err)); ++ } ++ ++ err = gcry_cipher_open (&hde, algo, GCRY_CIPHER_MODE_OCB, 0); + if (!err) + err = gcry_cipher_open (&hde2, algo, GCRY_CIPHER_MODE_OCB, 0); + if (!err) +@@ -7110,6 +7140,16 @@ check_ocb_cipher_splitaad (void) + aad[2] = tv[tidx].aad2? hex2buffer (tv[tidx].aad2, aadlen+2) : NULL; + aad[3] = tv[tidx].aad3? hex2buffer (tv[tidx].aad3, aadlen+3) : NULL; + ++ /* Verify the FIPS indicator marks this as non-approved */ ++ if (in_fips_mode) ++ { ++ err = gcry_control (GCRYCTL_FIPS_SERVICE_INDICATOR_CIPHER, ++ GCRY_CIPHER_AES, GCRY_CIPHER_MODE_OCB); ++ if (gpg_err_code (err) != GPG_ERR_NOT_SUPPORTED) ++ fail ("cipher-ocb-splitaad, gcry_control did not fail as expected: %s\n", ++ gpg_strerror (err)); ++ } ++ + err = gcry_cipher_open (&hde, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_OCB, 0); + if (err) + { +@@ -9044,6 +9084,17 @@ check_bulk_cipher_modes (void) + fprintf (stderr, " checking bulk encryption for %s [%i], mode %d\n", + gcry_cipher_algo_name (tv[i].algo), + tv[i].algo, tv[i].mode); ++ ++ /* Verify the FIPS indicator marks approved cipher/modes combinations */ ++ if (in_fips_mode) ++ { ++ err = gcry_control (GCRYCTL_FIPS_SERVICE_INDICATOR_CIPHER, ++ tv[i].algo, tv[i].mode); ++ if (gpg_err_code (err) != GPG_ERR_NO_ERROR) ++ fail ("gcry_control unexpectedly failed for algo = %s, mode = %d : %s\n", ++ gcry_cipher_algo_name (tv[i].algo), tv[i].mode, gpg_strerror (err)); ++ } ++ + err = gcry_cipher_open (&hde, tv[i].algo, tv[i].mode, 0); + if (!err) + err = gcry_cipher_open (&hdd, tv[i].algo, tv[i].mode, 0); +Index: libgcrypt-1.9.4/doc/gcrypt.texi +=================================================================== +--- libgcrypt-1.9.4.orig/doc/gcrypt.texi ++++ libgcrypt-1.9.4/doc/gcrypt.texi +@@ -961,6 +961,19 @@ been registered with Libgpg-error and ad + clamp again. Obviously this control code may only be used before a + second thread is started in a process. + ++@item GCRYCTL_FIPS_SERVICE_INDICATOR_CIPHER; Arguments: enum gcry_cipher_algos [, enum gcry_cipher_modes] ++ ++Check if the given symmetric cipher and optional cipher mode combination ++is approved under the current FIPS 140-3 certification. If the ++combination is approved, this function returns @code{GPG_ERR_NO_ERROR}. ++Otherwise @code{GPG_ERR_NOT_SUPPORTED} is returned. ++ ++@item GCRYCTL_FIPS_SERVICE_INDICATOR_KDF; Arguments: enum gcry_kdf_algos ++ ++Check if the given KDF is approved under the current FIPS 140-3 ++certification. If the KDF is approved, this function returns ++@code{GPG_ERR_NO_ERROR}. Otherwise @code{GPG_ERR_NOT_SUPPORTED} ++is returned. + + @end table + +@@ -980,7 +993,7 @@ descriptive message to the user and canc + + Some error values do not indicate a system error or an error in the + operation, but the result of an operation that failed properly. For +-example, if you try to decrypt a tempered message, the decryption will ++example, if you try to decrypt a tampered message, the decryption will + fail. Another error value actually means that the end of a data + buffer or list has been reached. The following descriptions explain + for many error codes what they mean usually. Some error values have +@@ -6320,25 +6333,6 @@ The following symmetric encryption algor + power-up: + + @table @asis +-@item 3DES +-To test the 3DES 3-key EDE encryption in ECB mode these tests are +-run: +-@enumerate +-@item +-A known answer test is run on a 64 bit test vector processed by 64 +-rounds of Single-DES block encryption and decryption using a key +-changed with each round. +-@item +-A known answer test is run on a 64 bit test vector processed by 16 +-rounds of 2-key and 3-key Triple-DES block encryption and decryptions +-using a key changed with each round. +-@item +-10 known answer tests using 3-key Triple-DES EDE encryption, comparing +-the ciphertext to the known value, then running a decryption and +-comparing it to the initial plaintext. +-@end enumerate +-(@code{cipher/des.c:selftest}) +- + @item AES-128 + A known answer tests is run using one test vector and one test + key with AES in ECB mode. (@code{cipher/rijndael.c:selftest_basic_128}) +@@ -6394,6 +6388,9 @@ A known answer test using 28 byte of dat + @item HMAC SHA-512 + A known answer test using 28 byte of data and a 4 byte key is run. + (@code{cipher/hmac-tests.c:selftests_sha512}) ++@item CMAC AES ++A known answer test using 40 byte of data and a 16 byte key is run. ++(@code{cipher/mac-cmac.c:selftests_cmac_aes}) + @end table + + @subsection Random Number Power-Up Test +@@ -6416,7 +6413,7 @@ The public key algorithms are tested dur + + @table @asis + @item RSA +-A pre-defined 1024 bit RSA key is used and these tests are run ++A pre-defined 2048 bit RSA key is used and these tests are run + in turn: + @enumerate + @item +@@ -6426,14 +6423,14 @@ Conversion of S-expression to internal f + Private key consistency check. + (@code{cipher/@/rsa.c:@/selftests_rsa}) + @item +-A pre-defined 20 byte value is signed with PKCS#1 padding for SHA-1. ++A pre-defined 20 byte value is signed with PKCS#1 padding for SHA-256. + The result is verified using the public key against the original data +-and against modified data. (@code{cipher/@/rsa.c:@/selftest_sign_1024}) ++and against modified data. (@code{cipher/@/rsa.c:@/selftest_sign_2048}) + @item +-A 1000 bit random value is encrypted and checked that it does not +-match the original random value. The encrypted result is then ++A predefined 66 byte value is encrypted and checked that it matches ++reference encyrpted message. The encrypted result is then + decrypted and checked that it matches the original random value. +-(@code{cipher/@/rsa.c:@/selftest_encr_1024}) ++(@code{cipher/@/rsa.c:@/selftest_encr_2048}) + @end enumerate + + @item DSA +@@ -6463,15 +6461,6 @@ of the same name but with a single dot a + @file{.hmac}. + + +-@subsection Critical Functions Power-Up Tests +- +-The 3DES weak key detection is tested during power-up by calling the +-detection function with keys taken from a table listening all weak +-keys. The table itself is protected using a SHA-1 hash. +-(@code{cipher/@/des.c:@/selftest}) +- +- +- + @c -------------------------------- + @section Conditional Tests + +@@ -6645,8 +6634,6 @@ If Libgcrypt is used in FIPS mode these + The cryptographic algorithms are restricted to this list: + + @table @asis +-@item GCRY_CIPHER_3DES +-3 key EDE Triple-DES symmetric encryption. + @item GCRY_CIPHER_AES128 + AES 128 bit symmetric encryption. + @item GCRY_CIPHER_AES192 +@@ -6673,6 +6660,8 @@ HMAC using a SHA-256 message digest. + HMAC using a SHA-384 message digest. + @item GCRY_MD_SHA512,GCRY_MD_FLAG_HMAC + HMAC using a SHA-512 message digest. ++@item GCRY_MAC_CMAC_AES ++CMAC using a AES key. + @item GCRY_PK_RSA + RSA encryption and signing. + @item GCRY_PK_DSA +@@ -6683,8 +6672,8 @@ Note that the CRC algorithms are not con + and thus are in addition available. + + @item +-RSA key generation refuses to create a key with a keysize of +-less than 1024 bits. ++RSA key generation refuses to create and uyse ea key with a keysize of ++less than 2048 bits. + + @item + DSA key generation refuses to create a key with a keysize other +@@ -6697,8 +6686,9 @@ The @code{transient-key} flag for RSA an + Support for the VIA Padlock engine is disabled. + + @item +-FIPS mode may only be used on systems with a /dev/random device. +-Switching into FIPS mode on other systems will fail at runtime. ++FIPS mode may only be used on systems with a /dev/random device or ++with a getentropy syscall. Switching into FIPS mode on other systems ++will fail at runtime. + + @item + Saving and loading a random seed file is ignored. +@@ -6731,11 +6721,15 @@ disables FIPS mode unless Enforced FIPS + Libgcrypt will enter the error state. + + @item ++The signatures using SHA-1 digest algorithm may not be used. ++ ++@item + In Enforced FIPS mode the command @code{GCRYCTL_DISABLE_SECMEM} is + ignored. In standard FIPS mode it disables FIPS mode. + + @item + A handler set by @code{gcry_set_outofcore_handler} is ignored. ++ + @item + A handler set by @code{gcry_set_fatalerror_handler} is ignored. + diff --git a/libgcrypt-FIPS-verify-unsupported-KDF-test.patch b/libgcrypt-FIPS-verify-unsupported-KDF-test.patch new file mode 100644 index 0000000..27c78f0 --- /dev/null +++ b/libgcrypt-FIPS-verify-unsupported-KDF-test.patch @@ -0,0 +1,68 @@ +From 0ab4e8063729147fb9abd463055785aac831bf5c Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Tue, 13 Jul 2021 16:58:54 +0200 +Subject: [PATCH 348/500] tests: Verify unsupported KDF tests fail in FIPS mode + +* tests/t-kdf.c (check_pbkdf2): Verify tests based on algorithms + unsupported in FIPS mode fail. +-- + +Signed-off-by: Jakub Jelen +--- + tests/t-kdf.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +Index: libgcrypt-1.9.4/tests/t-kdf.c +=================================================================== +--- libgcrypt-1.9.4.orig/tests/t-kdf.c ++++ libgcrypt-1.9.4/tests/t-kdf.c +@@ -998,7 +998,7 @@ check_pbkdf2 (void) + "\xa5\x7a\xe5\xa6\x08\x83\x96\xd1\x20\x85\x0c\x5c\x09\xde\x0a\x52" + "\x51\x00\x93\x8a\x59\xb1\xb5\xc3\xf7\x81\x09\x10\xd0\x5f\xcd\x97" + }, */ +- { ++ /* { -- not FIPS approved + "passwordPASSWORDpassword", 24, + "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, + GCRY_MD_GOSTR3411_CP, +@@ -1007,7 +1007,7 @@ check_pbkdf2 (void) + "\x78\x83\x58\xc6\x9c\xb2\xdb\xe2\x51\xa7\xbb\x17\xd5\xf4\x24\x1f" + "\x26\x5a\x79\x2a\x35\xbe\xcd\xe8\xd5\x6f\x32\x6b\x49\xc8\x50\x47" + "\xb7\x63\x8a\xcb\x47\x64\xb1\xfd" +- }, ++ }, */ + { + "pass\0word", 9, + "sa\0lt", 5, +@@ -1061,7 +1061,7 @@ check_pbkdf2 (void) + "\x1a\xdb\x60\x1c\x7e\x2a\x31\x4e\x8c\xb7\xb1\xe9\xdf\x84\x0e\x36" + "\xab\x56\x15\xbe\x5d\x74\x2b\x6c\xf2\x03\xfb\x55\xfd\xc4\x80\x71" + }, */ +- { ++ /* { -- not FIPS approved + "passwordPASSWORDpassword", 24, + "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, + GCRY_MD_STRIBOG512, +@@ -1074,7 +1074,7 @@ check_pbkdf2 (void) + "\xbd\x24\x21\xee\x9b\xb7\x11\x83\xba\x88\x2c\xee\xbf\xef\x25\x9f" + "\x33\xf9\xe2\x7d\xc6\x17\x8c\xb8\x9d\xc3\x74\x28\xcf\x9c\xc5\x2a" + "\x2b\xaa\x2d\x3a" +- }, ++ }, */ + { + "pass\0word", 9, + "sa\0lt", 5, +@@ -1104,6 +1104,13 @@ check_pbkdf2 (void) + GCRY_KDF_PBKDF2, tv[tvidx].hashalgo, + tv[tvidx].salt, tv[tvidx].saltlen, + tv[tvidx].c, tv[tvidx].dklen, outbuf); ++ if (gcry_fips_mode_active() && tvidx > 6) ++ { ++ if (!err) ++ fail ("pbkdf2 test %d unexpectedly passed in FIPS mode: %s\n", ++ tvidx, gpg_strerror (err)); ++ continue; ++ } + if (err) + fail ("pbkdf2 test %d failed: %s\n", tvidx, gpg_strerror (err)); + else if (memcmp (outbuf, tv[tvidx].dk, tv[tvidx].dklen)) diff --git a/libgcrypt-Optimized-chacha20-poly1305-for-P10-operation.patch b/libgcrypt-Optimized-chacha20-poly1305-for-P10-operation.patch new file mode 100644 index 0000000..fa09a5e --- /dev/null +++ b/libgcrypt-Optimized-chacha20-poly1305-for-P10-operation.patch @@ -0,0 +1,2028 @@ +From 88fe7ac33eb4cb4dff76a5cc7fca50da5fb0ee3a Mon Sep 17 00:00:00 2001 +From: Danny Tsen +Date: Sun, 12 Jun 2022 21:30:19 +0300 +Subject: Chacha20/poly1305 - Optimized chacha20/poly1305 for P10 operation + +* configure.ac: Added chacha20 and poly1305 assembly implementations. +* cipher/chacha20-p10le-8x.s: (New) - support 8 blocks (512 bytes) +unrolling. +* cipher/poly1305-p10le.s: (New) - support 4 blocks (128 bytes) +unrolling. +* cipher/Makefile.am: Added new chacha20 and poly1305 files. +* cipher/chacha20.c: Added PPC p10 le support for 8x chacha20. +* cipher/poly1305.c: Added PPC p10 le support for 4x poly1305. +* cipher/poly1305-internal.h: Added PPC p10 le support for poly1305. +--- + +GnuPG-bug-id: 6006 +Signed-off-by: Danny Tsen +[jk: cosmetic changes to C code] +[jk: fix building on ppc64be] +Signed-off-by: Jussi Kivilinna + +Index: libgcrypt-1.9.4/cipher/Makefile.am +=================================================================== +--- libgcrypt-1.9.4.orig/cipher/Makefile.am ++++ libgcrypt-1.9.4/cipher/Makefile.am +@@ -82,6 +82,7 @@ EXTRA_libcipher_la_SOURCES = \ + chacha20.c chacha20-amd64-ssse3.S chacha20-amd64-avx2.S \ + chacha20-armv7-neon.S chacha20-aarch64.S \ + chacha20-ppc.c chacha20-s390x.S \ ++ chacha20-p10le-8x.s \ + cipher-gcm-ppc.c cipher-gcm-intel-pclmul.c cipher-gcm-armv7-neon.S \ + cipher-gcm-armv8-aarch32-ce.S cipher-gcm-armv8-aarch64-ce.S \ + crc.c crc-intel-pclmul.c crc-armv8-ce.c \ +@@ -97,6 +98,7 @@ EXTRA_libcipher_la_SOURCES = \ + gostr3411-94.c \ + md4.c \ + md5.c \ ++ poly1305-p10le.s \ + rijndael.c rijndael-internal.h rijndael-tables.h \ + rijndael-aesni.c rijndael-padlock.c \ + rijndael-amd64.S rijndael-arm.S \ +Index: libgcrypt-1.9.4/cipher/chacha20-p10le-8x.s +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/cipher/chacha20-p10le-8x.s +@@ -0,0 +1,864 @@ ++# Copyright 2021- IBM Inc. All rights reserved ++# ++# 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 . ++# ++#=================================================================================== ++# Written by Danny Tsen ++# ++# This function handles multiple 64-byte block data length ++# and the length should be more than 512 bytes. ++# ++# unsigned int _gcry_chacha20_p10le_8x(u32 *state, byte *dst, const byte *src, size_t len); ++# ++# r1 - top of the stack ++# r3 to r10 input parameters ++# r3 - out ++# r4 - inp ++# r5 - len ++# r6 - key[8] ++# r7 - counter[4] ++# ++# do rounds, 8 quarter rounds ++# 1. a += b; d ^= a; d <<<= 16; ++# 2. c += d; b ^= c; b <<<= 12; ++# 3. a += b; d ^= a; d <<<= 8; ++# 4. c += d; b ^= c; b <<<= 7 ++# ++# row1 = (row1 + row2), row4 = row1 xor row4, row4 rotate each word by 16 ++# row3 = (row3 + row4), row2 = row3 xor row2, row2 rotate each word by 12 ++# row1 = (row1 + row2), row4 = row1 xor row4, row4 rotate each word by 8 ++# row3 = (row3 + row4), row2 = row3 xor row2, row2 rotate each word by 7 ++# ++# 4 blocks (a b c d) ++# ++# a0 b0 c0 d0 ++# a1 b1 c1 d1 ++# ... ++# a4 b4 c4 d4 ++# ... ++# a8 b8 c8 d8 ++# ... ++# a12 b12 c12 d12 ++# a13 ... ++# a14 ... ++# a15 b15 c15 d15 ++# ++# Column round (v0, v4, v8, v12, v1, v5, v9, v13, v2, v6, v10, v14, v3, v7, v11, v15) ++# Diagnal round (v0, v5, v10, v15, v1, v6, v11, v12, v2, v7, v8, v13, v3, v4, v9, v14) ++# ++.text ++ ++.macro QT_loop_8x ++ # QR(v0, v4, v8, v12, v1, v5, v9, v13, v2, v6, v10, v14, v3, v7, v11, v15) ++ xxlor 0, 32+25, 32+25 ++ xxlor 32+25, 20, 20 ++ vadduwm 0, 0, 4 ++ vadduwm 1, 1, 5 ++ vadduwm 2, 2, 6 ++ vadduwm 3, 3, 7 ++ vadduwm 16, 16, 20 ++ vadduwm 17, 17, 21 ++ vadduwm 18, 18, 22 ++ vadduwm 19, 19, 23 ++ ++ vpermxor 12, 12, 0, 25 ++ vpermxor 13, 13, 1, 25 ++ vpermxor 14, 14, 2, 25 ++ vpermxor 15, 15, 3, 25 ++ vpermxor 28, 28, 16, 25 ++ vpermxor 29, 29, 17, 25 ++ vpermxor 30, 30, 18, 25 ++ vpermxor 31, 31, 19, 25 ++ xxlor 32+25, 0, 0 ++ vadduwm 8, 8, 12 ++ vadduwm 9, 9, 13 ++ vadduwm 10, 10, 14 ++ vadduwm 11, 11, 15 ++ vadduwm 24, 24, 28 ++ vadduwm 25, 25, 29 ++ vadduwm 26, 26, 30 ++ vadduwm 27, 27, 31 ++ vxor 4, 4, 8 ++ vxor 5, 5, 9 ++ vxor 6, 6, 10 ++ vxor 7, 7, 11 ++ vxor 20, 20, 24 ++ vxor 21, 21, 25 ++ vxor 22, 22, 26 ++ vxor 23, 23, 27 ++ ++ xxlor 0, 32+25, 32+25 ++ xxlor 32+25, 21, 21 ++ vrlw 4, 4, 25 # ++ vrlw 5, 5, 25 ++ vrlw 6, 6, 25 ++ vrlw 7, 7, 25 ++ vrlw 20, 20, 25 # ++ vrlw 21, 21, 25 ++ vrlw 22, 22, 25 ++ vrlw 23, 23, 25 ++ xxlor 32+25, 0, 0 ++ vadduwm 0, 0, 4 ++ vadduwm 1, 1, 5 ++ vadduwm 2, 2, 6 ++ vadduwm 3, 3, 7 ++ vadduwm 16, 16, 20 ++ vadduwm 17, 17, 21 ++ vadduwm 18, 18, 22 ++ vadduwm 19, 19, 23 ++ ++ xxlor 0, 32+25, 32+25 ++ xxlor 32+25, 22, 22 ++ vpermxor 12, 12, 0, 25 ++ vpermxor 13, 13, 1, 25 ++ vpermxor 14, 14, 2, 25 ++ vpermxor 15, 15, 3, 25 ++ vpermxor 28, 28, 16, 25 ++ vpermxor 29, 29, 17, 25 ++ vpermxor 30, 30, 18, 25 ++ vpermxor 31, 31, 19, 25 ++ xxlor 32+25, 0, 0 ++ vadduwm 8, 8, 12 ++ vadduwm 9, 9, 13 ++ vadduwm 10, 10, 14 ++ vadduwm 11, 11, 15 ++ vadduwm 24, 24, 28 ++ vadduwm 25, 25, 29 ++ vadduwm 26, 26, 30 ++ vadduwm 27, 27, 31 ++ xxlor 0, 32+28, 32+28 ++ xxlor 32+28, 23, 23 ++ vxor 4, 4, 8 ++ vxor 5, 5, 9 ++ vxor 6, 6, 10 ++ vxor 7, 7, 11 ++ vxor 20, 20, 24 ++ vxor 21, 21, 25 ++ vxor 22, 22, 26 ++ vxor 23, 23, 27 ++ vrlw 4, 4, 28 # ++ vrlw 5, 5, 28 ++ vrlw 6, 6, 28 ++ vrlw 7, 7, 28 ++ vrlw 20, 20, 28 # ++ vrlw 21, 21, 28 ++ vrlw 22, 22, 28 ++ vrlw 23, 23, 28 ++ xxlor 32+28, 0, 0 ++ ++ # QR(v0, v5, v10, v15, v1, v6, v11, v12, v2, v7, v8, v13, v3, v4, v9, v14) ++ xxlor 0, 32+25, 32+25 ++ xxlor 32+25, 20, 20 ++ vadduwm 0, 0, 5 ++ vadduwm 1, 1, 6 ++ vadduwm 2, 2, 7 ++ vadduwm 3, 3, 4 ++ vadduwm 16, 16, 21 ++ vadduwm 17, 17, 22 ++ vadduwm 18, 18, 23 ++ vadduwm 19, 19, 20 ++ ++ vpermxor 15, 15, 0, 25 ++ vpermxor 12, 12, 1, 25 ++ vpermxor 13, 13, 2, 25 ++ vpermxor 14, 14, 3, 25 ++ vpermxor 31, 31, 16, 25 ++ vpermxor 28, 28, 17, 25 ++ vpermxor 29, 29, 18, 25 ++ vpermxor 30, 30, 19, 25 ++ ++ xxlor 32+25, 0, 0 ++ vadduwm 10, 10, 15 ++ vadduwm 11, 11, 12 ++ vadduwm 8, 8, 13 ++ vadduwm 9, 9, 14 ++ vadduwm 26, 26, 31 ++ vadduwm 27, 27, 28 ++ vadduwm 24, 24, 29 ++ vadduwm 25, 25, 30 ++ vxor 5, 5, 10 ++ vxor 6, 6, 11 ++ vxor 7, 7, 8 ++ vxor 4, 4, 9 ++ vxor 21, 21, 26 ++ vxor 22, 22, 27 ++ vxor 23, 23, 24 ++ vxor 20, 20, 25 ++ ++ xxlor 0, 32+25, 32+25 ++ xxlor 32+25, 21, 21 ++ vrlw 5, 5, 25 ++ vrlw 6, 6, 25 ++ vrlw 7, 7, 25 ++ vrlw 4, 4, 25 ++ vrlw 21, 21, 25 ++ vrlw 22, 22, 25 ++ vrlw 23, 23, 25 ++ vrlw 20, 20, 25 ++ xxlor 32+25, 0, 0 ++ ++ vadduwm 0, 0, 5 ++ vadduwm 1, 1, 6 ++ vadduwm 2, 2, 7 ++ vadduwm 3, 3, 4 ++ vadduwm 16, 16, 21 ++ vadduwm 17, 17, 22 ++ vadduwm 18, 18, 23 ++ vadduwm 19, 19, 20 ++ ++ xxlor 0, 32+25, 32+25 ++ xxlor 32+25, 22, 22 ++ vpermxor 15, 15, 0, 25 ++ vpermxor 12, 12, 1, 25 ++ vpermxor 13, 13, 2, 25 ++ vpermxor 14, 14, 3, 25 ++ vpermxor 31, 31, 16, 25 ++ vpermxor 28, 28, 17, 25 ++ vpermxor 29, 29, 18, 25 ++ vpermxor 30, 30, 19, 25 ++ xxlor 32+25, 0, 0 ++ ++ vadduwm 10, 10, 15 ++ vadduwm 11, 11, 12 ++ vadduwm 8, 8, 13 ++ vadduwm 9, 9, 14 ++ vadduwm 26, 26, 31 ++ vadduwm 27, 27, 28 ++ vadduwm 24, 24, 29 ++ vadduwm 25, 25, 30 ++ ++ xxlor 0, 32+28, 32+28 ++ xxlor 32+28, 23, 23 ++ vxor 5, 5, 10 ++ vxor 6, 6, 11 ++ vxor 7, 7, 8 ++ vxor 4, 4, 9 ++ vxor 21, 21, 26 ++ vxor 22, 22, 27 ++ vxor 23, 23, 24 ++ vxor 20, 20, 25 ++ vrlw 5, 5, 28 ++ vrlw 6, 6, 28 ++ vrlw 7, 7, 28 ++ vrlw 4, 4, 28 ++ vrlw 21, 21, 28 ++ vrlw 22, 22, 28 ++ vrlw 23, 23, 28 ++ vrlw 20, 20, 28 ++ xxlor 32+28, 0, 0 ++.endm ++ ++.macro QT_loop_4x ++ # QR(v0, v4, v8, v12, v1, v5, v9, v13, v2, v6, v10, v14, v3, v7, v11, v15) ++ vadduwm 0, 0, 4 ++ vadduwm 1, 1, 5 ++ vadduwm 2, 2, 6 ++ vadduwm 3, 3, 7 ++ vpermxor 12, 12, 0, 20 ++ vpermxor 13, 13, 1, 20 ++ vpermxor 14, 14, 2, 20 ++ vpermxor 15, 15, 3, 20 ++ vadduwm 8, 8, 12 ++ vadduwm 9, 9, 13 ++ vadduwm 10, 10, 14 ++ vadduwm 11, 11, 15 ++ vxor 4, 4, 8 ++ vxor 5, 5, 9 ++ vxor 6, 6, 10 ++ vxor 7, 7, 11 ++ vrlw 4, 4, 21 ++ vrlw 5, 5, 21 ++ vrlw 6, 6, 21 ++ vrlw 7, 7, 21 ++ vadduwm 0, 0, 4 ++ vadduwm 1, 1, 5 ++ vadduwm 2, 2, 6 ++ vadduwm 3, 3, 7 ++ vpermxor 12, 12, 0, 22 ++ vpermxor 13, 13, 1, 22 ++ vpermxor 14, 14, 2, 22 ++ vpermxor 15, 15, 3, 22 ++ vadduwm 8, 8, 12 ++ vadduwm 9, 9, 13 ++ vadduwm 10, 10, 14 ++ vadduwm 11, 11, 15 ++ vxor 4, 4, 8 ++ vxor 5, 5, 9 ++ vxor 6, 6, 10 ++ vxor 7, 7, 11 ++ vrlw 4, 4, 23 ++ vrlw 5, 5, 23 ++ vrlw 6, 6, 23 ++ vrlw 7, 7, 23 ++ ++ # QR(v0, v5, v10, v15, v1, v6, v11, v12, v2, v7, v8, v13, v3, v4, v9, v14) ++ vadduwm 0, 0, 5 ++ vadduwm 1, 1, 6 ++ vadduwm 2, 2, 7 ++ vadduwm 3, 3, 4 ++ vpermxor 15, 15, 0, 20 ++ vpermxor 12, 12, 1, 20 ++ vpermxor 13, 13, 2, 20 ++ vpermxor 14, 14, 3, 20 ++ vadduwm 10, 10, 15 ++ vadduwm 11, 11, 12 ++ vadduwm 8, 8, 13 ++ vadduwm 9, 9, 14 ++ vxor 5, 5, 10 ++ vxor 6, 6, 11 ++ vxor 7, 7, 8 ++ vxor 4, 4, 9 ++ vrlw 5, 5, 21 ++ vrlw 6, 6, 21 ++ vrlw 7, 7, 21 ++ vrlw 4, 4, 21 ++ vadduwm 0, 0, 5 ++ vadduwm 1, 1, 6 ++ vadduwm 2, 2, 7 ++ vadduwm 3, 3, 4 ++ vpermxor 15, 15, 0, 22 ++ vpermxor 12, 12, 1, 22 ++ vpermxor 13, 13, 2, 22 ++ vpermxor 14, 14, 3, 22 ++ vadduwm 10, 10, 15 ++ vadduwm 11, 11, 12 ++ vadduwm 8, 8, 13 ++ vadduwm 9, 9, 14 ++ vxor 5, 5, 10 ++ vxor 6, 6, 11 ++ vxor 7, 7, 8 ++ vxor 4, 4, 9 ++ vrlw 5, 5, 23 ++ vrlw 6, 6, 23 ++ vrlw 7, 7, 23 ++ vrlw 4, 4, 23 ++.endm ++ ++# Transpose ++.macro TP_4x a0 a1 a2 a3 ++ xxmrghw 10, 32+\a0, 32+\a1 # a0, a1, b0, b1 ++ xxmrghw 11, 32+\a2, 32+\a3 # a2, a3, b2, b3 ++ xxmrglw 12, 32+\a0, 32+\a1 # c0, c1, d0, d1 ++ xxmrglw 13, 32+\a2, 32+\a3 # c2, c3, d2, d3 ++ xxpermdi 32+\a0, 10, 11, 0 # a0, a1, a2, a3 ++ xxpermdi 32+\a1, 10, 11, 3 # b0, b1, b2, b3 ++ xxpermdi 32+\a2, 12, 13, 0 # c0, c1, c2, c3 ++ xxpermdi 32+\a3, 12, 13, 3 # d0, d1, d2, d3 ++.endm ++ ++# key stream = working state + state ++.macro Add_state S ++ vadduwm \S+0, \S+0, 16-\S ++ vadduwm \S+4, \S+4, 17-\S ++ vadduwm \S+8, \S+8, 18-\S ++ vadduwm \S+12, \S+12, 19-\S ++ ++ vadduwm \S+1, \S+1, 16-\S ++ vadduwm \S+5, \S+5, 17-\S ++ vadduwm \S+9, \S+9, 18-\S ++ vadduwm \S+13, \S+13, 19-\S ++ ++ vadduwm \S+2, \S+2, 16-\S ++ vadduwm \S+6, \S+6, 17-\S ++ vadduwm \S+10, \S+10, 18-\S ++ vadduwm \S+14, \S+14, 19-\S ++ ++ vadduwm \S+3, \S+3, 16-\S ++ vadduwm \S+7, \S+7, 17-\S ++ vadduwm \S+11, \S+11, 18-\S ++ vadduwm \S+15, \S+15, 19-\S ++.endm ++ ++# ++# write 256 bytes ++# ++.macro Write_256 S ++ add 9, 14, 5 ++ add 16, 14, 4 ++ lxvw4x 0, 0, 9 ++ lxvw4x 1, 17, 9 ++ lxvw4x 2, 18, 9 ++ lxvw4x 3, 19, 9 ++ lxvw4x 4, 20, 9 ++ lxvw4x 5, 21, 9 ++ lxvw4x 6, 22, 9 ++ lxvw4x 7, 23, 9 ++ lxvw4x 8, 24, 9 ++ lxvw4x 9, 25, 9 ++ lxvw4x 10, 26, 9 ++ lxvw4x 11, 27, 9 ++ lxvw4x 12, 28, 9 ++ lxvw4x 13, 29, 9 ++ lxvw4x 14, 30, 9 ++ lxvw4x 15, 31, 9 ++ ++ xxlxor \S+32, \S+32, 0 ++ xxlxor \S+36, \S+36, 1 ++ xxlxor \S+40, \S+40, 2 ++ xxlxor \S+44, \S+44, 3 ++ xxlxor \S+33, \S+33, 4 ++ xxlxor \S+37, \S+37, 5 ++ xxlxor \S+41, \S+41, 6 ++ xxlxor \S+45, \S+45, 7 ++ xxlxor \S+34, \S+34, 8 ++ xxlxor \S+38, \S+38, 9 ++ xxlxor \S+42, \S+42, 10 ++ xxlxor \S+46, \S+46, 11 ++ xxlxor \S+35, \S+35, 12 ++ xxlxor \S+39, \S+39, 13 ++ xxlxor \S+43, \S+43, 14 ++ xxlxor \S+47, \S+47, 15 ++ ++ stxvw4x \S+32, 0, 16 ++ stxvw4x \S+36, 17, 16 ++ stxvw4x \S+40, 18, 16 ++ stxvw4x \S+44, 19, 16 ++ ++ stxvw4x \S+33, 20, 16 ++ stxvw4x \S+37, 21, 16 ++ stxvw4x \S+41, 22, 16 ++ stxvw4x \S+45, 23, 16 ++ ++ stxvw4x \S+34, 24, 16 ++ stxvw4x \S+38, 25, 16 ++ stxvw4x \S+42, 26, 16 ++ stxvw4x \S+46, 27, 16 ++ ++ stxvw4x \S+35, 28, 16 ++ stxvw4x \S+39, 29, 16 ++ stxvw4x \S+43, 30, 16 ++ stxvw4x \S+47, 31, 16 ++ ++.endm ++ ++# ++# unsigned int _gcry_chacha20_p10le_8x(u32 *state, byte *dst, const byte *src, size_t len); ++# ++.global _gcry_chacha20_p10le_8x ++.align 5 ++_gcry_chacha20_p10le_8x: ++ cmpdi 6, 512 ++ blt Out_no_chacha ++ ++ stdu 1,-1024(1) ++ mflr 0 ++ ++ std 14,112(1) ++ std 15,120(1) ++ std 16,128(1) ++ std 17,136(1) ++ std 18,144(1) ++ std 19,152(1) ++ std 20,160(1) ++ std 21,168(1) ++ std 22,176(1) ++ std 23,184(1) ++ std 24,192(1) ++ std 25,200(1) ++ std 26,208(1) ++ std 27,216(1) ++ std 28,224(1) ++ std 29,232(1) ++ std 30,240(1) ++ std 31,248(1) ++ std 0, 1040(1) ++ ++ li 17, 16 ++ li 18, 32 ++ li 19, 48 ++ li 20, 64 ++ li 21, 80 ++ li 22, 96 ++ li 23, 112 ++ li 24, 128 ++ li 25, 144 ++ li 26, 160 ++ li 27, 176 ++ li 28, 192 ++ li 29, 208 ++ li 30, 224 ++ li 31, 240 ++ addi 9, 1, 256 ++ stvx 20, 0, 9 ++ stvx 21, 17, 9 ++ stvx 22, 18, 9 ++ stvx 23, 19, 9 ++ stvx 24, 20, 9 ++ stvx 25, 21, 9 ++ stvx 26, 22, 9 ++ stvx 27, 23, 9 ++ stvx 28, 24, 9 ++ stvx 29, 25, 9 ++ stvx 30, 26, 9 ++ stvx 31, 27, 9 ++ ++ add 9, 9, 27 ++ addi 14, 17, 16 ++ stxvx 14, 14, 9 ++ addi 14, 14, 16 ++ stxvx 15, 14, 9 ++ addi 14, 14, 16 ++ stxvx 16, 14, 9 ++ addi 14, 14, 16 ++ stxvx 17, 14, 9 ++ addi 14, 14, 16 ++ stxvx 18, 14, 9 ++ addi 14, 14, 16 ++ stxvx 19, 14, 9 ++ addi 14, 14, 16 ++ stxvx 20, 14, 9 ++ addi 14, 14, 16 ++ stxvx 21, 14, 9 ++ addi 14, 14, 16 ++ stxvx 22, 14, 9 ++ addi 14, 14, 16 ++ stxvx 23, 14, 9 ++ addi 14, 14, 16 ++ stxvx 24, 14, 9 ++ addi 14, 14, 16 ++ stxvx 25, 14, 9 ++ addi 14, 14, 16 ++ stxvx 26, 14, 9 ++ addi 14, 14, 16 ++ stxvx 27, 14, 9 ++ addi 14, 14, 16 ++ stxvx 28, 14, 9 ++ addi 14, 14, 16 ++ stxvx 29, 14, 9 ++ addi 14, 14, 16 ++ stxvx 30, 14, 9 ++ addi 14, 14, 16 ++ stxvx 31, 14, 9 ++ ++ mr 15, 6 # len ++ li 14, 0 # offset to inp and outp ++ ++ ld 10, sigma@got(2) ++ ++ lxvw4x 48, 0, 3 # vr16, constants ++ lxvw4x 49, 17, 3 # vr17, key 1 ++ lxvw4x 50, 18, 3 # vr18, key 2 ++ lxvw4x 51, 19, 3 # vr19, counter, nonce ++ ++ lxvw4x 62, 19, 10 # vr30, 4 ++ ++ vspltisw 21, 12 ++ vspltisw 23, 7 ++ ++ ld 11, permx@got(2) ++ lxvw4x 32+20, 0, 11 ++ lxvw4x 32+22, 17, 11 ++ ++ li 8, 10 ++ mtctr 8 ++ ++ xxlor 16, 48, 48 ++ xxlor 17, 49, 49 ++ xxlor 18, 50, 50 ++ xxlor 19, 51, 51 ++ ++ vspltisw 25, 4 ++ vspltisw 26, 8 ++ ++ xxlor 16, 48, 48 ++ xxlor 17, 49, 49 ++ xxlor 18, 50, 50 ++ xxlor 19, 51, 51 ++ ++ xxlor 25, 32+26, 32+26 ++ xxlor 24, 32+25, 32+25 ++ ++ vadduwm 31, 30, 25 # (0, 1, 2, 3) + (4, 4, 4, 4) ++ xxlor 30, 32+30, 32+30 ++ xxlor 31, 32+31, 32+31 ++ ++ xxlor 20, 32+20, 32+20 ++ xxlor 21, 32+21, 32+21 ++ xxlor 22, 32+22, 32+22 ++ xxlor 23, 32+23, 32+23 ++ ++Loop_8x: ++ lvx 0, 20, 10 ++ lvx 1, 21, 10 ++ lvx 2, 22, 10 ++ lvx 3, 23, 10 ++ xxspltw 32+4, 17, 0 ++ xxspltw 32+5, 17, 1 ++ xxspltw 32+6, 17, 2 ++ xxspltw 32+7, 17, 3 ++ xxspltw 32+8, 18, 0 ++ xxspltw 32+9, 18, 1 ++ xxspltw 32+10, 18, 2 ++ xxspltw 32+11, 18, 3 ++ xxspltw 32+12, 19, 0 ++ xxspltw 32+13, 19, 1 ++ xxspltw 32+14, 19, 2 ++ xxspltw 32+15, 19, 3 ++ vadduwm 12, 12, 30 # increase counter ++ ++ lvx 16, 20, 10 ++ lvx 17, 21, 10 ++ lvx 18, 22, 10 ++ lvx 19, 23, 10 ++ xxspltw 32+20, 17, 0 ++ xxspltw 32+21, 17, 1 ++ xxspltw 32+22, 17, 2 ++ xxspltw 32+23, 17, 3 ++ xxspltw 32+24, 18, 0 ++ xxspltw 32+25, 18, 1 ++ xxspltw 32+26, 18, 2 ++ xxspltw 32+27, 18, 3 ++ xxspltw 32+28, 19, 0 ++ xxspltw 32+29, 19, 1 ++ vadduwm 28, 28, 31 # increase counter ++ xxspltw 32+30, 19, 2 ++ xxspltw 32+31, 19, 3 ++ ++.align 5 ++quarter_loop_8x: ++ QT_loop_8x ++ ++ bdnz quarter_loop_8x ++ ++ xxlor 0, 32+30, 32+30 ++ xxlor 32+30, 30, 30 ++ vadduwm 12, 12, 30 ++ xxlor 32+30, 0, 0 ++ TP_4x 0, 1, 2, 3 ++ TP_4x 4, 5, 6, 7 ++ TP_4x 8, 9, 10, 11 ++ TP_4x 12, 13, 14, 15 ++ ++ xxlor 0, 48, 48 ++ xxlor 1, 49, 49 ++ xxlor 2, 50, 50 ++ xxlor 3, 51, 51 ++ xxlor 48, 16, 16 ++ xxlor 49, 17, 17 ++ xxlor 50, 18, 18 ++ xxlor 51, 19, 19 ++ Add_state 0 ++ xxlor 48, 0, 0 ++ xxlor 49, 1, 1 ++ xxlor 50, 2, 2 ++ xxlor 51, 3, 3 ++ Write_256 0 ++ addi 14, 14, 256 ++ addi 15, 15, -256 ++ ++ xxlor 5, 32+31, 32+31 ++ xxlor 32+31, 31, 31 ++ vadduwm 28, 28, 31 ++ xxlor 32+31, 5, 5 ++ TP_4x 16+0, 16+1, 16+2, 16+3 ++ TP_4x 16+4, 16+5, 16+6, 16+7 ++ TP_4x 16+8, 16+9, 16+10, 16+11 ++ TP_4x 16+12, 16+13, 16+14, 16+15 ++ ++ xxlor 32, 16, 16 ++ xxlor 33, 17, 17 ++ xxlor 34, 18, 18 ++ xxlor 35, 19, 19 ++ Add_state 16 ++ Write_256 16 ++ addi 14, 14, 256 ++ addi 15, 15, -256 ++ ++ # should update counter before out? ++ xxlor 32+24, 24, 24 ++ xxlor 32+25, 25, 25 ++ xxlor 32+30, 30, 30 ++ vadduwm 30, 30, 25 ++ vadduwm 31, 30, 24 ++ xxlor 30, 32+30, 32+30 ++ xxlor 31, 32+31, 32+31 ++ ++ cmpdi 15, 0 ++ beq Out_loop ++ ++ cmpdi 15, 512 ++ blt Loop_last ++ ++ mtctr 8 ++ b Loop_8x ++ ++Loop_last: ++ lxvw4x 48, 0, 3 # vr16, constants ++ lxvw4x 49, 17, 3 # vr17, key 1 ++ lxvw4x 50, 18, 3 # vr18, key 2 ++ lxvw4x 51, 19, 3 # vr19, counter, nonce ++ ++ vspltisw 21, 12 ++ vspltisw 23, 7 ++ lxvw4x 32+20, 0, 11 ++ lxvw4x 32+22, 17, 11 ++ ++ li 8, 10 ++ mtctr 8 ++ ++Loop_4x: ++ lvx 0, 20, 10 ++ lvx 1, 21, 10 ++ lvx 2, 22, 10 ++ lvx 3, 23, 10 ++ vspltw 4, 17, 0 ++ vspltw 5, 17, 1 ++ vspltw 6, 17, 2 ++ vspltw 7, 17, 3 ++ vspltw 8, 18, 0 ++ vspltw 9, 18, 1 ++ vspltw 10, 18, 2 ++ vspltw 11, 18, 3 ++ vspltw 12, 19, 0 ++ vadduwm 12, 12, 30 # increase counter ++ vspltw 13, 19, 1 ++ vspltw 14, 19, 2 ++ vspltw 15, 19, 3 ++ ++.align 5 ++quarter_loop: ++ QT_loop_4x ++ ++ bdnz quarter_loop ++ ++ vadduwm 12, 12, 30 ++ TP_4x 0, 1, 2, 3 ++ TP_4x 4, 5, 6, 7 ++ TP_4x 8, 9, 10, 11 ++ TP_4x 12, 13, 14, 15 ++ ++ Add_state 0 ++ Write_256 0 ++ addi 14, 14, 256 ++ addi 15, 15, -256 ++ ++ # Update state counter ++ vspltisw 25, 4 ++ vadduwm 30, 30, 25 ++ ++ cmpdi 15, 0 ++ beq Out_loop ++ ++ mtctr 8 ++ b Loop_4x ++ ++Out_loop: ++ # ++ # Update state counter ++ # ++ vspltisb 16, -1 # first 16 bytes - 0xffff...ff ++ vspltisb 17, 0 # second 16 bytes - 0x0000...00 ++ vsldoi 18, 16, 17, 12 ++ vand 18, 18, 30 ++ xxlor 32+19, 19, 19 ++ vadduwm 18, 19, 18 ++ stxvw4x 32+18, 19, 3 ++ li 3, 0 ++ ++ addi 9, 1, 256 ++ lvx 20, 0, 9 ++ lvx 21, 17, 9 ++ lvx 22, 18, 9 ++ lvx 23, 19, 9 ++ lvx 24, 20, 9 ++ lvx 25, 21, 9 ++ lvx 26, 22, 9 ++ lvx 27, 23, 9 ++ lvx 28, 24, 9 ++ lvx 29, 25, 9 ++ lvx 30, 26, 9 ++ lvx 31, 27, 9 ++ ++ add 9, 9, 27 ++ addi 14, 17, 16 ++ lxvx 14, 14, 9 ++ addi 14, 14, 16 ++ lxvx 15, 14, 9 ++ addi 14, 14, 16 ++ lxvx 16, 14, 9 ++ addi 14, 14, 16 ++ lxvx 17, 14, 9 ++ addi 14, 14, 16 ++ lxvx 18, 14, 9 ++ addi 14, 14, 16 ++ lxvx 19, 14, 9 ++ addi 14, 14, 16 ++ lxvx 20, 14, 9 ++ addi 14, 14, 16 ++ lxvx 21, 14, 9 ++ addi 14, 14, 16 ++ lxvx 22, 14, 9 ++ addi 14, 14, 16 ++ lxvx 23, 14, 9 ++ addi 14, 14, 16 ++ lxvx 24, 14, 9 ++ addi 14, 14, 16 ++ lxvx 25, 14, 9 ++ addi 14, 14, 16 ++ lxvx 26, 14, 9 ++ addi 14, 14, 16 ++ lxvx 27, 14, 9 ++ addi 14, 14, 16 ++ lxvx 28, 14, 9 ++ addi 14, 14, 16 ++ lxvx 29, 14, 9 ++ addi 14, 14, 16 ++ lxvx 30, 14, 9 ++ addi 14, 14, 16 ++ lxvx 31, 14, 9 ++ ++ ld 0, 1040(1) ++ ld 14,112(1) ++ ld 15,120(1) ++ ld 16,128(1) ++ ld 17,136(1) ++ ld 18,144(1) ++ ld 19,152(1) ++ ld 20,160(1) ++ ld 21,168(1) ++ ld 22,176(1) ++ ld 23,184(1) ++ ld 24,192(1) ++ ld 25,200(1) ++ ld 26,208(1) ++ ld 27,216(1) ++ ld 28,224(1) ++ ld 29,232(1) ++ ld 30,240(1) ++ ld 31,248(1) ++ ++ mtlr 0 ++ addi 1, 1, 1024 ++ blr ++ ++Out_no_chacha: ++ li 3, 0 ++ blr ++ ++.data ++.align 4 ++sigma: ++.long 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 ++.long 0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203 ++.long 1, 0, 0, 0 ++.long 0, 1, 2, 3 ++.long 0x61707865, 0x61707865, 0x61707865, 0x61707865 ++.long 0x3320646e, 0x3320646e, 0x3320646e, 0x3320646e ++.long 0x79622d32, 0x79622d32, 0x79622d32, 0x79622d32 ++.long 0x6b206574, 0x6b206574, 0x6b206574, 0x6b206574 ++permx: ++.long 0x22330011, 0x66774455, 0xaabb8899, 0xeeffccdd ++.long 0x11223300, 0x55667744, 0x99aabb88, 0xddeeffcc +Index: libgcrypt-1.9.4/cipher/chacha20.c +=================================================================== +--- libgcrypt-1.9.4.orig/cipher/chacha20.c ++++ libgcrypt-1.9.4/cipher/chacha20.c +@@ -125,6 +125,7 @@ typedef struct CHACHA20_context_s + unsigned int use_avx2:1; + unsigned int use_neon:1; + unsigned int use_ppc:1; ++ unsigned int use_p10:1; + unsigned int use_s390x:1; + } CHACHA20_context_t; + +@@ -163,6 +164,12 @@ unsigned int _gcry_chacha20_poly1305_amd + + #ifdef USE_PPC_VEC + ++#ifndef WORDS_BIGENDIAN ++unsigned int _gcry_chacha20_p10le_8x(u32 *state, byte *dst, ++ const byte *src, ++ size_t len); ++#endif ++ + unsigned int _gcry_chacha20_ppc8_blocks4(u32 *state, byte *dst, + const byte *src, + size_t nblks); +@@ -475,6 +482,9 @@ chacha20_do_setkey (CHACHA20_context_t * + #endif + #ifdef USE_PPC_VEC + ctx->use_ppc = (features & HWF_PPC_ARCH_2_07) != 0; ++# ifndef WORDS_BIGENDIAN ++ ctx->use_p10 = (features & HWF_PPC_ARCH_3_10) != 0; ++# endif + #endif + #ifdef USE_S390X_VX + ctx->use_s390x = (features & HWF_S390X_VX) != 0; +@@ -571,7 +581,22 @@ do_chacha20_encrypt_stream_tail (CHACHA2 + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 4; +- nburn = _gcry_chacha20_ppc8_blocks4(ctx->input, outbuf, inbuf, nblocks); ++#ifndef WORDS_BIGENDIAN ++ /* ++ * A workaround to skip counter overflow. This is rare. ++ */ ++ if (ctx->use_p10 && nblocks >= 8 ++ && ((u64)ctx->input[12] + nblocks) <= 0xffffffffU) ++ { ++ size_t len = nblocks * CHACHA20_BLOCK_SIZE; ++ nburn = _gcry_chacha20_p10le_8x(ctx->input, outbuf, inbuf, len); ++ } ++ else ++#endif ++ { ++ nburn = _gcry_chacha20_ppc8_blocks4(ctx->input, outbuf, inbuf, ++ nblocks); ++ } + burn = nburn > burn ? nburn : burn; + length -= nblocks * CHACHA20_BLOCK_SIZE; + outbuf += nblocks * CHACHA20_BLOCK_SIZE; +@@ -760,6 +785,11 @@ _gcry_chacha20_poly1305_encrypt(gcry_cip + } + #endif + #ifdef USE_PPC_VEC_POLY1305 ++ else if (ctx->use_ppc && ctx->use_p10) ++ { ++ /* Skip stitched chacha20-poly1305 for P10. */ ++ authptr = NULL; ++ } + else if (ctx->use_ppc && length >= CHACHA20_BLOCK_SIZE * 4) + { + nburn = _gcry_chacha20_ppc8_blocks4(ctx->input, outbuf, inbuf, 4); +@@ -998,6 +1028,7 @@ _gcry_chacha20_poly1305_decrypt(gcry_cip + { + CHACHA20_context_t *ctx = (void *) &c->context.c; + unsigned int nburn, burn = 0; ++ int skip_stitched = 0; + + if (!length) + return 0; +@@ -1033,8 +1064,16 @@ _gcry_chacha20_poly1305_decrypt(gcry_cip + + gcry_assert (c->u_mode.poly1305.ctx.leftover == 0); + ++#ifdef USE_PPC_VEC_POLY1305 ++ if (ctx->use_ppc && ctx->use_p10) ++ { ++ /* Skip stitched chacha20-poly1305 for P10. */ ++ skip_stitched = 1; ++ } ++#endif ++ + #ifdef USE_AVX2 +- if (ctx->use_avx2 && length >= 8 * CHACHA20_BLOCK_SIZE) ++ if (!skip_stitched && ctx->use_avx2 && length >= 8 * CHACHA20_BLOCK_SIZE) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 8; +@@ -1051,7 +1090,7 @@ _gcry_chacha20_poly1305_decrypt(gcry_cip + #endif + + #ifdef USE_SSSE3 +- if (ctx->use_ssse3) ++ if (!skip_stitched && ctx->use_ssse3) + { + if (length >= 4 * CHACHA20_BLOCK_SIZE) + { +@@ -1085,7 +1124,7 @@ _gcry_chacha20_poly1305_decrypt(gcry_cip + #endif + + #ifdef USE_AARCH64_SIMD +- if (ctx->use_neon && length >= 4 * CHACHA20_BLOCK_SIZE) ++ if (!skip_stitched && ctx->use_neon && length >= 4 * CHACHA20_BLOCK_SIZE) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 4; +@@ -1102,7 +1141,8 @@ _gcry_chacha20_poly1305_decrypt(gcry_cip + #endif + + #ifdef USE_PPC_VEC_POLY1305 +- if (ctx->use_ppc && length >= 4 * CHACHA20_BLOCK_SIZE) ++ /* skip stitch for p10 */ ++ if (!skip_stitched && ctx->use_ppc && length >= 4 * CHACHA20_BLOCK_SIZE) + { + size_t nblocks = length / CHACHA20_BLOCK_SIZE; + nblocks -= nblocks % 4; +@@ -1119,7 +1159,7 @@ _gcry_chacha20_poly1305_decrypt(gcry_cip + #endif + + #ifdef USE_S390X_VX_POLY1305 +- if (ctx->use_s390x) ++ if (!skip_stitched && ctx->use_s390x) + { + if (length >= 8 * CHACHA20_BLOCK_SIZE) + { +Index: libgcrypt-1.9.4/cipher/poly1305-internal.h +=================================================================== +--- libgcrypt-1.9.4.orig/cipher/poly1305-internal.h ++++ libgcrypt-1.9.4/cipher/poly1305-internal.h +@@ -33,6 +33,18 @@ + #define POLY1305_KEYLEN 32 + #define POLY1305_BLOCKSIZE 16 + ++/* POLY1305_USE_PPC_VEC indicates whether to enable PowerPC vector code. */ ++#undef POLY1305_USE_PPC_VEC ++#ifdef ENABLE_PPC_CRYPTO_SUPPORT ++# if defined(HAVE_COMPATIBLE_CC_PPC_ALTIVEC) && \ ++ defined(HAVE_GCC_INLINE_ASM_PPC_ALTIVEC) && \ ++ !defined(WORDS_BIGENDIAN) ++# if __GNUC__ >= 4 ++# define POLY1305_USE_PPC_VEC 1 ++# endif ++# endif ++#endif ++ + + typedef struct + { +@@ -46,6 +58,9 @@ typedef struct poly1305_context_s + POLY1305_STATE state; + byte buffer[POLY1305_BLOCKSIZE]; + unsigned int leftover; ++#ifdef POLY1305_USE_PPC_VEC ++ unsigned int use_p10:1; ++#endif + } poly1305_context_t; + + +Index: libgcrypt-1.9.4/cipher/poly1305-p10le.s +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/cipher/poly1305-p10le.s +@@ -0,0 +1,841 @@ ++# Copyright 2021- IBM Inc. All rights reserved ++# ++# 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 . ++# ++#=================================================================================== ++# Written by Danny Tsen ++# ++# Poly1305 - this version mainly using vector/VSX/Scalar ++# - 26 bits limbs ++# - Handle multiple 64 byte blcoks but need at least 2 64 bytes block ++# ++# Improve performance by breaking down polynominal to the sum of products with ++# h4 = m1 * r⁴ + m2 * r³ + m3 * r² + m4 * r ++# ++# 07/22/21 - this revison based on the above sum of products. Setup r^4, r^3, r^2, r and s3, s2, s1, s0 ++# to 9 vectors for multiplications. ++# ++# setup r^4, r^3, r^2, r vectors ++# vs [r^1, r^3, r^2, r^4] ++# vs0 = [r0,.....] ++# vs1 = [r1,.....] ++# vs2 = [r2,.....] ++# vs3 = [r3,.....] ++# vs4 = [r4,.....] ++# vs5 = [r1*5,...] ++# vs6 = [r2*5,...] ++# vs7 = [r2*5,...] ++# vs8 = [r4*5,...] ++# ++# Each word in a vector consists a member of a "r/s" in [a * r/s]. ++# ++# r0, r4*5, r3*5, r2*5, r1*5; ++# r1, r0, r4*5, r3*5, r2*5; ++# r2, r1, r0, r4*5, r3*5; ++# r3, r2, r1, r0, r4*5; ++# r4, r3, r2, r1, r0 ; ++# ++# ++# gcry_poly1305_p10le_4blocks( uint8_t *k, uint32_t mlen, uint8_t *m) ++# k = 32 bytes key ++# r3 = k (r, s) ++# r4 = mlen ++# r5 = m ++# ++.text ++ ++# Block size 16 bytes ++# key = (r, s) ++# clamp r &= 0x0FFFFFFC0FFFFFFC 0x0FFFFFFC0FFFFFFF ++# p = 2^130 - 5 ++# a += m ++# a = (r + a) % p ++# a += s ++# 16 bytes (a) ++# ++# p[0] = a0*r0 + a1*r4*5 + a2*r3*5 + a3*r2*5 + a4*r1*5; ++# p[1] = a0*r1 + a1*r0 + a2*r4*5 + a3*r3*5 + a4*r2*5; ++# p[2] = a0*r2 + a1*r1 + a2*r0 + a3*r4*5 + a4*r3*5; ++# p[3] = a0*r3 + a1*r2 + a2*r1 + a3*r0 + a4*r4*5; ++# p[4] = a0*r4 + a1*r3 + a2*r2 + a3*r1 + a4*r0 ; ++# ++# [r^2, r^3, r^1, r^4] ++# [m3, m2, m4, m1] ++# ++# multiply odd and even words ++.macro mul_odd ++ vmulouw 14, 4, 26 ++ vmulouw 10, 5, 3 ++ vmulouw 11, 6, 2 ++ vmulouw 12, 7, 1 ++ vmulouw 13, 8, 0 ++ vmulouw 15, 4, 27 ++ vaddudm 14, 14, 10 ++ vaddudm 14, 14, 11 ++ vmulouw 10, 5, 26 ++ vmulouw 11, 6, 3 ++ vaddudm 14, 14, 12 ++ vaddudm 14, 14, 13 # x0 ++ vaddudm 15, 15, 10 ++ vaddudm 15, 15, 11 ++ vmulouw 12, 7, 2 ++ vmulouw 13, 8, 1 ++ vaddudm 15, 15, 12 ++ vaddudm 15, 15, 13 # x1 ++ vmulouw 16, 4, 28 ++ vmulouw 10, 5, 27 ++ vmulouw 11, 6, 26 ++ vaddudm 16, 16, 10 ++ vaddudm 16, 16, 11 ++ vmulouw 12, 7, 3 ++ vmulouw 13, 8, 2 ++ vaddudm 16, 16, 12 ++ vaddudm 16, 16, 13 # x2 ++ vmulouw 17, 4, 29 ++ vmulouw 10, 5, 28 ++ vmulouw 11, 6, 27 ++ vaddudm 17, 17, 10 ++ vaddudm 17, 17, 11 ++ vmulouw 12, 7, 26 ++ vmulouw 13, 8, 3 ++ vaddudm 17, 17, 12 ++ vaddudm 17, 17, 13 # x3 ++ vmulouw 18, 4, 30 ++ vmulouw 10, 5, 29 ++ vmulouw 11, 6, 28 ++ vaddudm 18, 18, 10 ++ vaddudm 18, 18, 11 ++ vmulouw 12, 7, 27 ++ vmulouw 13, 8, 26 ++ vaddudm 18, 18, 12 ++ vaddudm 18, 18, 13 # x4 ++.endm ++ ++.macro mul_even ++ vmuleuw 9, 4, 26 ++ vmuleuw 10, 5, 3 ++ vmuleuw 11, 6, 2 ++ vmuleuw 12, 7, 1 ++ vmuleuw 13, 8, 0 ++ vaddudm 14, 14, 9 ++ vaddudm 14, 14, 10 ++ vaddudm 14, 14, 11 ++ vaddudm 14, 14, 12 ++ vaddudm 14, 14, 13 # x0 ++ ++ vmuleuw 9, 4, 27 ++ vmuleuw 10, 5, 26 ++ vmuleuw 11, 6, 3 ++ vmuleuw 12, 7, 2 ++ vmuleuw 13, 8, 1 ++ vaddudm 15, 15, 9 ++ vaddudm 15, 15, 10 ++ vaddudm 15, 15, 11 ++ vaddudm 15, 15, 12 ++ vaddudm 15, 15, 13 # x1 ++ ++ vmuleuw 9, 4, 28 ++ vmuleuw 10, 5, 27 ++ vmuleuw 11, 6, 26 ++ vmuleuw 12, 7, 3 ++ vmuleuw 13, 8, 2 ++ vaddudm 16, 16, 9 ++ vaddudm 16, 16, 10 ++ vaddudm 16, 16, 11 ++ vaddudm 16, 16, 12 ++ vaddudm 16, 16, 13 # x2 ++ ++ vmuleuw 9, 4, 29 ++ vmuleuw 10, 5, 28 ++ vmuleuw 11, 6, 27 ++ vmuleuw 12, 7, 26 ++ vmuleuw 13, 8, 3 ++ vaddudm 17, 17, 9 ++ vaddudm 17, 17, 10 ++ vaddudm 17, 17, 11 ++ vaddudm 17, 17, 12 ++ vaddudm 17, 17, 13 # x3 ++ ++ vmuleuw 9, 4, 30 ++ vmuleuw 10, 5, 29 ++ vmuleuw 11, 6, 28 ++ vmuleuw 12, 7, 27 ++ vmuleuw 13, 8, 26 ++ vaddudm 18, 18, 9 ++ vaddudm 18, 18, 10 ++ vaddudm 18, 18, 11 ++ vaddudm 18, 18, 12 ++ vaddudm 18, 18, 13 # x4 ++.endm ++ ++# setup r^4, r^3, r^2, r vectors ++# [r, r^3, r^2, r^4] ++# vs0 = [r0,...] ++# vs1 = [r1,...] ++# vs2 = [r2,...] ++# vs3 = [r3,...] ++# vs4 = [r4,...] ++# vs5 = [r4*5,...] ++# vs6 = [r3*5,...] ++# vs7 = [r2*5,...] ++# vs8 = [r1*5,...] ++# ++# r0, r4*5, r3*5, r2*5, r1*5; ++# r1, r0, r4*5, r3*5, r2*5; ++# r2, r1, r0, r4*5, r3*5; ++# r3, r2, r1, r0, r4*5; ++# r4, r3, r2, r1, r0 ; ++# ++.macro poly1305_setup_r ++ ++ # save r ++ xxlor 26, 58, 58 ++ xxlor 27, 59, 59 ++ xxlor 28, 60, 60 ++ xxlor 29, 61, 61 ++ xxlor 30, 62, 62 ++ ++ xxlxor 31, 31, 31 ++ ++# [r, r^3, r^2, r^4] ++ # compute r^2 ++ vmr 4, 26 ++ vmr 5, 27 ++ vmr 6, 28 ++ vmr 7, 29 ++ vmr 8, 30 ++ bl do_mul # r^2 r^1 ++ xxpermdi 58, 58, 36, 0x3 # r0 ++ xxpermdi 59, 59, 37, 0x3 # r1 ++ xxpermdi 60, 60, 38, 0x3 # r2 ++ xxpermdi 61, 61, 39, 0x3 # r3 ++ xxpermdi 62, 62, 40, 0x3 # r4 ++ xxpermdi 36, 36, 36, 0x3 ++ xxpermdi 37, 37, 37, 0x3 ++ xxpermdi 38, 38, 38, 0x3 ++ xxpermdi 39, 39, 39, 0x3 ++ xxpermdi 40, 40, 40, 0x3 ++ vspltisb 13, 2 ++ vsld 9, 27, 13 ++ vsld 10, 28, 13 ++ vsld 11, 29, 13 ++ vsld 12, 30, 13 ++ vaddudm 0, 9, 27 ++ vaddudm 1, 10, 28 ++ vaddudm 2, 11, 29 ++ vaddudm 3, 12, 30 ++ ++ bl do_mul # r^4 r^3 ++ vmrgow 26, 26, 4 ++ vmrgow 27, 27, 5 ++ vmrgow 28, 28, 6 ++ vmrgow 29, 29, 7 ++ vmrgow 30, 30, 8 ++ vspltisb 13, 2 ++ vsld 9, 27, 13 ++ vsld 10, 28, 13 ++ vsld 11, 29, 13 ++ vsld 12, 30, 13 ++ vaddudm 0, 9, 27 ++ vaddudm 1, 10, 28 ++ vaddudm 2, 11, 29 ++ vaddudm 3, 12, 30 ++ ++ # r^2 r^4 ++ xxlor 0, 58, 58 ++ xxlor 1, 59, 59 ++ xxlor 2, 60, 60 ++ xxlor 3, 61, 61 ++ xxlor 4, 62, 62 ++ xxlor 5, 32, 32 ++ xxlor 6, 33, 33 ++ xxlor 7, 34, 34 ++ xxlor 8, 35, 35 ++ ++ vspltw 9, 26, 3 ++ vspltw 10, 26, 2 ++ vmrgow 26, 10, 9 ++ vspltw 9, 27, 3 ++ vspltw 10, 27, 2 ++ vmrgow 27, 10, 9 ++ vspltw 9, 28, 3 ++ vspltw 10, 28, 2 ++ vmrgow 28, 10, 9 ++ vspltw 9, 29, 3 ++ vspltw 10, 29, 2 ++ vmrgow 29, 10, 9 ++ vspltw 9, 30, 3 ++ vspltw 10, 30, 2 ++ vmrgow 30, 10, 9 ++ ++ vsld 9, 27, 13 ++ vsld 10, 28, 13 ++ vsld 11, 29, 13 ++ vsld 12, 30, 13 ++ vaddudm 0, 9, 27 ++ vaddudm 1, 10, 28 ++ vaddudm 2, 11, 29 ++ vaddudm 3, 12, 30 ++.endm ++ ++do_mul: ++ mul_odd ++ ++ # do reduction ( h %= p ) ++ # carry reduction ++ vspltisb 9, 2 ++ vsrd 10, 14, 31 ++ vsrd 11, 17, 31 ++ vand 7, 17, 25 ++ vand 4, 14, 25 ++ vaddudm 18, 18, 11 ++ vsrd 12, 18, 31 ++ vaddudm 15, 15, 10 ++ ++ vsrd 11, 15, 31 ++ vand 8, 18, 25 ++ vand 5, 15, 25 ++ vaddudm 4, 4, 12 ++ vsld 10, 12, 9 ++ vaddudm 6, 16, 11 ++ ++ vsrd 13, 6, 31 ++ vand 6, 6, 25 ++ vaddudm 4, 4, 10 ++ vsrd 10, 4, 31 ++ vaddudm 7, 7, 13 ++ ++ vsrd 11, 7, 31 ++ vand 7, 7, 25 ++ vand 4, 4, 25 ++ vaddudm 5, 5, 10 ++ vaddudm 8, 8, 11 ++ blr ++ ++# ++# init key ++# ++do_poly1305_init: ++ ld 10, rmask@got(2) ++ ld 11, 0(10) ++ ld 12, 8(10) ++ ++ li 14, 16 ++ li 15, 32 ++ ld 10, cnum@got(2) ++ lvx 25, 0, 10 # v25 - mask ++ lvx 31, 14, 10 # v31 = 1a ++ lvx 19, 15, 10 # v19 = 1 << 24 ++ lxv 24, 48(10) # vs24 ++ lxv 25, 64(10) # vs25 ++ ++ # initialize ++ # load key from r3 to vectors ++ ld 9, 16(3) ++ ld 10, 24(3) ++ ld 11, 0(3) ++ ld 12, 8(3) ++ ++ # break 26 bits ++ extrdi 14, 9, 26, 38 ++ extrdi 15, 9, 26, 12 ++ extrdi 16, 9, 12, 0 ++ mtvsrdd 58, 0, 14 ++ insrdi 16, 10, 14, 38 ++ mtvsrdd 59, 0, 15 ++ extrdi 17, 10, 26, 24 ++ mtvsrdd 60, 0, 16 ++ extrdi 18, 10, 24, 0 ++ mtvsrdd 61, 0, 17 ++ mtvsrdd 62, 0, 18 ++ ++ # r1 = r1 * 5, r2 = r2 * 5, r3 = r3 * 5, r4 = r4 * 5 ++ li 9, 5 ++ mtvsrdd 36, 0, 9 ++ vmulouw 0, 27, 4 # v0 = rr0 ++ vmulouw 1, 28, 4 # v1 = rr1 ++ vmulouw 2, 29, 4 # v2 = rr2 ++ vmulouw 3, 30, 4 # v3 = rr3 ++ blr ++ ++# ++# gcry_poly1305_p10le_4blocks( uint8_t *k, uint32_t mlen, uint8_t *m) ++# k = 32 bytes key ++# r3 = k (r, s) ++# r4 = mlen ++# r5 = m ++# ++.global gcry_poly1305_p10le_4blocks ++.align 5 ++gcry_poly1305_p10le_4blocks: ++_gcry_poly1305_p10le_4blocks: ++ cmpdi 5, 128 ++ blt Out_no_poly1305 ++ ++ stdu 1,-1024(1) ++ mflr 0 ++ ++ std 14,112(1) ++ std 15,120(1) ++ std 16,128(1) ++ std 17,136(1) ++ std 18,144(1) ++ std 19,152(1) ++ std 20,160(1) ++ std 21,168(1) ++ std 31,248(1) ++ li 14, 256 ++ stvx 20, 14, 1 ++ addi 14, 14, 16 ++ stvx 21, 14, 1 ++ addi 14, 14, 16 ++ stvx 22, 14, 1 ++ addi 14, 14, 16 ++ stvx 23, 14, 1 ++ addi 14, 14, 16 ++ stvx 24, 14, 1 ++ addi 14, 14, 16 ++ stvx 25, 14, 1 ++ addi 14, 14, 16 ++ stvx 26, 14, 1 ++ addi 14, 14, 16 ++ stvx 27, 14, 1 ++ addi 14, 14, 16 ++ stvx 28, 14, 1 ++ addi 14, 14, 16 ++ stvx 29, 14, 1 ++ addi 14, 14, 16 ++ stvx 30, 14, 1 ++ addi 14, 14, 16 ++ stvx 31, 14, 1 ++ ++ addi 14, 14, 16 ++ stxvx 14, 14, 1 ++ addi 14, 14, 16 ++ stxvx 15, 14, 1 ++ addi 14, 14, 16 ++ stxvx 16, 14, 1 ++ addi 14, 14, 16 ++ stxvx 17, 14, 1 ++ addi 14, 14, 16 ++ stxvx 18, 14, 1 ++ addi 14, 14, 16 ++ stxvx 19, 14, 1 ++ addi 14, 14, 16 ++ stxvx 20, 14, 1 ++ addi 14, 14, 16 ++ stxvx 21, 14, 1 ++ addi 14, 14, 16 ++ stxvx 22, 14, 1 ++ addi 14, 14, 16 ++ stxvx 23, 14, 1 ++ addi 14, 14, 16 ++ stxvx 24, 14, 1 ++ addi 14, 14, 16 ++ stxvx 25, 14, 1 ++ addi 14, 14, 16 ++ stxvx 26, 14, 1 ++ addi 14, 14, 16 ++ stxvx 27, 14, 1 ++ addi 14, 14, 16 ++ stxvx 28, 14, 1 ++ addi 14, 14, 16 ++ stxvx 29, 14, 1 ++ addi 14, 14, 16 ++ stxvx 30, 14, 1 ++ addi 14, 14, 16 ++ stxvx 31, 14, 1 ++ std 0, 1040(1) ++ ++ bl do_poly1305_init ++ ++ li 21, 0 # counter to message ++ ++ poly1305_setup_r ++ ++ # load previous state ++ # break/convert r6 to 26 bits ++ ld 9, 32(3) ++ ld 10, 40(3) ++ lwz 19, 48(3) ++ sldi 19, 19, 24 ++ mtvsrdd 41, 0, 19 ++ extrdi 14, 9, 26, 38 ++ extrdi 15, 9, 26, 12 ++ extrdi 16, 9, 12, 0 ++ mtvsrdd 36, 0, 14 ++ insrdi 16, 10, 14, 38 ++ mtvsrdd 37, 0, 15 ++ extrdi 17, 10, 26, 24 ++ mtvsrdd 38, 0, 16 ++ extrdi 18, 10, 24, 0 ++ mtvsrdd 39, 0, 17 ++ mtvsrdd 40, 0, 18 ++ vor 8, 8, 9 ++ ++ # input m1 m2 ++ add 20, 4, 21 ++ xxlor 49, 24, 24 ++ xxlor 50, 25, 25 ++ lxvw4x 43, 0, 20 ++ addi 17, 20, 16 ++ lxvw4x 44, 0, 17 ++ vperm 14, 11, 12, 17 ++ vperm 15, 11, 12, 18 ++ vand 9, 14, 25 # a0 ++ vsrd 10, 14, 31 # >> 26 ++ vsrd 11, 10, 31 # 12 bits left ++ vand 10, 10, 25 # a1 ++ vspltisb 13, 12 ++ vand 16, 15, 25 ++ vsld 12, 16, 13 ++ vor 11, 11, 12 ++ vand 11, 11, 25 # a2 ++ vspltisb 13, 14 ++ vsrd 12, 15, 13 # >> 14 ++ vsrd 13, 12, 31 # >> 26, a4 ++ vand 12, 12, 25 # a3 ++ ++ vaddudm 20, 4, 9 ++ vaddudm 21, 5, 10 ++ vaddudm 22, 6, 11 ++ vaddudm 23, 7, 12 ++ vaddudm 24, 8, 13 ++ ++ # m3 m4 ++ addi 17, 17, 16 ++ lxvw4x 43, 0, 17 ++ addi 17, 17, 16 ++ lxvw4x 44, 0, 17 ++ vperm 14, 11, 12, 17 ++ vperm 15, 11, 12, 18 ++ vand 9, 14, 25 # a0 ++ vsrd 10, 14, 31 # >> 26 ++ vsrd 11, 10, 31 # 12 bits left ++ vand 10, 10, 25 # a1 ++ vspltisb 13, 12 ++ vand 16, 15, 25 ++ vsld 12, 16, 13 ++ vspltisb 13, 14 ++ vor 11, 11, 12 ++ vand 11, 11, 25 # a2 ++ vsrd 12, 15, 13 # >> 14 ++ vsrd 13, 12, 31 # >> 26, a4 ++ vand 12, 12, 25 # a3 ++ ++ # Smash 4 message blocks into 5 vectors of [m4, m2, m3, m1] ++ vmrgow 4, 9, 20 ++ vmrgow 5, 10, 21 ++ vmrgow 6, 11, 22 ++ vmrgow 7, 12, 23 ++ vmrgow 8, 13, 24 ++ vaddudm 8, 8, 19 ++ ++ addi 5, 5, -64 ++ addi 21, 21, 64 ++ ++ li 9, 64 ++ divdu 31, 5, 9 ++ ++ mtctr 31 ++ ++# h4 = m1 * r⁴ + m2 * r³ + m3 * r² + m4 * r ++# Rewrite the polynominal sum of product as follows, ++# h1 = (h0 + m1) * r^2, h2 = (h0 + m2) * r^2 ++# h3 = (h1 + m3) * r^2, h4 = (h2 + m4) * r^2 --> (h0 + m1) r*4 + (h3 + m3) r^2, (h0 + m2) r^4 + (h0 + m4) r^2 ++# .... Repeat ++# h5 = (h3 + m5) * r^2, h6 = (h4 + m6) * r^2 --> ++# h7 = (h5 + m7) * r^2, h8 = (h6 + m8) * r^1 --> m5 * r^4 + m6 * r^3 + m7 * r^2 + m8 * r ++# ++loop_4blocks: ++ ++ # Multiply odd words and even words ++ mul_odd ++ mul_even ++ # carry reduction ++ vspltisb 9, 2 ++ vsrd 10, 14, 31 ++ vsrd 11, 17, 31 ++ vand 7, 17, 25 ++ vand 4, 14, 25 ++ vaddudm 18, 18, 11 ++ vsrd 12, 18, 31 ++ vaddudm 15, 15, 10 ++ ++ vsrd 11, 15, 31 ++ vand 8, 18, 25 ++ vand 5, 15, 25 ++ vaddudm 4, 4, 12 ++ vsld 10, 12, 9 ++ vaddudm 6, 16, 11 ++ ++ vsrd 13, 6, 31 ++ vand 6, 6, 25 ++ vaddudm 4, 4, 10 ++ vsrd 10, 4, 31 ++ vaddudm 7, 7, 13 ++ ++ vsrd 11, 7, 31 ++ vand 7, 7, 25 ++ vand 4, 4, 25 ++ vaddudm 5, 5, 10 ++ vaddudm 8, 8, 11 ++ ++ # input m1 m2 m3 m4 ++ add 20, 4, 21 ++ xxlor 49, 24, 24 ++ xxlor 50, 25, 25 ++ lxvw4x 43, 0, 20 ++ addi 17, 20, 16 ++ lxvw4x 44, 0, 17 ++ vperm 14, 11, 12, 17 ++ vperm 15, 11, 12, 18 ++ addi 17, 17, 16 ++ lxvw4x 43, 0, 17 ++ addi 17, 17, 16 ++ lxvw4x 44, 0, 17 ++ vperm 17, 11, 12, 17 ++ vperm 18, 11, 12, 18 ++ ++ vand 20, 14, 25 # a0 ++ vand 9, 17, 25 # a0 ++ vsrd 21, 14, 31 # >> 26 ++ vsrd 22, 21, 31 # 12 bits left ++ vsrd 10, 17, 31 # >> 26 ++ vsrd 11, 10, 31 # 12 bits left ++ ++ vand 21, 21, 25 # a1 ++ vand 10, 10, 25 # a1 ++ ++ vspltisb 13, 12 ++ vand 16, 15, 25 ++ vsld 23, 16, 13 ++ vor 22, 22, 23 ++ vand 22, 22, 25 # a2 ++ vand 16, 18, 25 ++ vsld 12, 16, 13 ++ vor 11, 11, 12 ++ vand 11, 11, 25 # a2 ++ vspltisb 13, 14 ++ vsrd 23, 15, 13 # >> 14 ++ vsrd 24, 23, 31 # >> 26, a4 ++ vand 23, 23, 25 # a3 ++ vsrd 12, 18, 13 # >> 14 ++ vsrd 13, 12, 31 # >> 26, a4 ++ vand 12, 12, 25 # a3 ++ ++ vaddudm 4, 4, 20 ++ vaddudm 5, 5, 21 ++ vaddudm 6, 6, 22 ++ vaddudm 7, 7, 23 ++ vaddudm 8, 8, 24 ++ ++ # Smash 4 message blocks into 5 vectors of [m4, m2, m3, m1] ++ vmrgow 4, 9, 4 ++ vmrgow 5, 10, 5 ++ vmrgow 6, 11, 6 ++ vmrgow 7, 12, 7 ++ vmrgow 8, 13, 8 ++ vaddudm 8, 8, 19 ++ ++ addi 5, 5, -64 ++ addi 21, 21, 64 ++ ++ bdnz loop_4blocks ++ ++ xxlor 58, 0, 0 ++ xxlor 59, 1, 1 ++ xxlor 60, 2, 2 ++ xxlor 61, 3, 3 ++ xxlor 62, 4, 4 ++ xxlor 32, 5, 5 ++ xxlor 33, 6, 6 ++ xxlor 34, 7, 7 ++ xxlor 35, 8, 8 ++ ++ # Multiply odd words and even words ++ mul_odd ++ mul_even ++ ++ # Sum the products. ++ xxpermdi 41, 31, 46, 0 ++ xxpermdi 42, 31, 47, 0 ++ vaddudm 4, 14, 9 ++ xxpermdi 36, 31, 36, 3 ++ vaddudm 5, 15, 10 ++ xxpermdi 37, 31, 37, 3 ++ xxpermdi 43, 31, 48, 0 ++ vaddudm 6, 16, 11 ++ xxpermdi 38, 31, 38, 3 ++ xxpermdi 44, 31, 49, 0 ++ vaddudm 7, 17, 12 ++ xxpermdi 39, 31, 39, 3 ++ xxpermdi 45, 31, 50, 0 ++ vaddudm 8, 18, 13 ++ xxpermdi 40, 31, 40, 3 ++ ++ # carry reduction ++ vspltisb 9, 2 ++ vsrd 10, 4, 31 ++ vsrd 11, 7, 31 ++ vand 7, 7, 25 ++ vand 4, 4, 25 ++ vaddudm 8, 8, 11 ++ vsrd 12, 8, 31 ++ vaddudm 5, 5, 10 ++ ++ vsrd 11, 5, 31 ++ vand 8, 8, 25 ++ vand 5, 5, 25 ++ vaddudm 4, 4, 12 ++ vsld 10, 12, 9 ++ vaddudm 6, 6, 11 ++ ++ vsrd 13, 6, 31 ++ vand 6, 6, 25 ++ vaddudm 4, 4, 10 ++ vsrd 10, 4, 31 ++ vaddudm 7, 7, 13 ++ ++ vsrd 11, 7, 31 ++ vand 7, 7, 25 ++ vand 4, 4, 25 ++ vaddudm 5, 5, 10 ++ vaddudm 8, 8, 11 ++ ++ b do_final_update ++ ++do_final_update: ++ # v4, v5, v6, v7 and v8 are 26 bit vectors ++ vsld 5, 5, 31 ++ vor 20, 4, 5 ++ vspltisb 11, 12 ++ vsrd 12, 6, 11 ++ vsld 6, 6, 31 ++ vsld 6, 6, 31 ++ vor 20, 20, 6 ++ vspltisb 11, 14 ++ vsld 7, 7, 11 ++ vor 21, 7, 12 ++ mfvsrld 16, 40 # save last 2 bytes ++ vsld 8, 8, 11 ++ vsld 8, 8, 31 ++ vor 21, 21, 8 ++ mfvsrld 17, 52 ++ mfvsrld 19, 53 ++ srdi 16, 16, 24 ++ ++ std 17, 32(3) ++ std 19, 40(3) ++ stw 16, 48(3) ++ ++Out_loop: ++ li 3, 0 ++ ++ li 14, 256 ++ lvx 20, 14, 1 ++ addi 14, 14, 16 ++ lvx 21, 14, 1 ++ addi 14, 14, 16 ++ lvx 22, 14, 1 ++ addi 14, 14, 16 ++ lvx 23, 14, 1 ++ addi 14, 14, 16 ++ lvx 24, 14, 1 ++ addi 14, 14, 16 ++ lvx 25, 14, 1 ++ addi 14, 14, 16 ++ lvx 26, 14, 1 ++ addi 14, 14, 16 ++ lvx 27, 14, 1 ++ addi 14, 14, 16 ++ lvx 28, 14, 1 ++ addi 14, 14, 16 ++ lvx 29, 14, 1 ++ addi 14, 14, 16 ++ lvx 30, 14, 1 ++ addi 14, 14, 16 ++ lvx 31, 14, 1 ++ ++ addi 14, 14, 16 ++ lxvx 14, 14, 1 ++ addi 14, 14, 16 ++ lxvx 15, 14, 1 ++ addi 14, 14, 16 ++ lxvx 16, 14, 1 ++ addi 14, 14, 16 ++ lxvx 17, 14, 1 ++ addi 14, 14, 16 ++ lxvx 18, 14, 1 ++ addi 14, 14, 16 ++ lxvx 19, 14, 1 ++ addi 14, 14, 16 ++ lxvx 20, 14, 1 ++ addi 14, 14, 16 ++ lxvx 21, 14, 1 ++ addi 14, 14, 16 ++ lxvx 22, 14, 1 ++ addi 14, 14, 16 ++ lxvx 23, 14, 1 ++ addi 14, 14, 16 ++ lxvx 24, 14, 1 ++ addi 14, 14, 16 ++ lxvx 25, 14, 1 ++ addi 14, 14, 16 ++ lxvx 26, 14, 1 ++ addi 14, 14, 16 ++ lxvx 27, 14, 1 ++ addi 14, 14, 16 ++ lxvx 28, 14, 1 ++ addi 14, 14, 16 ++ lxvx 29, 14, 1 ++ addi 14, 14, 16 ++ lxvx 30, 14, 1 ++ addi 14, 14, 16 ++ lxvx 31, 14, 1 ++ ++ ld 0, 1040(1) ++ ld 14,112(1) ++ ld 15,120(1) ++ ld 16,128(1) ++ ld 17,136(1) ++ ld 18,144(1) ++ ld 19,152(1) ++ ld 20,160(1) ++ ld 21,168(1) ++ ld 31,248(1) ++ ++ mtlr 0 ++ addi 1, 1, 1024 ++ blr ++ ++Out_no_poly1305: ++ li 3, 0 ++ blr ++ ++.data ++.align 5 ++rmask: ++.byte 0xff, 0xff, 0xff, 0x0f, 0xfc, 0xff, 0xff, 0x0f, 0xfc, 0xff, 0xff, 0x0f, 0xfc, 0xff, 0xff, 0x0f ++cnum: ++.long 0x03ffffff, 0x00000000, 0x03ffffff, 0x00000000 ++.long 0x1a, 0x00, 0x1a, 0x00 ++.long 0x01000000, 0x01000000, 0x01000000, 0x01000000 ++.long 0x00010203, 0x04050607, 0x10111213, 0x14151617 ++.long 0x08090a0b, 0x0c0d0e0f, 0x18191a1b, 0x1c1d1e1f ++.long 0x05, 0x00, 0x00, 0x00 ++.long 0x02020202, 0x02020202, 0x02020202, 0x02020202 ++.long 0xffffffff, 0xffffffff, 0x00000000, 0x00000000 +Index: libgcrypt-1.9.4/cipher/poly1305.c +=================================================================== +--- libgcrypt-1.9.4.orig/cipher/poly1305.c ++++ libgcrypt-1.9.4/cipher/poly1305.c +@@ -78,11 +78,23 @@ poly1305_blocks (poly1305_context_t *ctx + #endif /* USE_S390X_ASM */ + + ++#ifdef POLY1305_USE_PPC_VEC ++ ++extern unsigned int ++gcry_poly1305_p10le_4blocks(unsigned char *key, const byte *m, size_t len); ++ ++#endif /* POLY1305_USE_PPC_VEC */ ++ ++ + static void poly1305_init (poly1305_context_t *ctx, + const byte key[POLY1305_KEYLEN]) + { + POLY1305_STATE *st = &ctx->state; + ++#ifdef POLY1305_USE_PPC_VEC ++ ctx->use_p10 = (_gcry_get_hw_features () & HWF_PPC_ARCH_3_10) != 0; ++#endif ++ + ctx->leftover = 0; + + st->h[0] = 0; +@@ -511,6 +523,7 @@ _gcry_poly1305_update_burn (poly1305_con + size_t bytes) + { + unsigned int burn = 0; ++ unsigned int nburn; + + /* handle leftover */ + if (ctx->leftover) +@@ -524,15 +537,31 @@ _gcry_poly1305_update_burn (poly1305_con + ctx->leftover += want; + if (ctx->leftover < POLY1305_BLOCKSIZE) + return 0; +- burn = poly1305_blocks (ctx, ctx->buffer, POLY1305_BLOCKSIZE, 1); ++ nburn = poly1305_blocks (ctx, ctx->buffer, POLY1305_BLOCKSIZE, 1); ++ burn = nburn > burn ? nburn : burn; + ctx->leftover = 0; + } + ++#ifdef POLY1305_USE_PPC_VEC ++ /* PPC-P10/little-endian: bulk process multiples of eight blocks */ ++ if (ctx->use_p10 && bytes >= POLY1305_BLOCKSIZE * 8) ++ { ++ size_t nblks = bytes / (POLY1305_BLOCKSIZE * 8); ++ size_t len = nblks * (POLY1305_BLOCKSIZE * 8); ++ POLY1305_STATE *st = &ctx->state; ++ nburn = gcry_poly1305_p10le_4blocks ((unsigned char *) st, m, len); ++ burn = nburn > burn ? nburn : burn; ++ m += len; ++ bytes -= len; ++ } ++#endif /* POLY1305_USE_PPC_VEC */ ++ + /* process full blocks */ + if (bytes >= POLY1305_BLOCKSIZE) + { + size_t nblks = bytes / POLY1305_BLOCKSIZE; +- burn = poly1305_blocks (ctx, m, nblks * POLY1305_BLOCKSIZE, 1); ++ nburn = poly1305_blocks (ctx, m, nblks * POLY1305_BLOCKSIZE, 1); ++ burn = nburn > burn ? nburn : burn; + m += nblks * POLY1305_BLOCKSIZE; + bytes -= nblks * POLY1305_BLOCKSIZE; + } +Index: libgcrypt-1.9.4/configure.ac +=================================================================== +--- libgcrypt-1.9.4.orig/configure.ac ++++ libgcrypt-1.9.4/configure.ac +@@ -2775,6 +2775,11 @@ if test "$found" = "1" ; then + powerpc64le-*-*) + # Build with the ppc8 vector implementation + GCRYPT_CIPHERS="$GCRYPT_CIPHERS chacha20-ppc.lo" ++ # Build with the assembly implementation ++ if test "$gcry_cv_gcc_inline_asm_ppc_altivec" = "yes" && ++ test "$gcry_cv_gcc_inline_asm_ppc_arch_3_00" = "yes" ; then ++ GCRYPT_CIPHERS="$GCRYPT_CIPHERS chacha20-p10le-8x.lo" ++ fi + ;; + powerpc64-*-*) + # Build with the ppc8 vector implementation +@@ -3087,6 +3092,17 @@ case "${host}" in + ;; + esac + ++# Arch specific MAC implementations ++case "${host}" in ++ powerpc64le-*-*) ++ # Build with the assembly implementation ++ if test "$gcry_cv_gcc_inline_asm_ppc_altivec" = "yes" && ++ test "$gcry_cv_gcc_inline_asm_ppc_arch_3_00" = "yes" ; then ++ GCRYPT_DIGESTS="$GCRYPT_DIGESTS poly1305-p10le.lo" ++ fi ++ ;; ++esac ++ + LIST_MEMBER(sm3, $enabled_digests) + if test "$found" = "1" ; then + GCRYPT_DIGESTS="$GCRYPT_DIGESTS sm3.lo" diff --git a/libgcrypt-PCT-DSA.patch b/libgcrypt-PCT-DSA.patch new file mode 100644 index 0000000..decc8d8 --- /dev/null +++ b/libgcrypt-PCT-DSA.patch @@ -0,0 +1,118 @@ +Index: libgcrypt-1.8.2/cipher/dsa.c +=================================================================== +--- libgcrypt-1.8.2.orig/cipher/dsa.c ++++ libgcrypt-1.8.2/cipher/dsa.c +@@ -181,24 +181,101 @@ test_keys (DSA_secret_key *sk, unsigned + /* Create a random plaintext. */ + _gcry_mpi_randomize (data, qbits, GCRY_WEAK_RANDOM); + +- /* Sign DATA using the secret key. */ +- sign (sig_a, sig_b, data, sk, 0, 0); ++ /* Use the gcry_pk_sign_md API in order to comply with FIPS 140-2, ++ * which requires full signature operation for PCT (hashing + ++ * asymmetric operation) */ ++ gcry_sexp_t s_skey = NULL; ++ gcry_sexp_t s_pkey = NULL; ++ gcry_sexp_t r_sig = NULL; ++ gcry_sexp_t s_hash = NULL; ++ gcry_md_hd_t hd = NULL; ++ gcry_mpi_t r_sig_mpi = NULL; ++ gcry_mpi_t s_sig_mpi = NULL; ++ unsigned char *buf = NULL; ++ size_t buflen; ++ ++ if (_gcry_md_open (&hd, GCRY_MD_SHA256, 0)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("gcry_pk_sign/open failed\n"); ++ goto leave; ++ } ++ ++ _gcry_mpi_aprint (GCRYMPI_FMT_STD, &buf, &buflen, data); ++ _gcry_md_write (hd, buf, buflen); ++ ++ xfree (buf); ++ buf = NULL; ++ ++ /* build DSA private key sexp in s_skey */ ++ sexp_build (&s_skey, NULL, "(private-key (dsa(p %m)(q %m)(g %m)(y %m)(x %m)))", ++ sk->p, sk->q, sk->g, sk->y, sk->x); ++ sexp_build (&s_hash, NULL, "(data (flags pkcs1)(hash-algo sha256))"); ++ if (_gcry_pk_sign_md (&r_sig, hd, s_hash, s_skey)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("gcry_pk_sign failed\n"); ++ goto leave; ++ } ++ ++ /* Check that the signature and the original plaintext differ. */ ++ if (_gcry_sexp_extract_param (r_sig, NULL, "rs", &r_sig_mpi, &s_sig_mpi, NULL)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("extracting signature data failed\n"); ++ goto leave; ++ } ++ ++ if ( !verify (r_sig_mpi, s_sig_mpi, data, &pk)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("Signature failed\n"); ++ goto leave; /* Signature matches but should not. */ ++ } ++ ++ _gcry_sexp_release (s_hash); ++ _gcry_md_close (hd); ++ ++ /* build DSA public key sexp in s_pkey */ ++ sexp_build (&s_pkey, NULL, "(public-key (dsa(p %m)(q %m)(g %m)(y %m)))", ++ pk.p, pk.q, pk.g, pk.y); ++ sexp_build (&s_hash, NULL, "(data (flags pkcs1)(hash-algo sha256))"); ++ ++ if (_gcry_md_open (&hd, GCRY_MD_SHA256, 0)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("gcry_md_open failed\n"); ++ } ++ ++ _gcry_mpi_aprint (GCRYMPI_FMT_STD, &buf, &buflen, data); ++ _gcry_md_write (hd, buf, buflen); ++ ++ xfree (buf); ++ buf = NULL; ++ ++ /* verify the signature */ ++ if (_gcry_pk_verify_md (r_sig, hd, s_hash, s_pkey)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("gcry_pk_verify failed\n"); ++ goto leave; /* Signature does not match. */ ++ } + +- /* Verify the signature using the public key. */ +- if ( verify (sig_a, sig_b, data, &pk) ) +- goto leave; /* Signature does not match. */ +- +- /* Modify the data and check that the signing fails. */ +- mpi_add_ui (data, data, 1); +- if ( !verify (sig_a, sig_b, data, &pk) ) +- goto leave; /* Signature matches but should not. */ +- +- result = 0; /* The test succeeded. */ ++ result = 0; /* The test succeeded. */ + + leave: + _gcry_mpi_release (sig_b); + _gcry_mpi_release (sig_a); + _gcry_mpi_release (data); ++ ++ _gcry_sexp_release (s_skey); ++ _gcry_sexp_release (s_pkey); ++ _gcry_sexp_release (s_hash); ++ _gcry_sexp_release (r_sig); ++ _gcry_mpi_release (r_sig_mpi); ++ _gcry_mpi_release (s_sig_mpi); ++ _gcry_md_close (hd); ++ + return result; + } + diff --git a/libgcrypt-PCT-ECC.patch b/libgcrypt-PCT-ECC.patch new file mode 100644 index 0000000..54e113a --- /dev/null +++ b/libgcrypt-PCT-ECC.patch @@ -0,0 +1,342 @@ +Index: libgcrypt-1.9.0/cipher/ecc.c +=================================================================== +--- libgcrypt-1.9.0.orig/cipher/ecc.c ++++ libgcrypt-1.9.0/cipher/ecc.c +@@ -100,7 +100,7 @@ static void *progress_cb_data; + + + /* Local prototypes. */ +-static void test_keys (mpi_ec_t ec, unsigned int nbits); ++static int test_keys (mpi_ec_t ec, unsigned int nbits); + static void test_ecdh_only_keys (mpi_ec_t ec, unsigned int nbits, int flags); + static unsigned int ecc_get_nbits (gcry_sexp_t parms); + +@@ -256,8 +256,10 @@ nist_generate_key (mpi_ec_t ec, int flag + else if (ec->model == MPI_EC_MONTGOMERY) + test_ecdh_only_keys (ec, ec->nbits - 63, flags); + else +- test_keys (ec, ec->nbits - 64); +- ++ { ++ if (test_keys (ec, ec->nbits - 64)) ++ return GPG_ERR_BAD_SIGNATURE; ++ } + return 0; + } + +@@ -268,9 +270,10 @@ nist_generate_key (mpi_ec_t ec, int flag + * test if the information is recuperated. + * Second, test with the sign and verify functions. + */ +-static void ++static int + test_keys (mpi_ec_t ec, unsigned int nbits) + { ++ int result = -1; /* Default to failure. */ + gcry_mpi_t test = mpi_new (nbits); + mpi_point_struct R_; + gcry_mpi_t c = mpi_new (nbits); +@@ -285,23 +288,205 @@ test_keys (mpi_ec_t ec, unsigned int nbi + + _gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM); + +- if (_gcry_ecc_ecdsa_sign (test, ec, r, s, 0, 0) ) +- log_fatal ("ECDSA operation: sign failed\n"); ++ /* Use the gcry_pk_sign_md API in order to comply with FIPS 140-2, ++ * which requires full signature operation for PCT (hashing + ++ * asymmetric operation). */ ++ gcry_sexp_t r_sig = NULL; ++ gcry_sexp_t s_skey = NULL; ++ gcry_sexp_t s_pkey = NULL; ++ gcry_sexp_t s_hash = NULL; ++ gcry_mpi_t s_sig_mpi = NULL; ++ gcry_md_hd_t hd = NULL; ++ unsigned char *buf = NULL; ++ size_t buflen; ++ mpi_ec_t ctx; ++ int flags = 0; ++ ++ if (_gcry_md_open (&hd, GCRY_MD_SHA256, 0)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("gcry_pk_sign failed: _gcry_md_open\n"); ++ } ++ ++ _gcry_mpi_aprint (GCRYMPI_FMT_STD, &buf, &buflen, test); ++ _gcry_md_write (hd, buf, buflen); ++ ++ xfree (buf); ++ buf = NULL; + +- if (_gcry_ecc_ecdsa_verify (test, ec, r, s)) ++ sexp_build (&s_hash, NULL, "(data (flags rfc6979)(hash-algo sha256))"); ++ ++ /* Assemble the point Q from affine coordinates by simple ++ * concatenation. */ ++ gcry_mpi_t Qx = NULL; ++ gcry_mpi_t Qy = NULL; ++ Qx = mpi_new (0); ++ Qy = mpi_new (0); ++ ctx = _gcry_mpi_ec_p_internal_new (ec->model, ec->dialect, flags, ++ ec->p, ec->a, ec->b); ++ if (_gcry_mpi_ec_get_affine (Qx, Qy, ec->Q, ctx)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("ecdh: Failed to get affine coordinates for Q\n"); ++ } ++ ++ unsigned char *rawqx, *rawqy; ++ unsigned int rawqxlen, rawqylen; ++ rawqx = _gcry_mpi_get_buffer (Qx, 0, &rawqxlen, NULL); ++ rawqy = _gcry_mpi_get_buffer (Qy, 0, &rawqylen, NULL); ++ ++ if (rawqxlen != rawqylen) ++ { ++ if (rawqxlen < rawqylen) ++ { ++ size_t diff = rawqylen - rawqxlen; ++ unsigned char *zeros = xmalloc (rawqxlen + diff); ++ memset (zeros, 0, rawqxlen + diff); ++ memmove (zeros + diff, rawqx, rawqxlen); ++ xfree (rawqx); ++ rawqx = zeros; ++ rawqxlen += diff; ++ } ++ if (rawqylen < rawqxlen) ++ { ++ size_t diff = rawqxlen - rawqylen; ++ unsigned char *zeros = xmalloc (rawqylen + diff); ++ memset (zeros, 0, rawqylen + diff); ++ memmove (zeros + diff, rawqy, rawqylen); ++ xfree (rawqy); ++ rawqy = zeros; ++ rawqylen += diff; ++ } ++ } ++ ++ unsigned char q[1 + rawqxlen + rawqxlen]; ++ size_t qlen; ++ memset (&q, 0, sizeof(q)); ++ *q = 4; ++ memcpy (q + 1, rawqx, rawqxlen); ++ memcpy (q + 1 + rawqxlen, rawqy, rawqylen); ++ qlen = 1 + rawqxlen + rawqylen; ++ ++ _gcry_mpi_release (Qx); ++ _gcry_mpi_release (Qy); ++ xfree (rawqx); ++ xfree (rawqy); ++ ++ /* build ECC private key sexp in s_skey */ ++ if (ec->name) ++ { ++ if (sexp_build (&s_skey, NULL, ++ "(private-key (ecc (curve %s)(d %m)(q %b)))", ++ ec->name, ec->d, qlen, q)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("ecc: Failed to build sexp for private key.\n"); ++ } ++ } ++ else ++ { ++ if (sexp_build (&s_skey, NULL, ++ "(private-key" ++ " (ecc (curve %s)(d %m)(p %m)(a %m)(b %m)(n %m)(h %m)(q %b)))", ++ "NIST P-512", ec->d, ec->p, ec->a, ec->b, ec->n, ec->h, ++ qlen, q)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("ecc: Failed to build sexp for private key.\n"); ++ } ++ } ++ if (_gcry_pk_sign_md (&r_sig, hd, s_hash, s_skey)) + { +- log_fatal ("ECDSA operation: sign, verify failed\n"); ++ if (DBG_CIPHER) ++ log_debug ("ecc: gcry_pk_sign failed\n"); ++ goto leave; ++ } ++ ++ /* Check that the signature and the original test differ. */ ++ if (_gcry_sexp_extract_param (r_sig, NULL, "s", &s_sig_mpi, NULL)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("extracting signature data failed\n"); ++ goto leave; ++ } ++ ++ if (!mpi_cmp (s_sig_mpi, test)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("Signature failed\n"); ++ goto leave; /* Signature and test match but should not. */ ++ } ++ ++ /* verify */ ++ /* build public key sexp in s_pkey */ ++ if (ec->name) ++ { ++ if (sexp_build (&s_pkey, NULL, ++ "(public-key (ecc (curve %s)(q %b)))", ec->name, qlen, q)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("ecc: Failed to build sexp for public key.\n"); ++ } ++ } ++ else ++ { ++ if (sexp_build (&s_pkey, NULL, ++ "(public-key" ++ " (ecc (curve %s)(p %m)(a %m)(b %m)(n %m)(h %m)(q %b)))", ++ "NIST P-512", ec->p, ec->a, ec->b, ec->n, ec->h, qlen, q)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("ecc: Failed to build sexp for private key.\n"); ++ } ++ } ++ ++ _gcry_md_close (hd); ++ ++ if (_gcry_md_open (&hd, GCRY_MD_SHA256, 0)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("gcry_pk_verify failed: _gcry_md_open\n"); ++ } ++ ++ _gcry_mpi_aprint (GCRYMPI_FMT_STD, &buf, &buflen, test); ++ _gcry_md_write (hd, buf, buflen); ++ ++ xfree (buf); ++ buf = NULL; ++ ++ /* verify the signature */ ++ if (_gcry_pk_verify_md (r_sig, hd, s_hash, s_pkey)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("ecc: gcry_pk_verify failed\n"); ++ goto leave; /* Signature does not match. */ + } + + if (DBG_CIPHER) +- log_debug ("ECDSA operation: sign, verify ok.\n"); ++ { ++ if (DBG_CIPHER) ++ log_debug ("ECDSA operation: sign, verify ok.\n"); ++ } ++ ++ result = 0; /* The test succeeded. */ + ++ leave: + point_free (&R_); + mpi_free (s); + mpi_free (r); + mpi_free (out); + mpi_free (c); + mpi_free (test); ++ ++ _gcry_sexp_release (r_sig); ++ _gcry_sexp_release (s_skey); ++ _gcry_sexp_release (s_pkey); ++ _gcry_sexp_release (s_hash); ++ _gcry_mpi_release (s_sig_mpi); ++ _gcry_md_close (hd); ++ xfree (ctx); ++ ++ return result; + } + + +Index: libgcrypt-1.9.0/cipher/pubkey.c +=================================================================== +--- libgcrypt-1.9.0.orig/cipher/pubkey.c ++++ libgcrypt-1.9.0/cipher/pubkey.c +@@ -390,6 +390,7 @@ calculate_hash (gcry_md_hd_t hd, gcry_se + gcry_err_code_t rc; + const unsigned char *digest; + int algo; ++ const char *flags; + + if (!hd) + return 0; +@@ -398,16 +399,21 @@ calculate_hash (gcry_md_hd_t hd, gcry_se + if (rc) + return rc; + ++ rc = _gcry_pk_util_get_flags (*s_hash, &flags); ++ if (rc) ++ return rc; ++ + digest = _gcry_md_read(hd, algo); + if (!digest) + return GPG_ERR_DIGEST_ALGO; + + rc = _gcry_sexp_build (s_hash, NULL, +- "(data (flags pkcs1)(hash %s %b))", ++ "(data (flags %s)(hash %s %b))", flags, + _gcry_md_algo_name(algo), + (int) _gcry_md_get_algo_dlen(algo), + digest); + ++ xfree ((void *)flags); + return rc; + } + +Index: libgcrypt-1.9.0/cipher/pubkey-internal.h +=================================================================== +--- libgcrypt-1.9.0.orig/cipher/pubkey-internal.h ++++ libgcrypt-1.9.0/cipher/pubkey-internal.h +@@ -45,6 +45,8 @@ gcry_err_code_t _gcry_pk_util_data_to_mp + struct pk_encoding_ctx *ctx); + gcry_err_code_t _gcry_pk_util_get_algo (gcry_sexp_t input, + int *algo); ++gcry_err_code_t _gcry_pk_util_get_flags (gcry_sexp_t input, ++ const char **flags); + + + +Index: libgcrypt-1.9.0/cipher/pubkey-util.c +=================================================================== +--- libgcrypt-1.9.0.orig/cipher/pubkey-util.c ++++ libgcrypt-1.9.0/cipher/pubkey-util.c +@@ -1159,6 +1159,40 @@ _gcry_pk_util_data_to_mpi (gcry_sexp_t i + return rc; + } + ++gcry_err_code_t ++_gcry_pk_util_get_flags (gcry_sexp_t input, const char **flags) ++{ ++ gcry_err_code_t rc = 0; ++ gcry_sexp_t ldata, list = NULL; ++ ++ ldata = sexp_find_token (input, "data", 0); ++ if (!ldata) ++ { ++ rc = GPG_ERR_INV_OBJ; ++ goto leave; ++ } ++ ++ list = sexp_find_token (ldata, "flags", 0); ++ if (!list) ++ { ++ rc = GPG_ERR_INV_OBJ; ++ goto leave; ++ } ++ ++ /* FIXME: gets only the first flag */ ++ *flags = sexp_nth_string (list, 1); ++ if (!*flags) ++ { ++ rc = GPG_ERR_NO_OBJ; ++ goto leave; ++ } ++ ++ leave: ++ sexp_release (ldata); ++ sexp_release (list); ++ ++ return rc; ++} + + gcry_err_code_t + _gcry_pk_util_get_algo (gcry_sexp_t input, int *algo) diff --git a/libgcrypt-PCT-RSA.patch b/libgcrypt-PCT-RSA.patch new file mode 100644 index 0000000..ade27d0 --- /dev/null +++ b/libgcrypt-PCT-RSA.patch @@ -0,0 +1,123 @@ +Index: libgcrypt-1.8.2/cipher/rsa.c +=================================================================== +--- libgcrypt-1.8.2.orig/cipher/rsa.c ++++ libgcrypt-1.8.2/cipher/rsa.c +@@ -159,22 +159,97 @@ test_keys (RSA_secret_key *sk, unsigned + /* Create another random plaintext as data for signature checking. */ + _gcry_mpi_randomize (plaintext, nbits, GCRY_WEAK_RANDOM); + +- /* Use the RSA secret function to create a signature of the plaintext. */ +- secret (signature, plaintext, sk); ++ /* Use the gcry_pk_sign_md API in order to comply with FIPS 140-2, ++ * which requires full signature operation for PCT (hashing + ++ * asymmetric operation */ ++ gcry_sexp_t s_skey = NULL; ++ gcry_sexp_t s_pkey = NULL; ++ gcry_sexp_t r_sig = NULL; ++ gcry_sexp_t s_hash = NULL; ++ gcry_md_hd_t hd = NULL; ++ gcry_mpi_t r_sig_mpi = NULL; ++ unsigned char *buf = NULL; ++ size_t buflen; + +- /* Use the RSA public function to verify this signature. */ +- public (decr_plaintext, signature, &pk); +- if (mpi_cmp (decr_plaintext, plaintext)) +- goto leave; /* Signature does not match. */ +- +- /* Modify the signature and check that the signing fails. */ +- mpi_add_ui (signature, signature, 1); +- public (decr_plaintext, signature, &pk); +- if (!mpi_cmp (decr_plaintext, plaintext)) +- goto leave; /* Signature matches but should not. */ ++ if (_gcry_md_open (&hd, GCRY_MD_SHA256, 0)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("gcry_pk_sign/open failed\n"); ++ goto leave_hash; ++ } ++ ++ _gcry_mpi_aprint (GCRYMPI_FMT_STD, &buf, &buflen, plaintext); ++ _gcry_md_write (hd, buf, buflen); ++ ++ xfree (buf); ++ buf = NULL; ++ ++ /* build RSA private key sexp in s_skey */ ++ sexp_build (&s_skey, NULL, ++ "(private-key (rsa(n %m)(e %m)(d %m)(p %m)(q %m)))", ++ sk->n, sk->e, sk->d, sk->p, sk->q); ++ sexp_build (&s_hash, NULL, ++ "(data (flags pkcs1)(hash-algo sha256))"); ++ ++ if (_gcry_pk_sign_md (&r_sig, hd, s_hash, s_skey)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("gcry_pk_sign failed\n"); ++ goto leave_hash; ++ } ++ ++ /* Check that the signature and the original plaintext differ. */ ++ if (_gcry_sexp_extract_param (r_sig, "sig-val!rsa", "s", &r_sig_mpi, NULL)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("extracting signature data failed\n"); ++ goto leave_hash; ++ } ++ ++ if (!mpi_cmp (r_sig_mpi, plaintext)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("Signature failed\n"); ++ goto leave_hash; /* Signature and plaintext match but should not. */ ++ } ++ ++ _gcry_sexp_release (s_hash); ++ _gcry_md_close (hd); ++ ++ /* build RSA public key sexp in s_pkey */ ++ sexp_build (&s_pkey, NULL, "(public-key (rsa(n %m)(e %m)))", pk.n, pk.e); ++ sexp_build (&s_hash, NULL, "(data (flags pkcs1)(hash-algo sha256))"); ++ ++ if (_gcry_md_open (&hd, GCRY_MD_SHA256, 0)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("gcry_md_open failed\n"); ++ } ++ ++ _gcry_mpi_aprint (GCRYMPI_FMT_STD, &buf, &buflen, plaintext); ++ _gcry_md_write (hd, buf, buflen); ++ ++ xfree (buf); ++ buf = NULL; ++ ++ /* verify the signature */ ++ if (_gcry_pk_verify_md (r_sig, hd, s_hash, s_pkey)) ++ { ++ if (DBG_CIPHER) ++ log_debug ("gcry_pk_verify failed\n"); ++ goto leave_hash; /* Signature does not match. */ ++ } + + result = 0; /* All tests succeeded. */ + ++ leave_hash: ++ _gcry_sexp_release (s_skey); ++ _gcry_sexp_release (s_pkey); ++ _gcry_sexp_release (s_hash); ++ _gcry_sexp_release (r_sig); ++ _gcry_md_close (hd); ++ _gcry_mpi_release (r_sig_mpi); ++ + leave: + _gcry_mpi_release (signature); + _gcry_mpi_release (decr_plaintext); +@@ -1903,7 +1979,7 @@ selftest_encr_2048 (gcry_sexp_t pkey, gc + /* This sexp trickery is to prevent the use of blinding. + * The flag doesn't get inherited by encr, so we have to + * derive a new sexp from the ciphertext */ +- char buf[1024]; ++ unsigned char buf[1024]; + memset(buf, 0, sizeof(buf)); + err = _gcry_mpi_print (GCRYMPI_FMT_STD, buf, sizeof buf, NULL, ciphertext); + if (err) diff --git a/libgcrypt-Restore-self-tests-from-constructor.patch b/libgcrypt-Restore-self-tests-from-constructor.patch new file mode 100644 index 0000000..5d6b3a1 --- /dev/null +++ b/libgcrypt-Restore-self-tests-from-constructor.patch @@ -0,0 +1,16 @@ +Index: libgcrypt-1.8.2/src/global.c +=================================================================== +--- libgcrypt-1.8.2.orig/src/global.c ++++ libgcrypt-1.8.2/src/global.c +@@ -140,8 +140,9 @@ global_init (void) + /* We always need the FSM lock to be functional. */ + _gcry_initialize_fsm_lock (); + +- /* Run the self-tests from the constructor. */ +- global_init (); ++ /* We run the integrity check at this point. The remaining ++ selftests are run before use of the library by application. */ ++ _gcry_fips_run_selftests (0); + } + + /* This function is called by the macro fips_is_operational and makes diff --git a/libgcrypt-dsa-rfc6979-test-fix.patch b/libgcrypt-dsa-rfc6979-test-fix.patch new file mode 100644 index 0000000..c902716 --- /dev/null +++ b/libgcrypt-dsa-rfc6979-test-fix.patch @@ -0,0 +1,124 @@ +Index: libgcrypt-1.8.2/tests/benchmark.c +=================================================================== +--- libgcrypt-1.8.2.orig/tests/benchmark.c ++++ libgcrypt-1.8.2/tests/benchmark.c +@@ -1400,7 +1400,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; + +Index: libgcrypt-1.8.2/tests/dsa-rfc6979.c +=================================================================== +--- libgcrypt-1.8.2.orig/tests/dsa-rfc6979.c ++++ libgcrypt-1.8.2/tests/dsa-rfc6979.c +@@ -165,16 +165,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" +@@ -398,89 +388,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-ecc-ecdsa-no-blinding.patch b/libgcrypt-ecc-ecdsa-no-blinding.patch new file mode 100644 index 0000000..4dad390 --- /dev/null +++ b/libgcrypt-ecc-ecdsa-no-blinding.patch @@ -0,0 +1,82 @@ +Index: libgcrypt-1.9.0/cipher/ecc.c +=================================================================== +--- libgcrypt-1.9.0.orig/cipher/ecc.c ++++ libgcrypt-1.9.0/cipher/ecc.c +@@ -1581,11 +1581,11 @@ selftest_sign (gcry_sexp_t pkey, gcry_se + { + /* Sample data from RFC 6979 section A.2.5, hash is of message "sample" */ + static const char sample_data[] = +- "(data (flags rfc6979)" ++ "(data (flags rfc6979 no-blinding)" + " (hash sha256 #af2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e98915" + /**/ "62113d8a62add1bf#))"; + static const char sample_data_bad[] = +- "(data (flags rfc6979)" ++ "(data (flags rfc6979 no-blinding)" + " (hash sha256 #bf2bdbe1aa9b6ec1e2ade1d694f41fc71a831d0268e98915" + /**/ "62113d8a62add1bf#))"; + static const char signature_r[] = +Index: libgcrypt-1.9.0/cipher/ecc-ecdsa.c +=================================================================== +--- libgcrypt-1.9.0.orig/cipher/ecc-ecdsa.c ++++ libgcrypt-1.9.0/cipher/ecc-ecdsa.c +@@ -51,6 +51,7 @@ _gcry_ecc_ecdsa_sign (gcry_mpi_t input, + unsigned int abits, qbits; + gcry_mpi_t b; /* Random number needed for blinding. */ + gcry_mpi_t bi; /* multiplicative inverse of B. */ ++ int with_blinding = !(flags & PUBKEY_FLAG_NO_BLINDING); + + if (DBG_CIPHER) + log_mpidump ("ecdsa sign hash ", input ); +@@ -64,12 +65,15 @@ _gcry_ecc_ecdsa_sign (gcry_mpi_t input, + + b = mpi_snew (qbits); + bi = mpi_snew (qbits); +- do ++ if (with_blinding) + { +- _gcry_mpi_randomize (b, qbits, GCRY_WEAK_RANDOM); +- mpi_mod (b, b, ec->n); ++ do ++ { ++ _gcry_mpi_randomize (b, qbits, GCRY_WEAK_RANDOM); ++ mpi_mod (b, b, ec->n); ++ } ++ while (!mpi_invm (bi, b, ec->n)); + } +- while (!mpi_invm (bi, b, ec->n)); + + k = NULL; + dr = mpi_alloc (0); +@@ -126,14 +130,23 @@ _gcry_ecc_ecdsa_sign (gcry_mpi_t input, + } + while (!mpi_cmp_ui (r, 0)); + +- /* Computation of dr, sum, and s are blinded with b. */ +- mpi_mulm (dr, b, ec->d, ec->n); +- mpi_mulm (dr, dr, r, ec->n); /* dr = d*r mod n */ +- mpi_mulm (sum, b, hash, ec->n); +- mpi_addm (sum, sum, dr, ec->n); /* sum = hash + (d*r) mod n */ +- mpi_mulm (s, k_1, sum, ec->n); /* s = k^(-1)*(hash+(d*r)) mod n */ +- /* Undo blinding by b^-1 */ +- mpi_mulm (s, bi, s, ec->n); ++ if (!with_blinding) ++ { ++ mpi_mulm (dr, ec->d, r, ec->n); /* dr = d*r mod n */ ++ mpi_addm (sum, hash, dr, ec->n); /* sum = hash + (d*r) mod n */ ++ } ++ else ++ { ++ mpi_mulm (dr, b, ec->d, ec->n); ++ mpi_mulm (dr, dr, r, ec->n); /* dr = d*r mod n */ ++ mpi_mulm (sum, b, hash, ec->n); ++ mpi_addm (sum, sum, dr, ec->n); /* sum = hash + (d*r) mod n */ ++ } ++ mpi_mulm (s, k_1, sum, ec->n); /* s = k^(-1)*(hash+(d*r)) mod n */ ++ if (with_blinding) ++ { ++ mpi_mulm (s, bi, s, ec->n); /* Undo blinding by b^-1 */ ++ } + } + while (!mpi_cmp_ui (s, 0)); + diff --git a/libgcrypt-fips_selftest_trigger_file.patch b/libgcrypt-fips_selftest_trigger_file.patch new file mode 100644 index 0000000..b152dfc --- /dev/null +++ b/libgcrypt-fips_selftest_trigger_file.patch @@ -0,0 +1,40 @@ +Index: libgcrypt-1.9.1/src/fips.c +=================================================================== +--- libgcrypt-1.9.1.orig/src/fips.c ++++ libgcrypt-1.9.1/src/fips.c +@@ -660,7 +660,7 @@ get_library_path(const char *libname, co + #endif + + static gpg_error_t +-get_hmac_path(char **fname) ++get_hmac_path(char **fname, char *suffix) + { + char libpath[4096]; + gpg_error_t err; +@@ -685,7 +685,7 @@ get_hmac_path(char **fname) + p = *fname; + memmove (p+1, p, strlen (p)+1); + *p = '.'; +- strcat (*fname, ".hmac"); ++ strcat (*fname, suffix); + err = 0; + } + } +@@ -717,7 +717,7 @@ check_binary_integrity (void) + else + { + FILE *fp; +- err = get_hmac_path(&fname); ++ err = get_hmac_path(&fname, ".hmac"); + if (!err) + { + /* Open the file. */ +@@ -779,7 +779,7 @@ can_skip_selftests(void) + if (fips_mode()) + return 0; + +- if (get_hmac_path(&fname)) ++ if (get_hmac_path(&fname, ".fips")) + return 0; + + /* check the hmac presence */ diff --git a/libgcrypt-fipsdrv-enable-algo-for-dsa-sign.patch b/libgcrypt-fipsdrv-enable-algo-for-dsa-sign.patch new file mode 100644 index 0000000..260ac93 --- /dev/null +++ b/libgcrypt-fipsdrv-enable-algo-for-dsa-sign.patch @@ -0,0 +1,65 @@ +Index: libgcrypt-1.6.1/tests/fipsdrv.c +=================================================================== +--- libgcrypt-1.6.1.orig/tests/fipsdrv.c ++++ libgcrypt-1.6.1/tests/fipsdrv.c +@@ -2190,11 +2190,12 @@ dsa_hash_from_key(gcry_sexp_t s_key) + return GCRY_MD_NONE; + } + +- ++ + /* Sign DATA of length DATALEN using the key taken from the S-expression + encoded KEYFILE. */ + static void +-run_dsa_sign (const void *data, size_t datalen, const char *keyfile) ++run_dsa_sign (const void *data, size_t datalen, ++ int hashalgo, const char *keyfile) + + { + gpg_error_t err; +@@ -2202,13 +2203,20 @@ run_dsa_sign (const void *data, size_t d + char hash[128]; + gcry_mpi_t tmpmpi; + int algo; ++ int algo_len; ++ int hashalgo_len; + + s_key = read_sexp_from_file (keyfile); + algo = dsa_hash_from_key(s_key); ++ algo_len = gcry_md_get_algo_dlen(algo); ++ hashalgo_len = gcry_md_get_algo_dlen(hashalgo); + +- gcry_md_hash_buffer (algo, hash, data, datalen); ++ if (hashalgo_len < algo_len) ++ algo_len = hashalgo_len; ++ ++ gcry_md_hash_buffer (hashalgo, hash, data, datalen); + err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash, +- gcry_md_get_algo_dlen(algo), NULL); ++ algo_len, NULL); + if (!err) + { + err = gcry_sexp_build (&s_data, NULL, +@@ -3000,14 +3008,21 @@ main (int argc, char **argv) + } + else if (!strcmp (mode_string, "dsa-sign")) + { ++ int algo; ++ + if (!key_string) + die ("option --key is required in this mode\n"); + if (access (key_string, R_OK)) + die ("option --key needs to specify an existing keyfile\n"); ++ if (!algo_string) ++ die ("option --algo is required in this mode\n"); ++ algo = gcry_md_map_name (algo_string); ++ if (!algo) ++ die ("digest algorithm `%s' is not supported\n", algo_string); + if (!data) + die ("no data available (do not use --chunk)\n"); + +- run_dsa_sign (data, datalen, key_string); ++ run_dsa_sign (data, datalen, algo, key_string); + } + else if (!strcmp (mode_string, "dsa-verify")) + { diff --git a/libgcrypt-fipsdrv-enable-algo-for-dsa-verify.patch b/libgcrypt-fipsdrv-enable-algo-for-dsa-verify.patch new file mode 100644 index 0000000..3f798ef --- /dev/null +++ b/libgcrypt-fipsdrv-enable-algo-for-dsa-verify.patch @@ -0,0 +1,64 @@ +--- libgcrypt-1.6.1-orig/tests/fipsdrv.c 2017-10-20 10:39:56.080098385 +0000 ++++ libgcrypt-1.6.1-orig/tests/fipsdrv.c 2017-10-20 10:41:15.780098385 +0000 +@@ -2288,7 +2288,7 @@ run_dsa_sign (const void *data, size_t d + S-expression in KEYFILE against the S-expression formatted + signature in SIGFILE. */ + static void +-run_dsa_verify (const void *data, size_t datalen, ++run_dsa_verify (const void *data, size_t datalen, int hashalgo, + const char *keyfile, const char *sigfile) + + { +@@ -2297,15 +2297,23 @@ run_dsa_verify (const void *data, size_t + char hash[128]; + gcry_mpi_t tmpmpi; + int algo; ++ int algo_len; ++ int hashalgo_len; + + s_key = read_sexp_from_file (keyfile); + algo = dsa_hash_from_key(s_key); + +- gcry_md_hash_buffer (algo, hash, data, datalen); ++ algo_len = gcry_md_get_algo_dlen(algo); ++ hashalgo_len = gcry_md_get_algo_dlen(hashalgo); ++ ++ if (hashalgo_len < algo_len) ++ algo_len = hashalgo_len; ++ ++ gcry_md_hash_buffer (hashalgo, 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, +- gcry_md_get_algo_dlen(algo), NULL); ++ algo_len, NULL); + if (!err) + { + err = gcry_sexp_build (&s_data, NULL, +@@ -3011,10 +3019,17 @@ main (int argc, char **argv) + } + else if (!strcmp (mode_string, "dsa-verify")) + { ++ int algo; ++ + if (!key_string) + die ("option --key is required in this mode\n"); + if (access (key_string, R_OK)) + die ("option --key needs to specify an existing keyfile\n"); ++ if (!algo_string) ++ die ("option --algo is required in this mode\n"); ++ algo = gcry_md_map_name (algo_string); ++ if (!algo) ++ die ("digest algorithm `%s' is not supported\n", algo_string); + if (!data) + die ("no data available (do not use --chunk)\n"); + if (!signature_string) +@@ -3022,7 +3037,7 @@ main (int argc, char **argv) + if (access (signature_string, R_OK)) + die ("option --signature needs to specify an existing file\n"); + +- run_dsa_verify (data, datalen, key_string, signature_string); ++ run_dsa_verify (data, datalen, algo, key_string, signature_string); + } + else if (!strcmp (mode_string, "ecdsa-gen-key")) + { diff --git a/libgcrypt-fix-rng.patch b/libgcrypt-fix-rng.patch new file mode 100644 index 0000000..53be9ba --- /dev/null +++ b/libgcrypt-fix-rng.patch @@ -0,0 +1,24 @@ +Index: libgcrypt-1.7.2/random/random.c +=================================================================== +--- libgcrypt-1.7.2.orig/random/random.c ++++ libgcrypt-1.7.2/random/random.c +@@ -419,6 +419,9 @@ _gcry_create_nonce (void *buffer, size_t + size_t n; + int err; + ++ /* Make sure we are initialized. */ ++ _gcry_random_initialize (1); ++ + /* First check whether we shall use the FIPS nonce generator. This + is only done in FIPS mode, in all other modes, we use our own + nonce generator which is seeded by the RNG actual in use. */ +@@ -433,9 +436,6 @@ _gcry_create_nonce (void *buffer, size_t + FIPS mode (not that this means it is also used if the FIPS RNG + has been selected but we are not in fips mode). */ + +- /* Make sure we are initialized. */ +- _gcry_random_initialize (1); +- + /* Acquire the nonce buffer lock. */ + err = gpgrt_lock_lock (&nonce_buffer_lock); + if (err) diff --git a/libgcrypt-fix-tests-fipsmode.patch b/libgcrypt-fix-tests-fipsmode.patch new file mode 100644 index 0000000..a9ab40c --- /dev/null +++ b/libgcrypt-fix-tests-fipsmode.patch @@ -0,0 +1,177 @@ +Index: libgcrypt-1.9.1/tests/basic.c +=================================================================== +--- libgcrypt-1.9.1.orig/tests/basic.c ++++ libgcrypt-1.9.1/tests/basic.c +@@ -9978,7 +9978,7 @@ check_ciphers (void) + check_one_cipher (algos[i], GCRY_CIPHER_MODE_EAX, 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); +@@ -10025,12 +10025,18 @@ 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_eax_cipher (); +- check_gost28147_cipher (); ++ if (!in_fips_mode) ++ { ++ check_gost28147_cipher (); ++ } + check_stream_cipher (); + check_stream_cipher_large_block (); + +@@ -13383,7 +13389,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", +@@ -14508,8 +14514,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"); + +@@ -14534,15 +14538,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"); +- } + } + } + +Index: libgcrypt-1.9.1/tests/benchmark.c +=================================================================== +--- libgcrypt-1.9.1.orig/tests/benchmark.c ++++ libgcrypt-1.9.1/tests/benchmark.c +@@ -943,8 +943,10 @@ cipher_bench ( const char *algoname ) + && algo != GCRY_CIPHER_CHACHA20) + 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; +Index: libgcrypt-1.9.1/tests/bench-slope.c +=================================================================== +--- libgcrypt-1.9.1.orig/tests/bench-slope.c ++++ libgcrypt-1.9.1/tests/bench-slope.c +@@ -1573,7 +1573,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 */ +Index: libgcrypt-1.9.1/tests/pubkey.c +=================================================================== +--- libgcrypt-1.9.1.orig/tests/pubkey.c ++++ libgcrypt-1.9.1/tests/pubkey.c +@@ -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)); +@@ -596,7 +611,7 @@ get_dsa_key_fips186_with_seed_new (gcry_ + " (use-fips186)" + " (transient-key)" + " (derive-parms" +- " (seed #f770a4598ff756931fc529764513b103ce57d85f4ad8c5cf297c9b4d48241c5b#))))", ++ " (seed #8b4c4d671fff82e8ed932260206d0571e3a1c2cee8cd94cb73fe58f9b67488fa#))))", + 0, 1); + if (rc) + die ("error creating S-expression: %s\n", gcry_strerror (rc)); +Index: libgcrypt-1.9.1/tests/t-secmem.c +=================================================================== +--- libgcrypt-1.9.1.orig/tests/t-secmem.c ++++ libgcrypt-1.9.1/tests/t-secmem.c +@@ -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-global_init-constructor.patch b/libgcrypt-global_init-constructor.patch new file mode 100644 index 0000000..dd4e523 --- /dev/null +++ b/libgcrypt-global_init-constructor.patch @@ -0,0 +1,254 @@ +Index: libgcrypt-1.9.1/src/global.c +=================================================================== +--- libgcrypt-1.9.1.orig/src/global.c ++++ libgcrypt-1.9.1/src/global.c +@@ -86,7 +86,7 @@ static gpg_err_code_t external_lock_test + likely to be called at startup. The suggested way for an + application to make sure that this has been called is by using + gcry_check_version. */ +-static void ++static void __attribute__((constructor)) + global_init (void) + { + gcry_error_t err = 0; +@@ -134,6 +134,16 @@ global_init (void) + if (err) + goto fail; + ++ 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; ++ err = _gcry_fips_run_selftests (0); ++ no_secure_memory = no_secmem_save; ++ ++ if (err) ++ goto fail; ++ + return; + + fail: +@@ -141,16 +151,6 @@ global_init (void) + } + + +-void __attribute__ ((constructor)) _gcry_global_constructor (void) +-{ +- /* We always need the FSM lock to be functional. */ +- _gcry_initialize_fsm_lock (); +- +- /* We run the integrity check at this point. The remaining +- selftests are run before use of the library by application. */ +- _gcry_fips_run_selftests (0); +-} +- + /* 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 +Index: libgcrypt-1.9.1/src/fips.c +=================================================================== +--- libgcrypt-1.9.1.orig/src/fips.c ++++ libgcrypt-1.9.1/src/fips.c +@@ -124,6 +124,7 @@ void + _gcry_initialize_fips_mode (int force) + { + static int done; ++ gpg_error_t err; + + /* Make sure we are not accidentally called twice. */ + if (done) +@@ -213,6 +214,23 @@ _gcry_initialize_fips_mode (int force) + /* Yes, we are in FIPS mode. */ + FILE *fp; + ++ /* Intitialize the lock to protect the FSM. */ ++ err = gpgrt_lock_init (&fsm_lock); ++ if (err) ++ { ++ /* If that fails we can't do anything but abort the ++ * process. We need to use log_info so that the FSM won't ++ * get involved. */ ++ log_info ("FATAL: failed to create the FSM lock in libgcrypt: %s\n", ++ gpg_strerror (err)); ++#ifdef HAVE_SYSLOG ++ syslog (LOG_USER|LOG_ERR, "Libgcrypt error: " ++ "creating FSM lock failed: %s - abort", ++ gpg_strerror (err)); ++#endif /*HAVE_SYSLOG*/ ++ abort (); ++ } ++ + /* If the FIPS force files exists, is readable and has a number + != 0 on its first line, we enable the enforced fips mode. */ + fp = fopen (FIPS_FORCE_FILE, "r"); +@@ -641,6 +659,39 @@ get_library_path(const char *libname, co + } + #endif + ++static gpg_error_t ++get_hmac_path(char **fname) ++{ ++ char libpath[4096]; ++ gpg_error_t err; ++ ++ if (get_library_path ("libgcrypt.so.20", "gcry_check_version", libpath, sizeof(libpath))) ++ err = gpg_error_from_syserror (); ++ else ++ { ++ *fname = _gcry_malloc (strlen (libpath) + 1 + 5 + 1 ); ++ if (!*fname) ++ err = gpg_error_from_syserror (); ++ else ++ { ++ char *p; ++ ++ /* Prefix the basename with a dot. */ ++ strcpy (*fname, libpath); ++ p = strrchr (*fname, '/'); ++ if (p) ++ p++; ++ else ++ p = *fname; ++ memmove (p+1, p, strlen (p)+1); ++ *p = '.'; ++ strcat (*fname, ".hmac"); ++ err = 0; ++ } ++ } ++ return err; ++} ++ + /* Run an integrity check on the binary. Returns 0 on success. */ + static int + check_binary_integrity (void) +@@ -665,25 +716,10 @@ check_binary_integrity (void) + err = gpg_error (GPG_ERR_INTERNAL); + else + { +- fname = xtrymalloc (strlen (libpath) + 1 + 5 + 1 ); +- if (!fname) +- err = gpg_error_from_syserror (); +- else ++ FILE *fp; ++ err = get_hmac_path(&fname); ++ if (!err) + { +- FILE *fp; +- char *p; +- +- /* Prefix the basename with a dot. */ +- strcpy (fname, libpath); +- p = strrchr (fname, '/'); +- if (p) +- p++; +- else +- p = fname; +- memmove (p+1, p, strlen (p)+1); +- *p = '.'; +- strcat (fname, ".hmac"); +- + /* Open the file. */ + fp = fopen (fname, "r"); + if (!fp) +@@ -734,6 +770,33 @@ check_binary_integrity (void) + #endif + } + ++int ++can_skip_selftests(void) ++{ ++ char *fname = NULL; ++ int ret = 0; ++ ++ if (fips_mode()) ++ return 0; ++ ++ if (get_hmac_path(&fname)) ++ return 0; ++ ++ /* check the hmac presence */ ++ if (access(fname, F_OK)) ++ /* no hmac file is present, don't run the tests */ ++ if (errno == ENOENT) ++ ret = 1; ++ /* otherwise one of these events happened: ++ * access() returned 0 ++ * -> run the tests ++ * some error other than ENOENT occurred ++ * -> run the tests anyway and let them fail ++ */ ++ ++ xfree(fname); ++ return ret; ++} + + /* Run the self-tests. If EXTENDED is true, extended versions of the + selftest are run, that is more tests than required by FIPS. */ +@@ -742,26 +805,13 @@ _gcry_fips_run_selftests (int extended) + { + enum module_states result = STATE_ERROR; + gcry_err_code_t ec = GPG_ERR_SELFTEST_FAILED; +- int in_poweron; +- +- lock_fsm (); +- in_poweron = (current_state == STATE_POWERON); +- unlock_fsm (); +- +- fips_new_state (STATE_SELFTEST); + +- /* We first check the integrity of the binary. +- If run from the constructor we are in POWERON state, +- we return and finish the remaining selftests before +- real use of the library. It will be in the POWERON +- state meanwhile. */ +- if (in_poweron) +- if (check_binary_integrity ()) +- goto leave; +- +- if (in_poweron) ++ if (can_skip_selftests()) + return 0; + ++ if (fips_mode ()) ++ fips_new_state (STATE_SELFTEST); ++ + if (run_cipher_selftests (extended)) + goto leave; + +@@ -774,6 +824,9 @@ _gcry_fips_run_selftests (int extended) + if (run_kdf_selftests (extended)) + goto leave; + ++ if (check_binary_integrity ()) ++ goto leave; ++ + /* Run random tests before the pubkey tests because the latter + require random. */ + if (run_random_selftests ()) +@@ -787,7 +840,8 @@ _gcry_fips_run_selftests (int extended) + ec = 0; + + leave: +- fips_new_state (result); ++ if (fips_mode ()) ++ fips_new_state (result); + + return ec; + } +@@ -843,7 +897,6 @@ fips_new_state (enum module_states new_s + { + case STATE_POWERON: + if (new_state == STATE_INIT +- || new_state == STATE_SELFTEST + || new_state == STATE_ERROR + || new_state == STATE_FATALERROR) + ok = 1; +@@ -858,8 +911,6 @@ fips_new_state (enum module_states new_s + + case STATE_SELFTEST: + if (new_state == STATE_OPERATIONAL +- || new_state == STATE_INIT +- || new_state == STATE_SELFTEST + || new_state == STATE_ERROR + || new_state == STATE_FATALERROR) + ok = 1; diff --git a/libgcrypt-hwf-ppc-fix-missing-HWF_PPC_ARCH_3_10-in-HW-feature.patch b/libgcrypt-hwf-ppc-fix-missing-HWF_PPC_ARCH_3_10-in-HW-feature.patch new file mode 100644 index 0000000..6b9732f --- /dev/null +++ b/libgcrypt-hwf-ppc-fix-missing-HWF_PPC_ARCH_3_10-in-HW-feature.patch @@ -0,0 +1,26 @@ +From 29bfb3ebbc63d7ed18b916c5c6946790fb3d15df Mon Sep 17 00:00:00 2001 +From: Jussi Kivilinna +Date: Fri, 1 Apr 2022 09:49:20 +0300 +Subject: hwf-ppc: fix missing HWF_PPC_ARCH_3_10 in HW feature + +* src/hwf-ppc.c (ppc_features): Add HWF_PPC_ARCH_3_10. +-- + +GnuPG-bug-id: T5913 +Signed-off-by: Jussi Kivilinna + +diff --git a/src/hwf-ppc.c b/src/hwf-ppc.c +index 7801f8b0..11d14dc1 100644 +--- a/src/hwf-ppc.c ++++ b/src/hwf-ppc.c +@@ -103,6 +103,7 @@ static const struct feature_map_s ppc_features[] = + { 0, PPC_FEATURE2_VEC_CRYPTO, HWF_PPC_VCRYPTO }, + #endif + { 0, PPC_FEATURE2_ARCH_3_00, HWF_PPC_ARCH_3_00 }, ++ { 0, PPC_FEATURE2_ARCH_3_10, HWF_PPC_ARCH_3_10 }, + }; + #endif + +-- +2.38.1 + diff --git a/libgcrypt-indicate-shake.patch b/libgcrypt-indicate-shake.patch new file mode 100644 index 0000000..7879ff3 --- /dev/null +++ b/libgcrypt-indicate-shake.patch @@ -0,0 +1,13 @@ +Index: libgcrypt-1.9.4/src/fips.c +=================================================================== +--- libgcrypt-1.9.4.orig/src/fips.c ++++ libgcrypt-1.9.4/src/fips.c +@@ -593,6 +593,8 @@ _gcry_fips_indicator_hash (va_list arg_p + case GCRY_MD_SHA3_256: + case GCRY_MD_SHA3_384: + case GCRY_MD_SHA3_512: ++ case GCRY_MD_SHAKE128: ++ case GCRY_MD_SHAKE256: + return GPG_ERR_NO_ERROR; + default: + return GPG_ERR_NOT_SUPPORTED; diff --git a/libgcrypt-invoke-global_init-from-constructor.patch b/libgcrypt-invoke-global_init-from-constructor.patch new file mode 100644 index 0000000..96b9652 --- /dev/null +++ b/libgcrypt-invoke-global_init-from-constructor.patch @@ -0,0 +1,14 @@ +Index: libgcrypt-1.8.2/src/global.c +=================================================================== +--- libgcrypt-1.8.2.orig/src/global.c ++++ libgcrypt-1.8.2/src/global.c +@@ -145,6 +145,9 @@ void __attribute__ ((constructor)) _gcry + { + /* We always need the FSM lock to be functional. */ + _gcry_initialize_fsm_lock (); ++ ++ /* Run the self-tests from the constructor. */ ++ global_init (); + } + + /* This function is called by the macro fips_is_operational and makes diff --git a/libgcrypt-jitterentropy-3.3.0.patch b/libgcrypt-jitterentropy-3.3.0.patch new file mode 100644 index 0000000..496b0f8 --- /dev/null +++ b/libgcrypt-jitterentropy-3.3.0.patch @@ -0,0 +1,4168 @@ +Index: libgcrypt-1.9.4/LICENSES +=================================================================== +--- libgcrypt-1.9.4.orig/LICENSES ++++ libgcrypt-1.9.4/LICENSES +@@ -57,46 +57,53 @@ with any binary distributions derived fr + + For files: + - random/jitterentropy-base.c ++ - random/jitterentropy-gcd.c ++ - random/jitterentropy-gcd.h ++ - random/jitterentropy-health.c ++ - random/jitterentropy-health.h ++ - random/jitterentropy-noise.c ++ - random/jitterentropy-noise.h ++ - random/jitterentropy-sha3.c ++ - random/jitterentropy-sha3.h ++ - random/jitterentropy-timer.c ++ - random/jitterentropy-timer.h + - random/jitterentropy.h + - random/rndjent.c (plus common Libgcrypt copyright holders) + + #+begin_quote +- * Copyright Stephan Mueller , 2013 +- * +- * License +- * ======= +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions +- * are met: +- * 1. Redistributions of source code must retain the above copyright +- * notice, and the entire permission notice in its entirety, +- * including the disclaimer of warranties. +- * 2. Redistributions in binary form must reproduce the above copyright +- * notice, this list of conditions and the following disclaimer in the +- * documentation and/or other materials provided with the distribution. +- * 3. The name of the author may not be used to endorse or promote +- * products derived from this software without specific prior +- * written permission. +- * +- * ALTERNATIVELY, this product may be distributed under the terms of +- * the GNU General Public License, in which case the provisions of the GPL are +- * required INSTEAD OF the above restrictions. (This clause is +- * necessary due to a potential bad interaction between the GPL and +- * the restrictions contained in a BSD-style copyright.) +- * +- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF +- * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE +- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +- * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH +- * DAMAGE. ++ Copyright (C) 2017 - 2021, Stephan Mueller ++ ++ Redistribution and use in source and binary forms, with or without ++ modification, are permitted provided that the following conditions ++ are met: ++ 1. Redistributions of source code must retain the above copyright ++ notice, and the entire permission notice in its entirety, ++ including the disclaimer of warranties. ++ 2. Redistributions in binary form must reproduce the above copyright ++ notice, this list of conditions and the following disclaimer in the ++ documentation and/or other materials provided with the distribution. ++ 3. The name of the author may not be used to endorse or promote ++ products derived from this software without specific prior ++ written permission. ++ ++ ALTERNATIVELY, this product may be distributed under the terms of ++ the GNU General Public License, in which case the provisions of the GPL2 ++ are required INSTEAD OF the above restrictions. (This clause is ++ necessary due to a potential bad interaction between the GPL and ++ the restrictions contained in a BSD-style copyright.) ++ ++ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF ++ WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE ++ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT ++ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ++ USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH ++ DAMAGE. + #+end_quote + + For files: +Index: libgcrypt-1.9.4/random/jitterentropy-base.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-base.c ++++ libgcrypt-1.9.4/random/jitterentropy-base.c +@@ -11,29 +11,9 @@ + * Interface + * ========= + * +- * See documentation in doc/ folder. +- * +- * License +- * ======= ++ * See documentation in jitterentropy(3) man page. + * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions +- * are met: +- * 1. Redistributions of source code must retain the above copyright +- * notice, and the entire permission notice in its entirety, +- * including the disclaimer of warranties. +- * 2. Redistributions in binary form must reproduce the above copyright +- * notice, this list of conditions and the following disclaimer in the +- * documentation and/or other materials provided with the distribution. +- * 3. The name of the author may not be used to endorse or promote +- * products derived from this software without specific prior +- * written permission. +- * +- * ALTERNATIVELY, this product may be distributed under the terms of +- * the GNU General Public License, in which case the provisions of the GPL2 are +- * required INSTEAD OF the above restrictions. (This clause is +- * necessary due to a potential bad interaction between the GPL and +- * the restrictions contained in a BSD-style copyright.) ++ * License: see LICENSE file in root directory + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +@@ -49,30 +29,43 @@ + * DAMAGE. + */ + +-#undef _FORTIFY_SOURCE +-#ifdef __OPTIMIZE__ +-#pragma GCC optimize ("O0") +-#endif +- + #include "jitterentropy.h" + +-#ifndef CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT +- /* only check optimization in a compilation for real work */ +- #ifdef __OPTIMIZE__ +- #error "The CPU Jitter random number generator must not be compiled with optimizations. See documentation. Use the compiler switch -O0 for compiling jitterentropy-base.c." +- #endif +-#endif ++#include "jitterentropy-base.h" ++#include "jitterentropy-gcd.h" ++#include "jitterentropy-health.h" ++#include "jitterentropy-noise.h" ++#include "jitterentropy-timer.h" ++#include "jitterentropy-sha3.h" + +-#define MAJVERSION 2 /* API / ABI incompatible changes, functional changes that ++#define MAJVERSION 3 /* API / ABI incompatible changes, functional changes that + * require consumer to be updated (as long as this number + * is zero, the API is not considered stable and can + * change without a bump of the major version) */ +-#define MINVERSION 1 /* API compatible, ABI may change, functional ++#define MINVERSION 3 /* API compatible, ABI may change, functional + * enhancements only, consumer can be left unchanged if + * enhancements are not considered */ + #define PATCHLEVEL 0 /* API / ABI compatible, no functional changes, no + * enhancements, bug fixes only */ + ++/*************************************************************************** ++ * Jitter RNG Static Definitions ++ * ++ * None of the following should be altered ++ ***************************************************************************/ ++ ++#ifdef __OPTIMIZE__ ++ #error "The CPU Jitter random number generator must not be compiled with optimizations. See documentation. Use the compiler switch -O0 for compiling jitterentropy.c." ++#endif ++ ++/* ++ * JENT_POWERUP_TESTLOOPCOUNT needs some loops to identify edge ++ * systems. 100 is definitely too little. ++ * ++ * SP800-90B requires at least 1024 initial test cycles. ++ */ ++#define JENT_POWERUP_TESTLOOPCOUNT 1024 ++ + /** + * jent_version() - Return machine-usable version number of jent library + * +@@ -84,7 +77,7 @@ + * The result of this function can be used in comparing the version number + * in a calling program if version-specific calls need to be make. + * +- * Return: Version number of kcapi library ++ * @return Version number of jitterentropy library + */ + JENT_PRIVATE_STATIC + unsigned int jent_version(void) +@@ -98,414 +91,57 @@ unsigned int jent_version(void) + return version; + } + +-/** +- * Update of the loop count used for the next round of +- * an entropy collection. +- * +- * Input: +- * @ec entropy collector struct -- may be NULL +- * @bits is the number of low bits of the timer to consider +- * @min is the number of bits we shift the timer value to the right at +- * the end to make sure we have a guaranteed minimum value +- * +- * @return Newly calculated loop counter +- */ +-static uint64_t jent_loop_shuffle(struct rand_data *ec, +- unsigned int bits, unsigned int min) +-{ +- uint64_t time = 0; +- uint64_t shuffle = 0; +- unsigned int i = 0; +- unsigned int mask = (1<data; +- /* +- * We fold the time value as much as possible to ensure that as many +- * bits of the time stamp are included as possible. +- */ +- for (i = 0; (DATA_SIZE_BITS / bits) > i; i++) { +- shuffle ^= time & mask; +- time = time >> bits; +- } +- +- /* +- * We add a lower boundary value to ensure we have a minimum +- * RNG loop count. +- */ +- return (shuffle + (1<data +- * +- * @return Number of loops the folding operation is performed +- */ +-static uint64_t jent_lfsr_time(struct rand_data *ec, uint64_t time, +- uint64_t loop_cnt) ++/* Calculate log2 of given value assuming that the value is a power of 2 */ ++static inline unsigned int jent_log2_simple(unsigned int val) + { +- unsigned int i; +- uint64_t j = 0; +- uint64_t new = 0; +-#define MAX_FOLD_LOOP_BIT 4 +-#define MIN_FOLD_LOOP_BIT 0 +- uint64_t fold_loop_cnt = +- jent_loop_shuffle(ec, MAX_FOLD_LOOP_BIT, MIN_FOLD_LOOP_BIT); +- +- /* +- * testing purposes -- allow test app to set the counter, not +- * needed during runtime +- */ +- if (loop_cnt) +- fold_loop_cnt = loop_cnt; +- for (j = 0; j < fold_loop_cnt; j++) { +- new = ec->data; +- for (i = 1; (DATA_SIZE_BITS) >= i; i++) { +- uint64_t tmp = time << (DATA_SIZE_BITS - i); +- +- tmp = tmp >> (DATA_SIZE_BITS - 1); ++ unsigned int idx = 0; + +- /* +- * Fibonacci LSFR with polynomial of +- * x^64 + x^61 + x^56 + x^31 + x^28 + x^23 + 1 which is +- * primitive according to +- * http://poincare.matf.bg.ac.rs/~ezivkovm/publications/primpol1.pdf +- * (the shift values are the polynomial values minus one +- * due to counting bits from 0 to 63). As the current +- * position is always the LSB, the polynomial only needs +- * to shift data in from the left without wrap. +- */ +- new ^= tmp; +- new ^= ((new >> 63) & 1); +- new ^= ((new >> 60) & 1); +- new ^= ((new >> 55) & 1); +- new ^= ((new >> 30) & 1); +- new ^= ((new >> 27) & 1); +- new ^= ((new >> 22) & 1); +- new = rol64(new, 1); +- } +- } +- ec->data = new; +- +- return fold_loop_cnt; ++ while (val >>= 1) ++ idx++; ++ return idx; + } + +-/** +- * Memory Access noise source -- this is a noise source based on variations in +- * memory access times +- * +- * This function performs memory accesses which will add to the timing +- * variations due to an unknown amount of CPU wait states that need to be +- * added when accessing memory. The memory size should be larger than the L1 +- * caches as outlined in the documentation and the associated testing. +- * +- * The L1 cache has a very high bandwidth, albeit its access rate is usually +- * slower than accessing CPU registers. Therefore, L1 accesses only add minimal +- * variations as the CPU has hardly to wait. Starting with L2, significant +- * variations are added because L2 typically does not belong to the CPU any more +- * and therefore a wider range of CPU wait states is necessary for accesses. +- * L3 and real memory accesses have even a wider range of wait states. However, +- * to reliably access either L3 or memory, the ec->mem memory must be quite +- * large which is usually not desirable. +- * +- * Input: +- * @ec Reference to the entropy collector with the memory access data -- if +- * the reference to the memory block to be accessed is NULL, this noise +- * source is disabled +- * @loop_cnt if a value not equal to 0 is set, use the given value as number of +- * loops to perform the folding +- * +- * @return Number of memory access operations +- */ +-static unsigned int jent_memaccess(struct rand_data *ec, uint64_t loop_cnt) ++/* Increase the memory size by one step */ ++static inline unsigned int jent_update_memsize(unsigned int flags) + { +- unsigned int wrap = 0; +- uint64_t i = 0; +-#define MAX_ACC_LOOP_BIT 7 +-#define MIN_ACC_LOOP_BIT 0 +- uint64_t acc_loop_cnt = +- jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT); +- +- if (NULL == ec || NULL == ec->mem) +- return 0; +- wrap = ec->memblocksize * ec->memblocks; ++ unsigned int global_max = JENT_FLAGS_TO_MAX_MEMSIZE( ++ JENT_MAX_MEMSIZE_MAX); ++ unsigned int max; + +- /* +- * testing purposes -- allow test app to set the counter, not +- * needed during runtime +- */ +- if (loop_cnt) +- acc_loop_cnt = loop_cnt; ++ max = JENT_FLAGS_TO_MAX_MEMSIZE(flags); + +- for (i = 0; i < (ec->memaccessloops + acc_loop_cnt); i++) { +- unsigned char *tmpval = ec->mem + ec->memlocation; +- /* +- * memory access: just add 1 to one byte, +- * wrap at 255 -- memory access implies read +- * from and write to memory location +- */ +- *tmpval = (*tmpval + 1) & 0xff; ++ if (!max) { + /* +- * Addition of memblocksize - 1 to pointer +- * with wrap around logic to ensure that every +- * memory location is hit evenly ++ * The safe starting value is the amount of memory we allocated ++ * last round. + */ +- ec->memlocation = ec->memlocation + ec->memblocksize - 1; +- ec->memlocation = ec->memlocation % wrap; +- } +- return i; ++ max = jent_log2_simple(JENT_MEMORY_SIZE); ++ /* Adjust offset */ ++ max = (max > JENT_MAX_MEMSIZE_OFFSET) ? ++ max - JENT_MAX_MEMSIZE_OFFSET : 0; ++ } else { ++ max++; ++ } ++ ++ max = (max > global_max) ? global_max : max; ++ ++ /* Clear out the max size */ ++ flags &= ~JENT_MAX_MEMSIZE_MASK; ++ /* Set the freshly calculated max size */ ++ flags |= JENT_MAX_MEMSIZE_TO_FLAGS(max); ++ ++ return flags; + } + + /*************************************************************************** +- * Start of entropy processing logic ++ * Random Number Generation + ***************************************************************************/ + + /** +- * Stuck test by checking the: +- * 1st derivation of the jitter measurement (time delta) +- * 2nd derivation of the jitter measurement (delta of time deltas) +- * 3rd derivation of the jitter measurement (delta of delta of time deltas) +- * +- * All values must always be non-zero. +- * +- * Input: +- * @ec Reference to entropy collector +- * @current_delta Jitter time delta +- * +- * @return +- * 0 jitter measurement not stuck (good bit) +- * 1 jitter measurement stuck (reject bit) +- */ +-static int jent_stuck(struct rand_data *ec, uint64_t current_delta) +-{ +- int64_t delta2 = ec->last_delta - current_delta; +- int64_t delta3 = (uint64_t)delta2 - (uint64_t)ec->last_delta2; +- +- ec->last_delta = current_delta; +- ec->last_delta2 = delta2; +- +- if (!current_delta || !delta2 || !delta3) +- return 1; +- +- return 0; +-} +- +-/** +- * This is the heart of the entropy generation: calculate time deltas and +- * use the CPU jitter in the time deltas. The jitter is injected into the +- * entropy pool. +- * +- * WARNING: ensure that ->prev_time is primed before using the output +- * of this function! This can be done by calling this function +- * and not using its result. +- * +- * Input: +- * @entropy_collector Reference to entropy collector +- * +- * @return: result of stuck test +- */ +-static int jent_measure_jitter(struct rand_data *ec) +-{ +- uint64_t time = 0; +- uint64_t current_delta = 0; +- int stuck; +- +- /* Invoke one noise source before time measurement to add variations */ +- jent_memaccess(ec, 0); +- +- /* +- * Get time stamp and calculate time delta to previous +- * invocation to measure the timing variations +- */ +- jent_get_nstime(&time); +- current_delta = time - ec->prev_time; +- ec->prev_time = time; +- +- /* Now call the next noise sources which also injects the data */ +- jent_lfsr_time(ec, current_delta, 0); +- +- /* Check whether we have a stuck measurement. */ +- stuck = jent_stuck(ec, current_delta); +- +- /* +- * Rotate the data buffer by a prime number (any odd number would +- * do) to ensure that every bit position of the input time stamp +- * has an even chance of being merged with a bit position in the +- * entropy pool. We do not use one here as the adjacent bits in +- * successive time deltas may have some form of dependency. The +- * chosen value of 7 implies that the low 7 bits of the next +- * time delta value is concatenated with the current time delta. +- */ +- if (!stuck) +- ec->data = rol64(ec->data, 7); +- +- return stuck; +-} +- +-/** +- * Shuffle the pool a bit by mixing some value with a bijective function (XOR) +- * into the pool. +- * +- * The function generates a mixer value that depends on the bits set and the +- * location of the set bits in the random number generated by the entropy +- * source. Therefore, based on the generated random number, this mixer value +- * can have 2**64 different values. That mixer value is initialized with the +- * first two SHA-1 constants. After obtaining the mixer value, it is XORed into +- * the random number. +- * +- * The mixer value is not assumed to contain any entropy. But due to the XOR +- * operation, it can also not destroy any entropy present in the entropy pool. +- * +- * Input: +- * @entropy_collector Reference to entropy collector +- */ +-static void jent_stir_pool(struct rand_data *entropy_collector) +-{ +- /* +- * to shut up GCC on 32 bit, we have to initialize the 64 variable +- * with two 32 bit variables +- */ +- union c { +- uint64_t uint64; +- uint32_t uint32[2]; +- }; +- /* +- * This constant is derived from the first two 32 bit initialization +- * vectors of SHA-1 as defined in FIPS 180-4 section 5.3.1 +- */ +- union c constant; +- /* +- * The start value of the mixer variable is derived from the third +- * and fourth 32 bit initialization vector of SHA-1 as defined in +- * FIPS 180-4 section 5.3.1 +- */ +- union c mixer; +- unsigned int i = 0; +- +- /* Ensure that the function implements a constant time operation. */ +- union c throw_away; +- +- /* +- * Store the SHA-1 constants in reverse order to make up the 64 bit +- * value -- this applies to a little endian system, on a big endian +- * system, it reverses as expected. But this really does not matter +- * as we do not rely on the specific numbers. We just pick the SHA-1 +- * constants as they have a good mix of bit set and unset. +- */ +- constant.uint32[1] = 0x67452301; +- constant.uint32[0] = 0xefcdab89; +- mixer.uint32[1] = 0x98badcfe; +- mixer.uint32[0] = 0x10325476; +- +- for (i = 0; i < DATA_SIZE_BITS; i++) { +- /* +- * get the i-th bit of the input random number and only XOR +- * the constant into the mixer value when that bit is set +- */ +- if ((entropy_collector->data >> i) & 1) +- mixer.uint64 ^= constant.uint64; +- else +- throw_away.uint64 ^= constant.uint64; +- mixer.uint64 = rol64(mixer.uint64, 1); +- } +- entropy_collector->data ^= mixer.uint64; +-} +- +-/** +- * Generator of one 64 bit random number +- * Function fills rand_data->data +- * +- * Input: +- * @ec Reference to entropy collector +- */ +-static void jent_gen_entropy(struct rand_data *ec) +-{ +- unsigned int k = 0; +- +- /* priming of the ->prev_time value */ +- jent_measure_jitter(ec); +- +- while (1) { +- /* If a stuck measurement is received, repeat measurement */ +- if (jent_measure_jitter(ec)) +- continue; +- +- /* +- * We multiply the loop value with ->osr to obtain the +- * oversampling rate requested by the caller +- */ +- if (++k >= (DATA_SIZE_BITS * ec->osr)) +- break; +- } +- if (ec->stir) +- jent_stir_pool(ec); +-} +- +-/** +- * The continuous test required by FIPS 140-2 -- the function automatically +- * primes the test if needed. +- * +- * Return: +- * 0 if FIPS test passed +- * < 0 if FIPS test failed +- */ +-static int jent_fips_test(struct rand_data *ec) +-{ +- if (ec->fips_enabled == -1) +- return 0; +- +- if (ec->fips_enabled == 0) { +- if (!jent_fips_enabled()) { +- ec->fips_enabled = -1; +- return 0; +- } else +- ec->fips_enabled = 1; +- } +- +- /* prime the FIPS test */ +- if (!ec->old_data) { +- ec->old_data = ec->data; +- jent_gen_entropy(ec); +- } +- +- if (ec->data == ec->old_data) +- return -1; +- +- ec->old_data = ec->data; +- +- return 0; +-} +- +-/** + * Entry function: Obtain entropy for the caller. + * + * This function invokes the entropy gathering logic as often to generate +@@ -515,34 +151,50 @@ static int jent_fips_test(struct rand_da + * This function truncates the last 64 bit entropy value output to the exact + * size specified by the caller. + * +- * Input: +- * @ec Reference to entropy collector +- * @data pointer to buffer for storing random data -- buffer must already +- * exist +- * @len size of the buffer, specifying also the requested number of random +- * in bytes ++ * @ec [in] Reference to entropy collector ++ * @data [out] pointer to buffer for storing random data -- buffer must ++ * already exist ++ * @len [in] size of the buffer, specifying also the requested number of random ++ * in bytes + * + * @return number of bytes returned when request is fulfilled or an error + * + * The following error codes can occur: + * -1 entropy_collector is NULL +- * -2 FIPS test failed ++ * -2 RCT failed ++ * -3 APT test failed ++ * -4 The timer cannot be initialized ++ * -5 LAG failure + */ + JENT_PRIVATE_STATIC + ssize_t jent_read_entropy(struct rand_data *ec, char *data, size_t len) + { + char *p = data; + size_t orig_len = len; ++ int ret = 0; + + if (NULL == ec) + return -1; + +- while (0 < len) { ++ if (jent_notime_settick(ec)) ++ return -4; ++ ++ while (len > 0) { + size_t tocopy; ++ unsigned int health_test_result; + +- jent_gen_entropy(ec); +- if (jent_fips_test(ec)) +- return -2; ++ jent_random_data(ec); ++ ++ if ((health_test_result = jent_health_failure(ec))) { ++ if (health_test_result & JENT_RCT_FAILURE) ++ ret = -2; ++ else if (health_test_result & JENT_APT_FAILURE) ++ ret = -3; ++ else ++ ret = -5; ++ ++ goto err; ++ } + + if ((DATA_SIZE_BITS / 8) < len) + tocopy = (DATA_SIZE_BITS / 8); +@@ -569,93 +221,349 @@ ssize_t jent_read_entropy(struct rand_da + * memory protects the entropy pool. Moreover, note that using this + * call reduces the speed of the RNG by up to half + */ +-#ifndef CONFIG_CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY +- jent_gen_entropy(ec); ++#ifndef JENT_CPU_JITTERENTROPY_SECURE_MEMORY ++ jent_random_data(ec); + #endif +- return orig_len; ++ ++err: ++ jent_notime_unsettick(ec); ++ return ret ? ret : (ssize_t)orig_len; ++} ++ ++static struct rand_data *_jent_entropy_collector_alloc(unsigned int osr, ++ unsigned int flags); ++ ++/** ++ * Entry function: Obtain entropy for the caller. ++ * ++ * This is a service function to jent_read_entropy() with the difference ++ * that it automatically re-allocates the entropy collector if a health ++ * test failure is observed. Before reallocation, a new power-on health test ++ * is performed. The allocation of the new entropy collector automatically ++ * increases the OSR by one. This is done based on the idea that a health ++ * test failure indicates that the assumed entropy rate is too high. ++ * ++ * Note the function returns with an health test error if the OSR is ++ * getting too large. If an error is returned by this function, the Jitter RNG ++ * is not safe to be used on the current system. ++ * ++ * @ec [in] Reference to entropy collector - this is a double pointer as ++ * The entropy collector may be freed and reallocated. ++ * @data [out] pointer to buffer for storing random data -- buffer must ++ * already exist ++ * @len [in] size of the buffer, specifying also the requested number of random ++ * in bytes ++ * ++ * @return see jent_read_entropy() ++ */ ++JENT_PRIVATE_STATIC ++ssize_t jent_read_entropy_safe(struct rand_data **ec, char *data, size_t len) ++{ ++ char *p = data; ++ size_t orig_len = len; ++ ssize_t ret = 0; ++ ++ if (!ec) ++ return -1; ++ ++ while (len > 0) { ++ unsigned int osr, flags, max_mem_set; ++ ++ ret = jent_read_entropy(*ec, p, len); ++ ++ switch (ret) { ++ case -1: ++ case -4: ++ return ret; ++ case -2: ++ case -3: ++ case -5: ++ osr = (*ec)->osr + 1; ++ flags = (*ec)->flags; ++ max_mem_set = (*ec)->max_mem_set; ++ ++ /* generic arbitrary cutoff */ ++ if (osr > 20) ++ return ret; ++ ++ /* ++ * If the caller did not set any specific maximum value ++ * let the Jitter RNG increase the maximum memory by ++ * one step. ++ */ ++ if (!max_mem_set) ++ flags = jent_update_memsize(flags); ++ ++ /* ++ * re-allocate entropy collector with higher OSR and ++ * memory size ++ */ ++ jent_entropy_collector_free(*ec); ++ ++ /* Perform new health test with updated OSR */ ++ if (jent_entropy_init_ex(osr, flags)) ++ return -1; ++ ++ *ec = _jent_entropy_collector_alloc(osr, flags); ++ if (!*ec) ++ return -1; ++ ++ /* Remember whether caller configured memory size */ ++ (*ec)->max_mem_set = !!max_mem_set; ++ ++ break; ++ ++ default: ++ len -= (size_t)ret; ++ p += (size_t)ret; ++ } ++ } ++ ++ return (ssize_t)orig_len; + } + + /*************************************************************************** + * Initialization logic + ***************************************************************************/ + +-JENT_PRIVATE_STATIC +-struct rand_data *jent_entropy_collector_alloc(unsigned int osr, +- unsigned int flags) ++/* ++ * Obtain memory size to allocate for memory access variations. ++ * ++ * The maximum variations we can get from the memory access is when we allocate ++ * a bit more memory than we have as data cache. But allocating as much ++ * memory as we have as data cache might strain the resources on the system ++ * more than necessary. ++ * ++ * On a lot of systems it is not necessary to need so much memory as the ++ * variations coming from the general Jitter RNG execution commonly provide ++ * large amount of variations. ++ * ++ * Thus, the default is: ++ * ++ * min(JENT_MEMORY_SIZE, data cache size) ++ * ++ * In case the data cache size cannot be obtained, use JENT_MEMORY_SIZE. ++ * ++ * If the caller provides a maximum memory size, use ++ * min(provided max memory, data cache size). ++ */ ++static inline uint32_t jent_memsize(unsigned int flags) ++{ ++ uint32_t memsize, max_memsize; ++ ++ max_memsize = JENT_FLAGS_TO_MAX_MEMSIZE(flags); ++ ++ if (max_memsize == 0) { ++ max_memsize = JENT_MEMORY_SIZE; ++ } else { ++ max_memsize = UINT32_C(1) << (max_memsize + ++ JENT_MAX_MEMSIZE_OFFSET); ++ } ++ ++ /* Allocate memory for adding variations based on memory access */ ++ memsize = jent_cache_size_roundup(); ++ ++ /* Limit the memory as defined by caller */ ++ memsize = (memsize > max_memsize) ? max_memsize : memsize; ++ ++ /* Set a value if none was found */ ++ if (!memsize) ++ memsize = JENT_MEMORY_SIZE; ++ ++ return memsize; ++} ++ ++static int jent_selftest_run = 0; ++ ++static struct rand_data ++*jent_entropy_collector_alloc_internal(unsigned int osr, unsigned int flags) + { + struct rand_data *entropy_collector; + ++ /* ++ * Requesting disabling and forcing of internal timer ++ * makes no sense. ++ */ ++ if ((flags & JENT_DISABLE_INTERNAL_TIMER) && ++ (flags & JENT_FORCE_INTERNAL_TIMER)) ++ return NULL; ++ ++ /* Force the self test to be run */ ++ if (!jent_selftest_run && jent_entropy_init_ex(osr, flags)) ++ return NULL; ++ ++ /* ++ * If the initial test code concludes to force the internal timer ++ * and the user requests it not to be used, do not allocate ++ * the Jitter RNG instance. ++ */ ++ if (jent_notime_forced() && (flags & JENT_DISABLE_INTERNAL_TIMER)) ++ return NULL; ++ + entropy_collector = jent_zalloc(sizeof(struct rand_data)); + if (NULL == entropy_collector) + return NULL; + + if (!(flags & JENT_DISABLE_MEMORY_ACCESS)) { +- /* Allocate memory for adding variations based on memory +- * access ++ uint32_t memsize = jent_memsize(flags); ++ ++ entropy_collector->mem = _gcry_calloc (1, memsize); ++ ++#ifdef JENT_RANDOM_MEMACCESS ++ /* ++ * Transform the size into a mask - it is assumed that size is ++ * a power of 2. + */ +- entropy_collector->mem = +- (unsigned char *)jent_zalloc(JENT_MEMORY_SIZE); +- if (NULL == entropy_collector->mem) { +- jent_zfree(entropy_collector, sizeof(struct rand_data)); +- return NULL; +- } +- entropy_collector->memblocksize = JENT_MEMORY_BLOCKSIZE; ++ entropy_collector->memmask = memsize - 1; ++#else /* JENT_RANDOM_MEMACCESS */ ++ entropy_collector->memblocksize = memsize / JENT_MEMORY_BLOCKS; + entropy_collector->memblocks = JENT_MEMORY_BLOCKS; ++ ++ /* sanity check */ ++ if (entropy_collector->memblocksize * ++ entropy_collector->memblocks != memsize) ++ goto err; ++ ++#endif /* JENT_RANDOM_MEMACCESS */ ++ ++ if (entropy_collector->mem == NULL) ++ goto err; + entropy_collector->memaccessloops = JENT_MEMORY_ACCESSLOOPS; + } + + /* verify and set the oversampling rate */ +- if (0 == osr) +- osr = 1; /* minimum sampling rate is 1 */ ++ if (osr < JENT_MIN_OSR) ++ osr = JENT_MIN_OSR; + entropy_collector->osr = osr; ++ entropy_collector->flags = flags; + +- entropy_collector->stir = 1; +- if (flags & JENT_DISABLE_STIR) +- entropy_collector->stir = 0; +- if (flags & JENT_DISABLE_UNBIAS) +- entropy_collector->disable_unbias = 1; ++ if (jent_fips_enabled() || (flags & JENT_FORCE_FIPS)) ++ entropy_collector->fips_enabled = 1; + +- /* fill the data pad with non-zero values */ +- jent_gen_entropy(entropy_collector); ++ /* Initialize the APT */ ++ jent_apt_init(entropy_collector, osr); ++ ++ /* Initialize the Lag Predictor Test */ ++ jent_lag_init(entropy_collector, osr); ++ ++ /* Was jent_entropy_init run (establishing the common GCD)? */ ++ if (jent_gcd_get(&entropy_collector->jent_common_timer_gcd)) { ++ /* ++ * It was not. This should probably be an error, but this ++ * behavior breaks the test code. Set the gcd to a value that ++ * won't hurt anything. ++ */ ++ entropy_collector->jent_common_timer_gcd = 1; ++ } ++ ++ /* ++ * Use timer-less noise source - note, OSR must be set in ++ * entropy_collector! ++ */ ++ if (!(flags & JENT_DISABLE_INTERNAL_TIMER)) { ++ if (jent_notime_enable(entropy_collector, flags)) ++ goto err; ++ } + + return entropy_collector; ++ ++err: ++ if (entropy_collector->mem != NULL) ++ jent_zfree(entropy_collector->mem, JENT_MEMORY_SIZE); ++ jent_zfree(entropy_collector, sizeof(struct rand_data)); ++ return NULL; ++} ++ ++static struct rand_data *_jent_entropy_collector_alloc(unsigned int osr, ++ unsigned int flags) ++{ ++ struct rand_data *ec = jent_entropy_collector_alloc_internal(osr, ++ flags); ++ ++ if (!ec) ++ return ec; ++ ++ /* fill the data pad with non-zero values */ ++ if (jent_notime_settick(ec)) { ++ jent_entropy_collector_free(ec); ++ return NULL; ++ } ++ jent_random_data(ec); ++ jent_notime_unsettick(ec); ++ ++ return ec; ++} ++ ++JENT_PRIVATE_STATIC ++struct rand_data *jent_entropy_collector_alloc(unsigned int osr, ++ unsigned int flags) ++{ ++ struct rand_data *ec = _jent_entropy_collector_alloc(osr, flags); ++ ++ /* Remember that the caller provided a maximum size flag */ ++ if (ec) ++ ec->max_mem_set = !!JENT_FLAGS_TO_MAX_MEMSIZE(flags); ++ ++ return ec; + } + + JENT_PRIVATE_STATIC + void jent_entropy_collector_free(struct rand_data *entropy_collector) + { +- if (NULL != entropy_collector) { +- if (NULL != entropy_collector->mem) { +- jent_zfree(entropy_collector->mem, JENT_MEMORY_SIZE); ++ if (entropy_collector != NULL) { ++ jent_notime_disable(entropy_collector); ++ if (entropy_collector->mem != NULL) { ++ jent_zfree(entropy_collector->mem, ++ jent_memsize(entropy_collector->flags)); + entropy_collector->mem = NULL; + } + jent_zfree(entropy_collector, sizeof(struct rand_data)); + } + } + +-JENT_PRIVATE_STATIC +-int jent_entropy_init(void) ++int jent_time_entropy_init(unsigned int osr, unsigned int flags) + { +- int i; +- uint64_t delta_sum = 0; +- uint64_t old_delta = 0; +- int time_backwards = 0; +- int count_mod = 0; +- int count_stuck = 0; +- struct rand_data ec; ++ struct rand_data *ec; ++ uint64_t *delta_history; ++ int i, time_backwards = 0, count_stuck = 0, ret = 0; ++ unsigned int health_test_result; + +- memset(&ec, 0, sizeof(ec)); ++ delta_history = jent_gcd_init(JENT_POWERUP_TESTLOOPCOUNT); ++ if (!delta_history) ++ return EMEM; ++ ++ if (flags & JENT_FORCE_INTERNAL_TIMER) ++ jent_notime_force(); ++ else ++ flags |= JENT_DISABLE_INTERNAL_TIMER; ++ ++ /* ++ * If the start-up health tests (including the APT and RCT) are not ++ * run, then the entropy source is not 90B compliant. We could test if ++ * fips_enabled should be set using the jent_fips_enabled() function, ++ * but this can be overridden using the JENT_FORCE_FIPS flag, which ++ * isn't passed in yet. It is better to run the tests on the small ++ * amount of data that we have, which should not fail unless things ++ * are really bad. ++ */ ++ flags |= JENT_FORCE_FIPS; ++ ec = jent_entropy_collector_alloc_internal(osr, flags); ++ if (!ec) { ++ ret = EMEM; ++ goto out; ++ } ++ ++ if (jent_notime_settick(ec)) { ++ ret = EMEM; ++ goto out; ++ } ++ ++ /* To initialize the prior time. */ ++ jent_measure_jitter(ec, 0, NULL); + + /* We could perform statistical tests here, but the problem is + * that we only have a few loop counts to do testing. These +- * loop counts may show some slight skew and we produce +- * false positives. +- * +- * Moreover, only old systems show potentially problematic +- * jitter entropy that could potentially be caught here. But +- * the RNG is intended for hardware that is available or widely +- * used, but not old systems that are long out of favor. Thus, +- * no statistical tests. ++ * loop counts may show some slight skew leading to false positives. + */ + + /* +@@ -664,38 +572,31 @@ int jent_entropy_init(void) + * following sanity checks verify that we have a high-resolution + * timer. + */ +- /* +- * TESTLOOPCOUNT needs some loops to identify edge systems. 100 is +- * definitely too little. +- */ +-#define TESTLOOPCOUNT 300 + #define CLEARCACHE 100 +- for (i = 0; (TESTLOOPCOUNT + CLEARCACHE) > i; i++) { +- uint64_t time = 0; +- uint64_t time2 = 0; +- uint64_t delta = 0; +- unsigned int lowdelta = 0; +- int stuck; ++ for (i = -CLEARCACHE; i < JENT_POWERUP_TESTLOOPCOUNT; i++) { ++ uint64_t start_time = 0, end_time = 0, delta = 0; ++ unsigned int stuck; + + /* Invoke core entropy collection logic */ +- jent_get_nstime(&time); +- ec.prev_time = time; +- jent_lfsr_time(&ec, time, 0); +- jent_get_nstime(&time2); ++ stuck = jent_measure_jitter(ec, 0, &delta); ++ end_time = ec->prev_time; ++ start_time = ec->prev_time - delta; + + /* test whether timer works */ +- if (!time || !time2) +- return ENOTIME; +- delta = time2 - time; ++ if (!start_time || !end_time) { ++ ret = ENOTIME; ++ goto out; ++ } ++ + /* + * test whether timer is fine grained enough to provide + * delta even when called shortly after each other -- this + * implies that we also have a high resolution timer + */ +- if (!delta) +- return ECOARSETIME; +- +- stuck = jent_stuck(&ec, delta); ++ if (!delta || (end_time == start_time)) { ++ ret = ECOARSETIME; ++ goto out; ++ } + + /* + * up to here we did not modify any variable that will be +@@ -704,32 +605,18 @@ int jent_entropy_init(void) + * etc. with the goal to clear it to get the worst case + * measurements. + */ +- if (CLEARCACHE > i) ++ if (i < 0) + continue; + + if (stuck) + count_stuck++; + + /* test whether we have an increasing timer */ +- if (!(time2 > time)) ++ if (!(end_time > start_time)) + time_backwards++; + +- /* use 32 bit value to ensure compilation on 32 bit arches */ +- lowdelta = time2 - time; +- if (!(lowdelta % 100)) +- count_mod++; +- +- /* +- * ensure that we have a varying delta timer which is necessary +- * for the calculation of entropy -- perform this check +- * only after the first loop is executed as we need to prime +- * the old_data value +- */ +- if (delta > old_delta) +- delta_sum += (delta - old_delta); +- else +- delta_sum += (old_delta - delta); +- old_delta = delta; ++ /* Watch for common adjacent GCD values */ ++ jent_gcd_add_value(delta_history, delta, i); + } + + /* +@@ -739,55 +626,109 @@ int jent_entropy_init(void) + * should not fail. The value of 3 should cover the NTP case being + * performed during our test run. + */ +- if (3 < time_backwards) +- return ENOMONOTONIC; ++ if (time_backwards > 3) { ++ ret = ENOMONOTONIC; ++ goto out; ++ } + +- /* +- * Variations of deltas of time must on average be larger +- * than 1 to ensure the entropy estimation +- * implied with 1 is preserved +- */ +- if ((delta_sum) <= 1) +- return EMINVARVAR; ++ /* First, did we encounter a health test failure? */ ++ if ((health_test_result = jent_health_failure(ec))) { ++ ret = (health_test_result & JENT_RCT_FAILURE) ? ERCT : EHEALTH; ++ goto out; ++ } + +- /* +- * Ensure that we have variations in the time stamp below 10 for at least +- * 10% of all checks -- on some platforms, the counter increments in +- * multiples of 100, but not always +- */ +- if ((TESTLOOPCOUNT/10 * 9) < count_mod) +- return ECOARSETIME; ++ ret = jent_gcd_analyze(delta_history, JENT_POWERUP_TESTLOOPCOUNT); ++ if (ret) ++ goto out; + + /* + * If we have more than 90% stuck results, then this Jitter RNG is + * likely to not work well. + */ +- if (JENT_STUCK_INIT_THRES(TESTLOOPCOUNT) < count_stuck) +- return ESTUCK; ++ if (JENT_STUCK_INIT_THRES(JENT_POWERUP_TESTLOOPCOUNT) < count_stuck) ++ ret = ESTUCK; ++ ++out: ++ jent_gcd_fini(delta_history, JENT_POWERUP_TESTLOOPCOUNT); ++ ++ if ((flags & JENT_FORCE_INTERNAL_TIMER) && ec) ++ jent_notime_unsettick(ec); ++ ++ jent_entropy_collector_free(ec); + +- return 0; ++ return ret; + } + +-/*************************************************************************** +- * Statistical test logic not compiled for regular operation +- ***************************************************************************/ ++static inline int jent_entropy_init_common_pre(void) ++{ ++ int ret; ++ ++ jent_notime_block_switch(); ++ ++ if (sha3_tester()) ++ return EHASH; ++ ++ ret = jent_gcd_selftest(); ++ ++ jent_selftest_run = 1; ++ ++ return ret; ++} ++ ++static inline int jent_entropy_init_common_post(int ret) ++{ ++ /* Unmark the execution of the self tests if they failed. */ ++ if (ret) ++ jent_selftest_run = 0; ++ ++ return ret; ++} ++ ++JENT_PRIVATE_STATIC ++int jent_entropy_init(void) ++{ ++ int ret = jent_entropy_init_common_pre(); ++ ++ if (ret) ++ return ret; ++ ++ ret = jent_time_entropy_init(0, JENT_DISABLE_INTERNAL_TIMER); ++ ++#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER ++ if (ret) ++ ret = jent_time_entropy_init(0, JENT_FORCE_INTERNAL_TIMER); ++#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ ++ ++ return jent_entropy_init_common_post(ret); ++} + +-#ifdef CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT +-/* +- * Statistical test: return the time duration for the folding operation. If min +- * is set, perform the given number of LFSR ops. Otherwise, allow the +- * loop count shuffling to define the number of LFSR ops. +- */ + JENT_PRIVATE_STATIC +-uint64_t jent_lfsr_var_stat(struct rand_data *ec, unsigned int min) ++int jent_entropy_init_ex(unsigned int osr, unsigned int flags) + { +- uint64_t time = 0; +- uint64_t time2 = 0; ++ int ret = jent_entropy_init_common_pre(); ++ ++ if (ret) ++ return ret; ++ ++ /* Test without internal timer unless caller does not want it */ ++ if (!(flags & JENT_FORCE_INTERNAL_TIMER)) ++ ret = jent_time_entropy_init(osr, ++ flags | JENT_DISABLE_INTERNAL_TIMER); + +- jent_get_nstime(&time); +- jent_memaccess(ec, min); +- jent_lfsr_time(ec, time, min); +- jent_get_nstime(&time2); +- return ((time2 - time)); ++#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER ++ /* Test with internal timer unless caller does not want it */ ++ if (ret && !(flags & JENT_DISABLE_INTERNAL_TIMER)) ++ ret = jent_time_entropy_init(osr, ++ flags | JENT_FORCE_INTERNAL_TIMER); ++#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ ++ ++ return jent_entropy_init_common_post(ret); + } +-#endif /* CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT */ ++ ++#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER ++JENT_PRIVATE_STATIC ++int jent_entropy_switch_notime_impl(struct jent_notime_thread *new_thread) ++{ ++ return jent_notime_switch(new_thread); ++} ++#endif +Index: libgcrypt-1.9.4/random/jitterentropy-base.h +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-base.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * License: see LICENSE file in root directory ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF ++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT ++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ */ ++ ++#ifndef JITTERENTROPY_BASE_H ++#define JITTERENTROPY_BASE_H ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++ ++int jent_time_entropy_init(unsigned int osr, unsigned int flags); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* JITTERENTROPY_BASE_H */ +Index: libgcrypt-1.9.4/random/jitterentropy-base-user.h +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-base-user.h ++++ libgcrypt-1.9.4/random/jitterentropy-base-user.h +@@ -39,6 +39,9 @@ + * DAMAGE. + */ + ++#include ++#include ++ + #ifndef GCRYPT_JITTERENTROPY_BASE_USER_H + #define GCRYPT_JITTERENTROPY_BASE_USER_H + +@@ -131,4 +134,174 @@ jent_fips_enabled(void) + } + + ++static inline void jent_memset_secure(void *s, size_t n) ++{ ++ wipememory (s, n); ++} ++ ++static inline long jent_ncpu(void) ++{ ++#ifdef _POSIX_SOURCE ++ long ncpu = sysconf(_SC_NPROCESSORS_ONLN); ++ ++ if (ncpu == -1) ++ return -errno; ++ ++ if (ncpu == 0) ++ return -EFAULT; ++ ++ return ncpu; ++#else ++ return 1; ++#endif ++} ++ ++#ifdef __linux__ ++ ++# if defined(_SC_LEVEL1_DCACHE_SIZE) && \ ++ defined(_SC_LEVEL2_CACHE_SIZE) && \ ++ defined(_SC_LEVEL3_CACHE_SIZE) ++ ++static inline void jent_get_cachesize(long *l1, long *l2, long *l3) ++{ ++ *l1 = sysconf(_SC_LEVEL1_DCACHE_SIZE); ++ *l2 = sysconf(_SC_LEVEL2_CACHE_SIZE); ++ *l3 = sysconf(_SC_LEVEL3_CACHE_SIZE); ++} ++ ++# else ++ ++static inline void jent_get_cachesize(long *l1, long *l2, long *l3) ++{ ++#define JENT_SYSFS_CACHE_DIR "/sys/devices/system/cpu/cpu0/cache" ++ long val; ++ unsigned int i; ++ char buf[10], file[50]; ++ int fd = 0; ++ ++ /* Iterate over all caches */ ++ for (i = 0; i < 4; i++) { ++ unsigned int shift = 0; ++ char *ext; ++ ++ /* ++ * Check the cache type - we are only interested in Unified ++ * and Data caches. ++ */ ++ memset(buf, 0, sizeof(buf)); ++ snprintf(file, sizeof(file), "%s/index%u/type", ++ JENT_SYSFS_CACHE_DIR, i); ++ fd = open(file, O_RDONLY); ++ if (fd < 0) ++ continue; ++ while (read(fd, buf, sizeof(buf)) < 0 && errno == EINTR); ++ close(fd); ++ buf[sizeof(buf) - 1] = '\0'; ++ ++ if (strncmp(buf, "Data", 4) && strncmp(buf, "Unified", 7)) ++ continue; ++ ++ /* Get size of cache */ ++ memset(buf, 0, sizeof(buf)); ++ snprintf(file, sizeof(file), "%s/index%u/size", ++ JENT_SYSFS_CACHE_DIR, i); ++ ++ fd = open(file, O_RDONLY); ++ if (fd < 0) ++ continue; ++ while (read(fd, buf, sizeof(buf)) < 0 && errno == EINTR); ++ close(fd); ++ buf[sizeof(buf) - 1] = '\0'; ++ ++ ext = strstr(buf, "K"); ++ if (ext) { ++ shift = 10; ++ ext = '\0'; ++ } else { ++ ext = strstr(buf, "M"); ++ if (ext) { ++ shift = 20; ++ ext = '\0'; ++ } ++ } ++ ++ val = strtol(buf, NULL, 10); ++ if (val == LONG_MAX) ++ continue; ++ val <<= shift; ++ ++ if (!*l1) ++ *l1 = val; ++ else if (!*l2) ++ *l2 = val; ++ else { ++ *l3 = val; ++ break; ++ } ++ } ++#undef JENT_SYSFS_CACHE_DIR ++} ++ ++# endif ++ ++static inline uint32_t jent_cache_size_roundup(void) ++{ ++ static int checked = 0; ++ static uint32_t cache_size = 0; ++ ++ if (!checked) { ++ long l1 = 0, l2 = 0, l3 = 0; ++ ++ jent_get_cachesize(&l1, &l2, &l3); ++ checked = 1; ++ ++ /* Cache size reported by system */ ++ if (l1 > 0) ++ cache_size += (uint32_t)l1; ++ if (l2 > 0) ++ cache_size += (uint32_t)l2; ++ if (l3 > 0) ++ cache_size += (uint32_t)l3; ++ ++ /* ++ * Force the output_size to be of the form ++ * (bounding_power_of_2 - 1). ++ */ ++ cache_size |= (cache_size >> 1); ++ cache_size |= (cache_size >> 2); ++ cache_size |= (cache_size >> 4); ++ cache_size |= (cache_size >> 8); ++ cache_size |= (cache_size >> 16); ++ ++ if (cache_size == 0) ++ return 0; ++ ++ /* ++ * Make the output_size the smallest power of 2 strictly ++ * greater than cache_size. ++ */ ++ cache_size++; ++ } ++ ++ return cache_size; ++} ++ ++#else /* __linux__ */ ++ ++static inline uint32_t jent_cache_size_roundup(void) ++{ ++ return 0; ++} ++ ++#endif /* __linux__ */ ++ ++#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER ++#include ++ ++static inline void jent_yield(void) ++{ ++ sched_yield(); ++} ++#endif ++ + #endif /* GCRYPT_JITTERENTROPY_BASE_USER_H */ +Index: libgcrypt-1.9.4/random/jitterentropy-gcd.c +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-gcd.c +@@ -0,0 +1,188 @@ ++/* Jitter RNG: GCD health test ++ * ++ * Copyright (C) 2021, Joshua E. Hill ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * License: see LICENSE file in root directory ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF ++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT ++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ */ ++ ++#include "jitterentropy.h" ++#include "jitterentropy-gcd.h" ++ ++/* The common divisor for all timestamp deltas */ ++static uint64_t jent_common_timer_gcd = 0; ++ ++static inline int jent_gcd_tested(void) ++{ ++ return (jent_common_timer_gcd != 0); ++} ++ ++/* A straight forward implementation of the Euclidean algorithm for GCD. */ ++static inline uint64_t jent_gcd64(uint64_t a, uint64_t b) ++{ ++ /* Make a greater a than or equal b. */ ++ if (a < b) { ++ uint64_t c = a; ++ a = b; ++ b = c; ++ } ++ ++ /* Now perform the standard inner-loop for this algorithm.*/ ++ while (b != 0) { ++ uint64_t r; ++ ++ r = a % b; ++ ++ a = b; ++ b = r; ++ } ++ ++ return a; ++} ++ ++static int jent_gcd_analyze_internal(uint64_t *delta_history, size_t nelem, ++ uint64_t *running_gcd_out, ++ uint64_t *delta_sum_out) ++{ ++ uint64_t running_gcd, delta_sum = 0; ++ size_t i; ++ ++ if (!delta_history) ++ return -EAGAIN; ++ ++ running_gcd = delta_history[0]; ++ ++ /* Now perform the analysis on the accumulated delta data. */ ++ for (i = 1; i < nelem; i++) { ++ /* ++ * ensure that we have a varying delta timer which is necessary ++ * for the calculation of entropy -- perform this check ++ * only after the first loop is executed as we need to prime ++ * the old_data value ++ */ ++ if (delta_history[i] >= delta_history[i - 1]) ++ delta_sum += delta_history[i] - delta_history[i - 1]; ++ else ++ delta_sum += delta_history[i - 1] - delta_history[i]; ++ ++ /* ++ * This calculates the gcd of all the delta values. that is ++ * gcd(delta_1, delta_2, ..., delta_nelem) ++ ++ * Some timers increment by a fixed (non-1) amount each step. ++ * This code checks for such increments, and allows the library ++ * to output the number of such changes have occurred. ++ */ ++ running_gcd = jent_gcd64(delta_history[i], running_gcd); ++ } ++ ++ *running_gcd_out = running_gcd; ++ *delta_sum_out = delta_sum; ++ ++ return 0; ++} ++ ++int jent_gcd_analyze(uint64_t *delta_history, size_t nelem) ++{ ++ uint64_t running_gcd, delta_sum; ++ int ret = jent_gcd_analyze_internal(delta_history, nelem, &running_gcd, ++ &delta_sum); ++ ++ if (ret == -EAGAIN) ++ return 0; ++ ++ /* ++ * Variations of deltas of time must on average be larger than 1 to ++ * ensure the entropy estimation implied with 1 is preserved. ++ */ ++ if (delta_sum <= nelem - 1) { ++ ret = EMINVARVAR; ++ goto out; ++ } ++ ++ /* ++ * Ensure that we have variations in the time stamp below 100 for at ++ * least 10% of all checks -- on some platforms, the counter increments ++ * in multiples of 100, but not always ++ */ ++ if (running_gcd >= 100) { ++ ret = ECOARSETIME; ++ goto out; ++ } ++ ++ /* Adjust all deltas by the observed (small) common factor. */ ++ if (!jent_gcd_tested()) ++ jent_common_timer_gcd = running_gcd; ++ ++out: ++ return ret; ++} ++ ++uint64_t *jent_gcd_init(size_t nelem) ++{ ++ uint64_t *delta_history; ++ ++ delta_history = jent_zalloc(nelem * sizeof(uint64_t)); ++ if (!delta_history) ++ return NULL; ++ ++ return delta_history; ++} ++ ++void jent_gcd_fini(uint64_t *delta_history, size_t nelem) ++{ ++ if (delta_history) ++ jent_zfree(delta_history, ++ (unsigned int)(nelem * sizeof(uint64_t))); ++} ++ ++int jent_gcd_get(uint64_t *value) ++{ ++ if (!jent_gcd_tested()) ++ return 1; ++ ++ *value = jent_common_timer_gcd; ++ return 0; ++} ++ ++int jent_gcd_selftest(void) ++{ ++#define JENT_GCD_SELFTEST_ELEM 10 ++#define JENT_GCD_SELFTEST_EXP 3ULL ++ uint64_t *gcd = jent_gcd_init(JENT_GCD_SELFTEST_ELEM); ++ uint64_t running_gcd, delta_sum; ++ unsigned int i; ++ int ret = EGCD; ++ ++ if (!gcd) ++ return EMEM; ++ ++ for (i = 0; i < JENT_GCD_SELFTEST_ELEM; i++) ++ jent_gcd_add_value(gcd, i * JENT_GCD_SELFTEST_EXP, i); ++ ++ if (jent_gcd_analyze_internal(gcd, JENT_GCD_SELFTEST_ELEM, ++ &running_gcd, &delta_sum)) ++ goto out; ++ ++ if (running_gcd != JENT_GCD_SELFTEST_EXP) ++ goto out; ++ ++ ret = 0; ++ ++out: ++ jent_gcd_fini(gcd, JENT_GCD_SELFTEST_ELEM); ++ return ret; ++} +Index: libgcrypt-1.9.4/random/jitterentropy-gcd.h +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-gcd.h +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * License: see LICENSE file in root directory ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF ++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT ++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ */ ++ ++#ifndef JITTERENTROPY_GCD_H ++#define JITTERENTROPY_GCD_H ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++ ++int jent_gcd_analyze(uint64_t *delta_history, size_t nelem); ++uint64_t *jent_gcd_init(size_t nelem); ++void jent_gcd_fini(uint64_t *delta_history, size_t nelem); ++int jent_gcd_get(uint64_t *value); ++int jent_gcd_selftest(void); ++ ++/* Watch for common adjacent GCD values */ ++#define jent_gcd_add_value(delta_history, delta, idx) \ ++ delta_history[idx] = delta; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* JITTERENTROPY_GCD_H */ +Index: libgcrypt-1.9.4/random/jitterentropy.h +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy.h ++++ libgcrypt-1.9.4/random/jitterentropy.h +@@ -42,11 +42,122 @@ + #ifndef _JITTERENTROPY_H + #define _JITTERENTROPY_H + +-#ifdef __KERNEL__ +-#include "jitterentropy-base-kernel.h" +-#else ++/*************************************************************************** ++ * Jitter RNG Configuration Section ++ * ++ * You may alter the following options ++ ***************************************************************************/ ++ ++/* ++ * Enable timer-less timer support ++ * ++ * In case the hardware is identified to not provide a high-resolution time ++ * stamp, this option enables a built-in high-resolution time stamp mechanism. ++ * ++ * The timer-less noise source is based on threads. This noise source requires ++ * the linking with the POSIX threads library. I.e. the executing environment ++ * must offer POSIX threads. If this option is disabled, no linking ++ * with the POSIX threads library is needed. ++ */ ++#undef JENT_CONF_ENABLE_INTERNAL_TIMER ++ ++/* ++ * Disable the loop shuffle operation ++ * ++ * The shuffle operation enlarges the timing of the conditioning function ++ * by a variable length defined by the LSB of a time stamp. Some mathematicians ++ * are concerned that this pseudo-random selection of the loop iteration count ++ * may create some form of dependency between the different loop counts ++ * and the associated time duration of the conditioning function. It ++ * also complicates entropy assessment because it effectively combines a bunch ++ * of shifted/scaled copies the same distribution and masks failures from the ++ * health testing. ++ * ++ * By enabling this flag, the loop shuffle operation is disabled and ++ * the entropy collection operates in a way that honor the concerns. ++ * ++ * By enabling this flag, the time of collecting entropy may be enlarged. ++ */ ++#define JENT_CONF_DISABLE_LOOP_SHUFFLE ++ ++/* ++ * Shall the LAG predictor health test be enabled? ++ */ ++#define JENT_HEALTH_LAG_PREDICTOR ++ ++/* ++ * Shall the jent_memaccess use a (statistically) random selection for the ++ * memory to update? ++ */ ++#define JENT_RANDOM_MEMACCESS ++ ++/*************************************************************************** ++ * Jitter RNG State Definition Section ++ ***************************************************************************/ ++ + #include "jitterentropy-base-user.h" +-#endif /* __KERNEL__ */ ++ ++#define SHA3_256_SIZE_DIGEST_BITS 256 ++#define SHA3_256_SIZE_DIGEST (SHA3_256_SIZE_DIGEST_BITS >> 3) ++ ++/* ++ * The output 256 bits can receive more than 256 bits of min entropy, ++ * of course, but the 256-bit output of SHA3-256(M) can only asymptotically ++ * approach 256 bits of min entropy, not attain that bound. Random maps will ++ * tend to have output collisions, which reduces the creditable output entropy ++ * (that is what SP 800-90B Section 3.1.5.1.2 attempts to bound). ++ * ++ * The value "64" is justified in Appendix A.4 of the current 90C draft, ++ * and aligns with NIST's in "epsilon" definition in this document, which is ++ * that a string can be considered "full entropy" if you can bound the min ++ * entropy in each bit of output to at least 1-epsilon, where epsilon is ++ * required to be <= 2^(-32). ++ */ ++#define ENTROPY_SAFETY_FACTOR 64 ++ ++/** ++ * Function pointer data structure to register an external thread handler ++ * used for the timer-less mode of the Jitter RNG. ++ * ++ * The external caller provides these function pointers to handle the ++ * management of the timer thread that is spawned by the Jitter RNG. ++ * ++ * @var jent_notime_init This function is intended to initialze the threading ++ * support. All data that is required by the threading code must be ++ * held in the data structure @param ctx. The Jitter RNG maintains the ++ * data structure and uses it for every invocation of the following calls. ++ * ++ * @var jent_notime_fini This function shall terminate the threading support. ++ * The function must dispose of all memory and resources used for the ++ * threading operation. It must also dispose of the @param ctx memory. ++ * ++ * @var jent_notime_start This function is called when the Jitter RNG wants ++ * to start a thread. Besides providing a pointer to the @param ctx ++ * allocated during initialization time, the Jitter RNG provides a ++ * pointer to the function the thread shall execute and the argument ++ * the function shall be invoked with. These two parameters have the ++ * same purpose as the trailing two parameters of pthread_create(3). ++ * ++ * @var jent_notime_stop This function is invoked by the Jitter RNG when the ++ * thread should be stopped. Note, the Jitter RNG intends to start/stop ++ * the thread frequently. ++ * ++ * An example implementation is found in the Jitter RNG itself with its ++ * default thread handler of jent_notime_thread_builtin. ++ * ++ * If the caller wants to register its own thread handler, it must be done ++ * with the API call jent_entropy_switch_notime_impl as the first ++ * call to interact with the Jitter RNG, even before jent_entropy_init. ++ * After jent_entropy_init is called, changing of the threading implementation ++ * is not allowed. ++ */ ++struct jent_notime_thread { ++ int (*jent_notime_init)(void **ctx); ++ void (*jent_notime_fini)(void *ctx); ++ int (*jent_notime_start)(void *ctx, ++ void *(*start_routine) (void *), void *arg); ++ void (*jent_notime_stop)(void *ctx); ++}; + + /* The entropy pool */ + struct rand_data +@@ -55,35 +166,179 @@ struct rand_data + * of the RNG are marked as SENSITIVE. A user must not + * access that information while the RNG executes its loops to + * calculate the next random value. */ +- uint64_t data; /* SENSITIVE Actual random number */ +- uint64_t old_data; /* SENSITIVE Previous random number */ +- uint64_t prev_time; /* SENSITIVE Previous time stamp */ +-#define DATA_SIZE_BITS ((sizeof(uint64_t)) * 8) +- uint64_t last_delta; /* SENSITIVE stuck test */ +- int64_t last_delta2; /* SENSITIVE stuck test */ +- unsigned int osr; /* Oversample rate */ +- int fips_enabled; /* FIPS enabled? */ +- unsigned int stir:1; /* Post-processing stirring */ +- unsigned int disable_unbias:1; /* Deactivate Von-Neuman unbias */ +-#define JENT_MEMORY_BLOCKS 64 +-#define JENT_MEMORY_BLOCKSIZE 32 ++ uint8_t data[SHA3_256_SIZE_DIGEST]; /* SENSITIVE Actual random number */ ++ uint64_t prev_time; /* SENSITIVE Previous time stamp */ ++#define DATA_SIZE_BITS (SHA3_256_SIZE_DIGEST_BITS) ++ ++#ifndef JENT_HEALTH_LAG_PREDICTOR ++ uint64_t last_delta; /* SENSITIVE stuck test */ ++ uint64_t last_delta2; /* SENSITIVE stuck test */ ++#endif /* JENT_HEALTH_LAG_PREDICTOR */ ++ ++ unsigned int flags; /* Flags used to initialize */ ++ unsigned int osr; /* Oversampling rate */ ++ ++#ifdef JENT_RANDOM_MEMACCESS ++ /* The step size should be larger than the cacheline size. */ ++# ifndef JENT_MEMORY_BITS ++# define JENT_MEMORY_BITS 17 ++# endif ++# ifndef JENT_MEMORY_SIZE ++# define JENT_MEMORY_SIZE (UINT32_C(1)<> JENT_FLAGS_TO_MEMSIZE_SHIFT) ++#define JENT_MAX_MEMSIZE_TO_FLAGS(val) (val << JENT_FLAGS_TO_MEMSIZE_SHIFT) ++#define JENT_MAX_MEMSIZE_32kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 1)) ++#define JENT_MAX_MEMSIZE_64kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 2)) ++#define JENT_MAX_MEMSIZE_128kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 3)) ++#define JENT_MAX_MEMSIZE_256kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 4)) ++#define JENT_MAX_MEMSIZE_512kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 5)) ++#define JENT_MAX_MEMSIZE_1MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 6)) ++#define JENT_MAX_MEMSIZE_2MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 7)) ++#define JENT_MAX_MEMSIZE_4MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 8)) ++#define JENT_MAX_MEMSIZE_8MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 9)) ++#define JENT_MAX_MEMSIZE_16MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(10)) ++#define JENT_MAX_MEMSIZE_32MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(11)) ++#define JENT_MAX_MEMSIZE_64MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(12)) ++#define JENT_MAX_MEMSIZE_128MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(13)) ++#define JENT_MAX_MEMSIZE_256MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(14)) ++#define JENT_MAX_MEMSIZE_512MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(15)) ++#define JENT_MAX_MEMSIZE_MAX JENT_MAX_MEMSIZE_512MB ++#define JENT_MAX_MEMSIZE_MASK JENT_MAX_MEMSIZE_MAX ++/* We start at 32kB -> offset is log2(32768) */ ++#define JENT_MAX_MEMSIZE_OFFSET 14 ++ ++#ifdef JENT_CONF_DISABLE_LOOP_SHUFFLE ++# define JENT_MIN_OSR 3 ++#else ++# define JENT_MIN_OSR 1 ++#endif ++ ++#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + + /* -- BEGIN Main interface functions -- */ + +@@ -94,19 +349,21 @@ struct rand_data + * + * It is allowed to change this value as required for the intended environment. + */ +-#define JENT_STUCK_INIT_THRES(x) (x/10 * 9) ++#define JENT_STUCK_INIT_THRES(x) ((x*9) / 10) + #endif + + #ifdef JENT_PRIVATE_COMPILE + # define JENT_PRIVATE_STATIC static + #else /* JENT_PRIVATE_COMPILE */ +-# define JENT_PRIVATE_STATIC ++# define JENT_PRIVATE_STATIC __attribute__((visibility("default"))) + #endif + + /* Number of low bits of the time value that we want to consider */ + /* get raw entropy */ + JENT_PRIVATE_STATIC + ssize_t jent_read_entropy(struct rand_data *ec, char *data, size_t len); ++JENT_PRIVATE_STATIC ++ssize_t jent_read_entropy_safe(struct rand_data **ec, char *data, size_t len); + /* initialize an instance of the entropy collector */ + JENT_PRIVATE_STATIC + struct rand_data *jent_entropy_collector_alloc(unsigned int osr, +@@ -118,13 +375,47 @@ void jent_entropy_collector_free(struct + /* initialization of entropy collector */ + JENT_PRIVATE_STATIC + int jent_entropy_init(void); ++JENT_PRIVATE_STATIC ++int jent_entropy_init_ex(unsigned int osr, unsigned int flags); + + /* return version number of core library */ + JENT_PRIVATE_STATIC + unsigned int jent_version(void); + ++#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER ++/* Set a different thread handling logic for the notimer support */ ++JENT_PRIVATE_STATIC ++int jent_entropy_switch_notime_impl(struct jent_notime_thread *new_thread); ++#endif ++ + /* -- END of Main interface functions -- */ + ++/* -- BEGIN timer-less threading support functions to prevent code dupes -- */ ++ ++struct jent_notime_ctx { ++#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER ++ pthread_attr_t notime_pthread_attr; /* pthreads library */ ++ pthread_t notime_thread_id; /* pthreads thread ID */ ++#endif ++}; ++ ++#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER ++ ++JENT_PRIVATE_STATIC ++int jent_notime_init(void **ctx); ++ ++JENT_PRIVATE_STATIC ++void jent_notime_fini(void *ctx); ++ ++#else ++ ++static inline int jent_notime_init(void **ctx) { (void)ctx; return 0; } ++static inline void jent_notime_fini(void *ctx) { (void)ctx; } ++ ++#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ ++ ++/* -- END timer-less threading support functions to prevent code dupes -- */ ++ + /* -- BEGIN error codes for init function -- */ + #define ENOTIME 1 /* Timer service not available */ + #define ECOARSETIME 2 /* Timer too coarse for RNG */ +@@ -135,6 +426,18 @@ unsigned int jent_version(void); + #define EMINVARVAR 6 /* Timer variations of variations is too small */ + #define EPROGERR 7 /* Programming error */ + #define ESTUCK 8 /* Too many stuck results during init. */ ++#define EHEALTH 9 /* Health test failed during initialization */ ++#define ERCT 10 /* RCT failed during initialization */ ++#define EHASH 11 /* Hash self test failed */ ++#define EMEM 12 /* Can't allocate memory for initialization */ ++#define EGCD 13 /* GCD self-test failed */ ++/* -- END error codes for init function -- */ ++ ++/* -- BEGIN error masks for health tests -- */ ++#define JENT_RCT_FAILURE 1 /* Failure in RCT health test. */ ++#define JENT_APT_FAILURE 2 /* Failure in APT health test. */ ++#define JENT_LAG_FAILURE 4 /* Failure in Lag predictor health test. */ ++/* -- END error masks for health tests -- */ + + /* -- BEGIN statistical test functions only complied with CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT -- */ + +Index: libgcrypt-1.9.4/random/jitterentropy-health.c +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-health.c +@@ -0,0 +1,438 @@ ++/* Jitter RNG: Health Tests ++ * ++ * Copyright (C) 2021, Joshua E. Hill ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * License: see LICENSE file in root directory ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF ++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT ++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ */ ++ ++#include "jitterentropy.h" ++#include "jitterentropy-health.h" ++ ++/*************************************************************************** ++ * Lag Predictor Test ++ * ++ * This test is a vendor-defined conditional test that is designed to detect ++ * a known failure mode where the result becomes mostly deterministic ++ * Note that (lag_observations & JENT_LAG_MASK) is the index where the next ++ * value provided will be stored. ++ ***************************************************************************/ ++ ++#ifdef JENT_HEALTH_LAG_PREDICTOR ++ ++/* ++ * These cutoffs are configured using an entropy estimate of 1/osr under an ++ * alpha=2^(-22) for a window size of 131072. The other health tests use ++ * alpha=2^-30, but operate on much smaller window sizes. This larger selection ++ * of alpha makes the behavior per-lag-window similar to the APT test. ++ * ++ * The global cutoffs are calculated using the ++ * InverseBinomialCDF(n=(JENT_LAG_WINDOW_SIZE-JENT_LAG_HISTORY_SIZE), p=2^(-1/osr); 1-alpha) ++ * The local cutoffs are somewhat more complicated. For background, see Feller's ++ * _Introduction to Probability Theory and It's Applications_ Vol. 1, ++ * Chapter 13, section 7 (in particular see equation 7.11, where x is a root ++ * of the denominator of equation 7.6). ++ * ++ * We'll proceed using the notation of SP 800-90B Section 6.3.8 (which is ++ * developed in Kelsey-McKay-Turan paper "Predictive Models for Min-entropy ++ * Estimation".) ++ * ++ * Here, we set p=2^(-1/osr), seeking a run of successful guesses (r) with ++ * probability of less than (1-alpha). That is, it is very very likely ++ * (probability 1-alpha) that there is _no_ run of length r in a block of size ++ * JENT_LAG_WINDOW_SIZE-JENT_LAG_HISTORY_SIZE. ++ * ++ * We have to iteratively look for an appropriate value for the cutoff r. ++ */ ++static const unsigned int jent_lag_global_cutoff_lookup[20] = ++ { 66443, 93504, 104761, 110875, 114707, 117330, 119237, 120686, 121823, ++ 122739, 123493, 124124, 124660, 125120, 125520, 125871, 126181, 126457, ++ 126704, 126926 }; ++static const unsigned int jent_lag_local_cutoff_lookup[20] = ++ { 38, 75, 111, 146, 181, 215, 250, 284, 318, 351, ++ 385, 419, 452, 485, 518, 551, 584, 617, 650, 683 }; ++ ++void jent_lag_init(struct rand_data *ec, unsigned int osr) ++{ ++ /* ++ * Establish the lag global and local cutoffs based on the presumed ++ * entropy rate of 1/osr. ++ */ ++ if (osr > ARRAY_SIZE(jent_lag_global_cutoff_lookup)) { ++ ec->lag_global_cutoff = ++ jent_lag_global_cutoff_lookup[ ++ ARRAY_SIZE(jent_lag_global_cutoff_lookup) - 1]; ++ } else { ++ ec->lag_global_cutoff = jent_lag_global_cutoff_lookup[osr - 1]; ++ } ++ ++ if (osr > ARRAY_SIZE(jent_lag_local_cutoff_lookup)) { ++ ec->lag_local_cutoff = ++ jent_lag_local_cutoff_lookup[ ++ ARRAY_SIZE(jent_lag_local_cutoff_lookup) - 1]; ++ } else { ++ ec->lag_local_cutoff = jent_lag_local_cutoff_lookup[osr - 1]; ++ } ++} ++ ++/** ++ * Reset the lag counters ++ * ++ * @ec [in] Reference to entropy collector ++ */ ++static void jent_lag_reset(struct rand_data *ec) ++{ ++ unsigned int i; ++ ++ /* Reset Lag counters */ ++ ec->lag_prediction_success_count = 0; ++ ec->lag_prediction_success_run = 0; ++ ec->lag_best_predictor = 0; //The first guess is basically arbitrary. ++ ec->lag_observations = 0; ++ ++ for (i = 0; i < JENT_LAG_HISTORY_SIZE; i++) { ++ ec->lag_scoreboard[i] = 0; ++ ec->lag_delta_history[i] = 0; ++ } ++} ++ ++/* ++ * A macro for accessing the history. Index 0 is the last observed symbol ++ * index 1 is the symbol observed two inputs ago, etc. ++ */ ++#define JENT_LAG_HISTORY(EC,LOC) \ ++ ((EC)->lag_delta_history[((EC)->lag_observations - (LOC) - 1) & \ ++ JENT_LAG_MASK]) ++ ++/** ++ * Insert a new entropy event into the lag predictor test ++ * ++ * @ec [in] Reference to entropy collector ++ * @current_delta [in] Current time delta ++ */ ++static void jent_lag_insert(struct rand_data *ec, uint64_t current_delta) ++{ ++ uint64_t prediction; ++ unsigned int i; ++ ++ /* Initialize the delta_history */ ++ if (ec->lag_observations < JENT_LAG_HISTORY_SIZE) { ++ ec->lag_delta_history[ec->lag_observations] = current_delta; ++ ec->lag_observations++; ++ return; ++ } ++ ++ /* ++ * The history is initialized. First make a guess and examine the ++ * results. ++ */ ++ prediction = JENT_LAG_HISTORY(ec, ec->lag_best_predictor); ++ ++ if (prediction == current_delta) { ++ /* The prediction was correct. */ ++ ec->lag_prediction_success_count++; ++ ec->lag_prediction_success_run++; ++ ++ if ((ec->lag_prediction_success_run >= ec->lag_local_cutoff) || ++ (ec->lag_prediction_success_count >= ec->lag_global_cutoff)) ++ ec->health_failure |= JENT_LAG_FAILURE; ++ } else { ++ /* The prediction wasn't correct. End any run of successes.*/ ++ ec->lag_prediction_success_run = 0; ++ } ++ ++ /* Now update the predictors using the current data. */ ++ for (i = 0; i < JENT_LAG_HISTORY_SIZE; i++) { ++ if (JENT_LAG_HISTORY(ec, i) == current_delta) { ++ /* ++ * The ith predictor (which guesses i + 1 symbols in ++ * the past) successfully guessed. ++ */ ++ ec->lag_scoreboard[i] ++; ++ ++ /* ++ * Keep track of the best predictor (tie goes to the ++ * shortest lag) ++ */ ++ if (ec->lag_scoreboard[i] > ++ ec->lag_scoreboard[ec->lag_best_predictor]) ++ ec->lag_best_predictor = i; ++ } ++ } ++ ++ /* ++ * Finally, update the lag_delta_history array with the newly input ++ * value. ++ */ ++ ec->lag_delta_history[(ec->lag_observations) & JENT_LAG_MASK] = ++ current_delta; ++ ec->lag_observations++; ++ ++ /* ++ * lag_best_predictor now is the index of the predictor with the largest ++ * number of correct guesses. ++ * This establishes our next guess. ++ */ ++ ++ /* Do we now need a new window? */ ++ if (ec->lag_observations >= JENT_LAG_WINDOW_SIZE) ++ jent_lag_reset(ec); ++} ++ ++static inline uint64_t jent_delta2(struct rand_data *ec, uint64_t current_delta) ++{ ++ /* Note that delta2_n = delta_n - delta_{n-1} */ ++ return jent_delta(JENT_LAG_HISTORY(ec, 0), current_delta); ++} ++ ++static inline uint64_t jent_delta3(struct rand_data *ec, uint64_t delta2) ++{ ++ /* ++ * Note that delta3_n = delta2_n - delta2_{n-1} ++ * = delta2_n - (delta_{n-1} - delta_{n-2}) ++ */ ++ return jent_delta(jent_delta(JENT_LAG_HISTORY(ec, 1), ++ JENT_LAG_HISTORY(ec, 0)), delta2); ++} ++ ++#else /* JENT_HEALTH_LAG_PREDICTOR */ ++ ++static inline void jent_lag_insert(struct rand_data *ec, uint64_t current_delta) ++{ ++ (void)ec; ++ (void)current_delta; ++} ++ ++static inline uint64_t jent_delta2(struct rand_data *ec, uint64_t current_delta) ++{ ++ uint64_t delta2 = jent_delta(ec->last_delta, current_delta); ++ ++ ec->last_delta = current_delta; ++ return delta2; ++} ++ ++static inline uint64_t jent_delta3(struct rand_data *ec, uint64_t delta2) ++{ ++ uint64_t delta3 = jent_delta(ec->last_delta2, delta2); ++ ++ ec->last_delta2 = delta2; ++ return delta3; ++} ++ ++#endif /* JENT_HEALTH_LAG_PREDICTOR */ ++ ++/*************************************************************************** ++ * Adaptive Proportion Test ++ * ++ * This test complies with SP800-90B section 4.4.2. ++ ***************************************************************************/ ++ ++/* ++ * See the SP 800-90B comment #10b for the corrected cutoff for the SP 800-90B ++ * APT. ++ * http://www.untruth.org/~josh/sp80090b/UL%20SP800-90B-final%20comments%20v1.9%2020191212.pdf ++ * In in the syntax of R, this is C = 2 + qbinom(1 - 2^(-30), 511, 2^(-1/osr)). ++ * (The original formula wasn't correct because the first symbol must ++ * necessarily have been observed, so there is no chance of observing 0 of these ++ * symbols.) ++ * ++ * For any value above 14, this yields the maximal allowable value of 512 ++ * (by FIPS 140-2 IG 7.19 Resolution # 16, we cannot choose a cutoff value that ++ * renders the test unable to fail). ++ */ ++static const unsigned int jent_apt_cutoff_lookup[15]= ++ { 325, 422, 459, 477, 488, 494, 499, 502, ++ 505, 507, 508, 509, 510, 511, 512 }; ++ ++void jent_apt_init(struct rand_data *ec, unsigned int osr) ++{ ++ /* ++ * Establish the apt_cutoff based on the presumed entropy rate of ++ * 1/osr. ++ */ ++ if (osr >= ARRAY_SIZE(jent_apt_cutoff_lookup)) { ++ ec->apt_cutoff = jent_apt_cutoff_lookup[ ++ ARRAY_SIZE(jent_apt_cutoff_lookup) - 1]; ++ } else { ++ ec->apt_cutoff = jent_apt_cutoff_lookup[osr - 1]; ++ } ++} ++ ++/** ++ * Reset the APT counter ++ * ++ * @ec [in] Reference to entropy collector ++ */ ++static void jent_apt_reset(struct rand_data *ec) ++{ ++ /* When reset, accept the _next_ value input as the new base. */ ++ ec->apt_base_set = 0; ++} ++ ++/** ++ * Insert a new entropy event into APT ++ * ++ * @ec [in] Reference to entropy collector ++ * @current_delta [in] Current time delta ++ */ ++static void jent_apt_insert(struct rand_data *ec, uint64_t current_delta) ++{ ++ /* Initialize the base reference */ ++ if (!ec->apt_base_set) { ++ ec->apt_base = current_delta; // APT Step 1 ++ ec->apt_base_set = 1; // APT Step 2 ++ ++ /* ++ * Reset APT counter ++ * Note that we've taken in the first symbol in the window. ++ */ ++ ec->apt_count = 1; // B = 1 ++ ec->apt_observations = 1; ++ ++ return; ++ } ++ ++ if (current_delta == ec->apt_base) { ++ ec->apt_count++; // B = B + 1 ++ ++ /* Note, ec->apt_count starts with one. */ ++ if (ec->apt_count >= ec->apt_cutoff) ++ ec->health_failure |= JENT_APT_FAILURE; ++ } ++ ++ ec->apt_observations++; ++ ++ /* Completed one window, the next symbol input will be new apt_base. */ ++ if (ec->apt_observations >= JENT_APT_WINDOW_SIZE) ++ jent_apt_reset(ec); // APT Step 4 ++} ++ ++/*************************************************************************** ++ * Stuck Test and its use as Repetition Count Test ++ * ++ * The Jitter RNG uses an enhanced version of the Repetition Count Test ++ * (RCT) specified in SP800-90B section 4.4.1. Instead of counting identical ++ * back-to-back values, the input to the RCT is the counting of the stuck ++ * values during the generation of one Jitter RNG output block. ++ * ++ * The RCT is applied with an alpha of 2^{-30} compliant to FIPS 140-2 IG 9.8. ++ * ++ * During the counting operation, the Jitter RNG always calculates the RCT ++ * cut-off value of C. If that value exceeds the allowed cut-off value, ++ * the Jitter RNG output block will be calculated completely but discarded at ++ * the end. The caller of the Jitter RNG is informed with an error code. ++ ***************************************************************************/ ++ ++/** ++ * Repetition Count Test as defined in SP800-90B section 4.4.1 ++ * ++ * @ec [in] Reference to entropy collector ++ * @stuck [in] Indicator whether the value is stuck ++ */ ++static void jent_rct_insert(struct rand_data *ec, int stuck) ++{ ++ /* ++ * If we have a count less than zero, a previous RCT round identified ++ * a failure. We will not overwrite it. ++ */ ++ if (ec->rct_count < 0) ++ return; ++ ++ if (stuck) { ++ ec->rct_count++; ++ ++ /* ++ * The cutoff value is based on the following consideration: ++ * alpha = 2^-30 as recommended in FIPS 140-2 IG 9.8. ++ * In addition, we require an entropy value H of 1/osr as this ++ * is the minimum entropy required to provide full entropy. ++ * Note, we collect (DATA_SIZE_BITS + ENTROPY_SAFETY_FACTOR)*osr ++ * deltas for inserting them into the entropy pool which should ++ * then have (close to) DATA_SIZE_BITS bits of entropy in the ++ * conditioned output. ++ * ++ * Note, ec->rct_count (which equals to value B in the pseudo ++ * code of SP800-90B section 4.4.1) starts with zero. Hence ++ * we need to subtract one from the cutoff value as calculated ++ * following SP800-90B. Thus C = ceil(-log_2(alpha)/H) = 30*osr. ++ */ ++ if ((unsigned int)ec->rct_count >= (30 * ec->osr)) { ++ ec->rct_count = -1; ++ ec->health_failure |= JENT_RCT_FAILURE; ++ } ++ } else { ++ ec->rct_count = 0; ++ } ++} ++ ++/** ++ * Stuck test by checking the: ++ * 1st derivative of the jitter measurement (time delta) ++ * 2nd derivative of the jitter measurement (delta of time deltas) ++ * 3rd derivative of the jitter measurement (delta of delta of time deltas) ++ * ++ * All values must always be non-zero. ++ * ++ * @ec [in] Reference to entropy collector ++ * @current_delta [in] Jitter time delta ++ * ++ * @return ++ * 0 jitter measurement not stuck (good bit) ++ * 1 jitter measurement stuck (reject bit) ++ */ ++unsigned int jent_stuck(struct rand_data *ec, uint64_t current_delta) ++{ ++ uint64_t delta2 = jent_delta2(ec, current_delta); ++ uint64_t delta3 = jent_delta3(ec, delta2); ++ ++ /* ++ * Insert the result of the comparison of two back-to-back time ++ * deltas. ++ */ ++ jent_apt_insert(ec, current_delta); ++ jent_lag_insert(ec, current_delta); ++ ++ if (!current_delta || !delta2 || !delta3) { ++ /* RCT with a stuck bit */ ++ jent_rct_insert(ec, 1); ++ return 1; ++ } ++ ++ /* RCT with a non-stuck bit */ ++ jent_rct_insert(ec, 0); ++ ++ return 0; ++} ++ ++/** ++ * Report any health test failures ++ * ++ * @ec [in] Reference to entropy collector ++ * ++ * @return a bitmask indicating which tests failed ++ * 0 No health test failure ++ * 1 RCT failure ++ * 2 APT failure ++ * 4 Lag predictor test failure ++ */ ++unsigned int jent_health_failure(struct rand_data *ec) ++{ ++ /* Test is only enabled in FIPS mode */ ++ if (!ec->fips_enabled) ++ return 0; ++ ++ return ec->health_failure; ++} +Index: libgcrypt-1.9.4/random/jitterentropy-health.h +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-health.h +@@ -0,0 +1,51 @@ ++/* ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * License: see LICENSE file in root directory ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF ++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT ++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ */ ++ ++#ifndef JITTERENTROPY_HEALTH_H ++#define JITTERENTROPY_HEALTH_H ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++ ++static inline uint64_t jent_delta(uint64_t prev, uint64_t next) ++{ ++ return (next - prev); ++} ++ ++#ifdef JENT_HEALTH_LAG_PREDICTOR ++void jent_lag_init(struct rand_data *ec, unsigned int osr); ++#else /* JENT_HEALTH_LAG_PREDICTOR */ ++static inline void jent_lag_init(struct rand_data *ec, unsigned int osr) ++{ ++ (void)ec; ++ (void)osr; ++} ++#endif /* JENT_HEALTH_LAG_PREDICTOR */ ++ ++void jent_apt_init(struct rand_data *ec, unsigned int osr); ++unsigned int jent_stuck(struct rand_data *ec, uint64_t current_delta); ++unsigned int jent_health_failure(struct rand_data *ec); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* JITTERENTROPY_HEALTH_H */ +Index: libgcrypt-1.9.4/random/jitterentropy-noise.c +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-noise.c +@@ -0,0 +1,387 @@ ++/* Jitter RNG: Noise Sources ++ * ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * License: see LICENSE file in root directory ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF ++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT ++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ */ ++ ++#include "jitterentropy-noise.h" ++#include "jitterentropy-health.h" ++#include "jitterentropy-timer.h" ++#include "jitterentropy-sha3.h" ++ ++#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) ++ ++/*************************************************************************** ++ * Noise sources ++ ***************************************************************************/ ++ ++/** ++ * Update of the loop count used for the next round of ++ * an entropy collection. ++ * ++ * @ec [in] entropy collector struct -- may be NULL ++ * @bits [in] is the number of low bits of the timer to consider ++ * @min [in] is the number of bits we shift the timer value to the right at ++ * the end to make sure we have a guaranteed minimum value ++ * ++ * @return Newly calculated loop counter ++ */ ++static uint64_t jent_loop_shuffle(struct rand_data *ec, ++ unsigned int bits, unsigned int min) ++{ ++#ifdef JENT_CONF_DISABLE_LOOP_SHUFFLE ++ ++ (void)ec; ++ (void)bits; ++ ++ return (UINT64_C(1)<data[0]; ++ } ++ ++ /* ++ * We fold the time value as much as possible to ensure that as many ++ * bits of the time stamp are included as possible. ++ */ ++ for (i = 0; ((DATA_SIZE_BITS + bits - 1) / bits) > i; i++) { ++ shuffle ^= time & mask; ++ time = time >> bits; ++ } ++ ++ /* ++ * We add a lower boundary value to ensure we have a minimum ++ * RNG loop count. ++ */ ++ return (shuffle + (UINT64_C(1)< 63); ++ hash_loop_cnt = ++ jent_loop_shuffle(ec, MAX_HASH_LOOP, MIN_HASH_LOOP); ++ ++ sha3_256_init(&ctx); ++ ++ /* ++ * testing purposes -- allow test app to set the counter, not ++ * needed during runtime ++ */ ++ if (loop_cnt) ++ hash_loop_cnt = loop_cnt; ++ ++ /* ++ * This loop basically slows down the SHA-3 operation depending ++ * on the hash_loop_cnt. Each iteration of the loop generates the ++ * same result. ++ */ ++ for (j = 0; j < hash_loop_cnt; j++) { ++ sha3_update(&ctx, ec->data, SHA3_256_SIZE_DIGEST); ++ sha3_update(&ctx, (uint8_t *)&time, sizeof(uint64_t)); ++ sha3_update(&ctx, (uint8_t *)&j, sizeof(uint64_t)); ++ ++ /* ++ * If the time stamp is stuck, do not finally insert the value ++ * into the entropy pool. Although this operation should not do ++ * any harm even when the time stamp has no entropy, SP800-90B ++ * requires that any conditioning operation to have an identical ++ * amount of input data according to section 3.1.5. ++ */ ++ ++ /* ++ * The sha3_final operations re-initialize the context for the ++ * next loop iteration. ++ */ ++ if (stuck || (j < hash_loop_cnt - 1)) ++ sha3_final(&ctx, itermediary); ++ else ++ sha3_final(&ctx, ec->data); ++ } ++ ++ jent_memset_secure(&ctx, SHA_MAX_CTX_SIZE); ++ jent_memset_secure(itermediary, sizeof(itermediary)); ++} ++ ++#define MAX_ACC_LOOP_BIT 7 ++#define MIN_ACC_LOOP_BIT 0 ++#ifdef JENT_RANDOM_MEMACCESS ++ ++static inline uint32_t uint32rotl(const uint32_t x, int k) ++{ ++ return (x << k) | (x >> (32 - k)); ++} ++ ++static inline uint32_t xoshiro128starstar(uint32_t *s) ++{ ++ const uint32_t result = uint32rotl(s[1] * 5, 7) * 9; ++ const uint32_t t = s[1] << 9; ++ ++ s[2] ^= s[0]; ++ s[3] ^= s[1]; ++ s[1] ^= s[2]; ++ s[0] ^= s[3]; ++ ++ s[2] ^= t; ++ ++ s[3] = uint32rotl(s[3], 11); ++ ++ return result; ++} ++ ++static void jent_memaccess(struct rand_data *ec, uint64_t loop_cnt) ++{ ++ uint64_t i = 0; ++ union { ++ uint32_t u[4]; ++ uint8_t b[sizeof(uint32_t) * 4]; ++ } prngState = { .u = {0x8e93eec0, 0xce65608a, 0xa8d46b46, 0xe83cef69} }; ++ uint32_t addressMask; ++ uint64_t acc_loop_cnt; ++ ++ if (NULL == ec || NULL == ec->mem) ++ return; ++ ++ addressMask = ec->memmask; ++ ++ /* Ensure that macros cannot overflow jent_loop_shuffle() */ ++ BUILD_BUG_ON((MAX_ACC_LOOP_BIT + MIN_ACC_LOOP_BIT) > 63); ++ acc_loop_cnt = ++ jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT); ++ ++ /* ++ * Mix the current data into prngState ++ * ++ * Any time you see a PRNG in a noise source, you should be concerned. ++ * ++ * The PRNG doesn't directly produce the raw noise, it just adjusts the ++ * location being updated. The timing of the update is part of the raw ++ * sample. The main thing this process gets you isn't better ++ * "per-update: timing, it gets you mostly independent "per-update" ++ * timing, so we can now benefit from the Central Limit Theorem! ++ */ ++ for (i = 0; i < sizeof(prngState); i++) ++ prngState.b[i] ^= ec->data[i]; ++ ++ /* ++ * testing purposes -- allow test app to set the counter, not ++ * needed during runtime ++ */ ++ if (loop_cnt) ++ acc_loop_cnt = loop_cnt; ++ ++ for (i = 0; i < (ec->memaccessloops + acc_loop_cnt); i++) { ++ /* Take PRNG output to find the memory location to update. */ ++ unsigned char *tmpval = ec->mem + ++ (xoshiro128starstar(prngState.u) & ++ addressMask); ++ ++ /* ++ * memory access: just add 1 to one byte, ++ * wrap at 255 -- memory access implies read ++ * from and write to memory location ++ */ ++ *tmpval = (unsigned char)((*tmpval + 1) & 0xff); ++ } ++} ++ ++#else /* JENT_RANDOM_MEMACCESS */ ++ ++/** ++ * Memory Access noise source -- this is a noise source based on variations in ++ * memory access times ++ * ++ * This function performs memory accesses which will add to the timing ++ * variations due to an unknown amount of CPU wait states that need to be ++ * added when accessing memory. The memory size should be larger than the L1 ++ * caches as outlined in the documentation and the associated testing. ++ * ++ * The L1 cache has a very high bandwidth, albeit its access rate is usually ++ * slower than accessing CPU registers. Therefore, L1 accesses only add minimal ++ * variations as the CPU has hardly to wait. Starting with L2, significant ++ * variations are added because L2 typically does not belong to the CPU any more ++ * and therefore a wider range of CPU wait states is necessary for accesses. ++ * L3 and real memory accesses have even a wider range of wait states. However, ++ * to reliably access either L3 or memory, the ec->mem memory must be quite ++ * large which is usually not desirable. ++ * ++ * @ec [in] Reference to the entropy collector with the memory access data -- if ++ * the reference to the memory block to be accessed is NULL, this noise ++ * source is disabled ++ * @loop_cnt [in] if a value not equal to 0 is set, use the given value as ++ * number of loops to perform the hash operation ++ */ ++static void jent_memaccess(struct rand_data *ec, uint64_t loop_cnt) ++{ ++ unsigned int wrap = 0; ++ uint64_t i = 0; ++ ++ /* Ensure that macros cannot overflow jent_loop_shuffle() */ ++ BUILD_BUG_ON((MAX_ACC_LOOP_BIT + MIN_ACC_LOOP_BIT) > 63); ++ uint64_t acc_loop_cnt = ++ jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT); ++ ++ if (NULL == ec || NULL == ec->mem) ++ return; ++ wrap = ec->memblocksize * ec->memblocks; ++ ++ /* ++ * testing purposes -- allow test app to set the counter, not ++ * needed during runtime ++ */ ++ if (loop_cnt) ++ acc_loop_cnt = loop_cnt; ++ for (i = 0; i < (ec->memaccessloops + acc_loop_cnt); i++) { ++ unsigned char *tmpval = ec->mem + ec->memlocation; ++ /* ++ * memory access: just add 1 to one byte, ++ * wrap at 255 -- memory access implies read ++ * from and write to memory location ++ */ ++ *tmpval = (unsigned char)((*tmpval + 1) & 0xff); ++ /* ++ * Addition of memblocksize - 1 to pointer ++ * with wrap around logic to ensure that every ++ * memory location is hit evenly ++ */ ++ ec->memlocation = ec->memlocation + ec->memblocksize - 1; ++ ec->memlocation = ec->memlocation % wrap; ++ } ++} ++ ++#endif /* JENT_RANDOM_MEMACCESS */ ++ ++/*************************************************************************** ++ * Start of entropy processing logic ++ ***************************************************************************/ ++ ++/** ++ * This is the heart of the entropy generation: calculate time deltas and ++ * use the CPU jitter in the time deltas. The jitter is injected into the ++ * entropy pool. ++ * ++ * WARNING: ensure that ->prev_time is primed before using the output ++ * of this function! This can be done by calling this function ++ * and not using its result. ++ * ++ * @ec [in] Reference to entropy collector ++ * @loop_cnt [in] see jent_hash_time ++ * @ret_current_delta [out] Test interface: return time delta - may be NULL ++ * ++ * @return: result of stuck test ++ */ ++unsigned int jent_measure_jitter(struct rand_data *ec, ++ uint64_t loop_cnt, ++ uint64_t *ret_current_delta) ++{ ++ uint64_t time = 0; ++ uint64_t current_delta = 0; ++ unsigned int stuck; ++ ++ /* Invoke one noise source before time measurement to add variations */ ++ jent_memaccess(ec, loop_cnt); ++ ++ /* ++ * Get time stamp and calculate time delta to previous ++ * invocation to measure the timing variations ++ */ ++ jent_get_nstime_internal(ec, &time); ++ current_delta = jent_delta(ec->prev_time, time) / ++ ec->jent_common_timer_gcd; ++ ec->prev_time = time; ++ ++ /* Check whether we have a stuck measurement. */ ++ stuck = jent_stuck(ec, current_delta); ++ ++ /* Now call the next noise sources which also injects the data */ ++ jent_hash_time(ec, current_delta, loop_cnt, stuck); ++ ++ /* return the raw entropy value */ ++ if (ret_current_delta) ++ *ret_current_delta = current_delta; ++ ++ return stuck; ++} ++ ++/** ++ * Generator of one 256 bit random number ++ * Function fills rand_data->data ++ * ++ * @ec [in] Reference to entropy collector ++ */ ++void jent_random_data(struct rand_data *ec) ++{ ++ unsigned int k = 0, safety_factor = ENTROPY_SAFETY_FACTOR; ++ ++ if (!ec->fips_enabled) ++ safety_factor = 0; ++ ++ /* priming of the ->prev_time value */ ++ jent_measure_jitter(ec, 0, NULL); ++ ++ while (1) { ++ /* If a stuck measurement is received, repeat measurement */ ++ if (jent_measure_jitter(ec, 0, NULL)) ++ continue; ++ ++ /* ++ * We multiply the loop value with ->osr to obtain the ++ * oversampling rate requested by the caller ++ */ ++ if (++k >= ((DATA_SIZE_BITS + safety_factor) * ec->osr)) ++ break; ++ } ++} +Index: libgcrypt-1.9.4/random/jitterentropy-noise.h +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-noise.h +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * License: see LICENSE file in root directory ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF ++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT ++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ */ ++ ++#ifndef JITTERENTROPY_NOISE_H ++#define JITTERENTROPY_NOISE_H ++ ++#include "jitterentropy.h" ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++ ++unsigned int jent_measure_jitter(struct rand_data *ec, ++ uint64_t loop_cnt, ++ uint64_t *ret_current_delta); ++void jent_random_data(struct rand_data *ec); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* JITTERENTROPY_NOISE_H */ +Index: libgcrypt-1.9.4/random/jitterentropy-sha3.c +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-sha3.c +@@ -0,0 +1,382 @@ ++/* Jitter RNG: SHA-3 Implementation ++ * ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * License: see LICENSE file in root directory ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF ++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT ++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ */ ++ ++#include "jitterentropy-sha3.h" ++ ++/*************************************************************************** ++ * Message Digest Implementation ++ ***************************************************************************/ ++ ++/* ++ * Conversion of Little-Endian representations in byte streams - the data ++ * representation in the integer values is the host representation. ++ */ ++static inline uint32_t ptr_to_le32(const uint8_t *p) ++{ ++ return (uint32_t)p[0] | (uint32_t)p[1] << 8 | ++ (uint32_t)p[2] << 16 | (uint32_t)p[3] << 24; ++} ++ ++static inline uint64_t ptr_to_le64(const uint8_t *p) ++{ ++ return (uint64_t)ptr_to_le32(p) | (uint64_t)ptr_to_le32(p + 4) << 32; ++} ++ ++static inline void le32_to_ptr(uint8_t *p, const uint32_t value) ++{ ++ p[0] = (uint8_t)(value); ++ p[1] = (uint8_t)(value >> 8); ++ p[2] = (uint8_t)(value >> 16); ++ p[3] = (uint8_t)(value >> 24); ++} ++ ++static inline void le64_to_ptr(uint8_t *p, const uint64_t value) ++{ ++ le32_to_ptr(p + 4, (uint32_t)(value >> 32)); ++ le32_to_ptr(p, (uint32_t)(value)); ++} ++ ++/*********************************** Keccak ***********************************/ ++/* state[x + y*5] */ ++#define A(x, y) (x + 5 * y) ++ ++static inline void keccakp_theta(uint64_t s[25]) ++{ ++ uint64_t C[5], D[5]; ++ ++ /* Step 1 */ ++ C[0] = s[A(0, 0)] ^ s[A(0, 1)] ^ s[A(0, 2)] ^ s[A(0, 3)] ^ s[A(0, 4)]; ++ C[1] = s[A(1, 0)] ^ s[A(1, 1)] ^ s[A(1, 2)] ^ s[A(1, 3)] ^ s[A(1, 4)]; ++ C[2] = s[A(2, 0)] ^ s[A(2, 1)] ^ s[A(2, 2)] ^ s[A(2, 3)] ^ s[A(2, 4)]; ++ C[3] = s[A(3, 0)] ^ s[A(3, 1)] ^ s[A(3, 2)] ^ s[A(3, 3)] ^ s[A(3, 4)]; ++ C[4] = s[A(4, 0)] ^ s[A(4, 1)] ^ s[A(4, 2)] ^ s[A(4, 3)] ^ s[A(4, 4)]; ++ ++ /* Step 2 */ ++ D[0] = C[4] ^ rol64(C[1], 1); ++ D[1] = C[0] ^ rol64(C[2], 1); ++ D[2] = C[1] ^ rol64(C[3], 1); ++ D[3] = C[2] ^ rol64(C[4], 1); ++ D[4] = C[3] ^ rol64(C[0], 1); ++ ++ /* Step 3 */ ++ s[A(0, 0)] ^= D[0]; ++ s[A(1, 0)] ^= D[1]; ++ s[A(2, 0)] ^= D[2]; ++ s[A(3, 0)] ^= D[3]; ++ s[A(4, 0)] ^= D[4]; ++ ++ s[A(0, 1)] ^= D[0]; ++ s[A(1, 1)] ^= D[1]; ++ s[A(2, 1)] ^= D[2]; ++ s[A(3, 1)] ^= D[3]; ++ s[A(4, 1)] ^= D[4]; ++ ++ s[A(0, 2)] ^= D[0]; ++ s[A(1, 2)] ^= D[1]; ++ s[A(2, 2)] ^= D[2]; ++ s[A(3, 2)] ^= D[3]; ++ s[A(4, 2)] ^= D[4]; ++ ++ s[A(0, 3)] ^= D[0]; ++ s[A(1, 3)] ^= D[1]; ++ s[A(2, 3)] ^= D[2]; ++ s[A(3, 3)] ^= D[3]; ++ s[A(4, 3)] ^= D[4]; ++ ++ s[A(0, 4)] ^= D[0]; ++ s[A(1, 4)] ^= D[1]; ++ s[A(2, 4)] ^= D[2]; ++ s[A(3, 4)] ^= D[3]; ++ s[A(4, 4)] ^= D[4]; ++} ++ ++static inline void keccakp_rho(uint64_t s[25]) ++{ ++ /* Step 1 */ ++ /* s[A(0, 0)] = s[A(0, 0)]; */ ++ ++#define RHO_ROL(t) (((t + 1) * (t + 2) / 2) % 64) ++ /* Step 3 */ ++ s[A(1, 0)] = rol64(s[A(1, 0)], RHO_ROL(0)); ++ s[A(0, 2)] = rol64(s[A(0, 2)], RHO_ROL(1)); ++ s[A(2, 1)] = rol64(s[A(2, 1)], RHO_ROL(2)); ++ s[A(1, 2)] = rol64(s[A(1, 2)], RHO_ROL(3)); ++ s[A(2, 3)] = rol64(s[A(2, 3)], RHO_ROL(4)); ++ s[A(3, 3)] = rol64(s[A(3, 3)], RHO_ROL(5)); ++ s[A(3, 0)] = rol64(s[A(3, 0)], RHO_ROL(6)); ++ s[A(0, 1)] = rol64(s[A(0, 1)], RHO_ROL(7)); ++ s[A(1, 3)] = rol64(s[A(1, 3)], RHO_ROL(8)); ++ s[A(3, 1)] = rol64(s[A(3, 1)], RHO_ROL(9)); ++ s[A(1, 4)] = rol64(s[A(1, 4)], RHO_ROL(10)); ++ s[A(4, 4)] = rol64(s[A(4, 4)], RHO_ROL(11)); ++ s[A(4, 0)] = rol64(s[A(4, 0)], RHO_ROL(12)); ++ s[A(0, 3)] = rol64(s[A(0, 3)], RHO_ROL(13)); ++ s[A(3, 4)] = rol64(s[A(3, 4)], RHO_ROL(14)); ++ s[A(4, 3)] = rol64(s[A(4, 3)], RHO_ROL(15)); ++ s[A(3, 2)] = rol64(s[A(3, 2)], RHO_ROL(16)); ++ s[A(2, 2)] = rol64(s[A(2, 2)], RHO_ROL(17)); ++ s[A(2, 0)] = rol64(s[A(2, 0)], RHO_ROL(18)); ++ s[A(0, 4)] = rol64(s[A(0, 4)], RHO_ROL(19)); ++ s[A(4, 2)] = rol64(s[A(4, 2)], RHO_ROL(20)); ++ s[A(2, 4)] = rol64(s[A(2, 4)], RHO_ROL(21)); ++ s[A(4, 1)] = rol64(s[A(4, 1)], RHO_ROL(22)); ++ s[A(1, 1)] = rol64(s[A(1, 1)], RHO_ROL(23)); ++} ++ ++static inline void keccakp_pi(uint64_t s[25]) ++{ ++ uint64_t t = s[A(4, 4)]; ++ ++ /* Step 1 */ ++ /* s[A(0, 0)] = s[A(0, 0)]; */ ++ s[A(4, 4)] = s[A(1, 4)]; ++ s[A(1, 4)] = s[A(3, 1)]; ++ s[A(3, 1)] = s[A(1, 3)]; ++ s[A(1, 3)] = s[A(0, 1)]; ++ s[A(0, 1)] = s[A(3, 0)]; ++ s[A(3, 0)] = s[A(3, 3)]; ++ s[A(3, 3)] = s[A(2, 3)]; ++ s[A(2, 3)] = s[A(1, 2)]; ++ s[A(1, 2)] = s[A(2, 1)]; ++ s[A(2, 1)] = s[A(0, 2)]; ++ s[A(0, 2)] = s[A(1, 0)]; ++ s[A(1, 0)] = s[A(1, 1)]; ++ s[A(1, 1)] = s[A(4, 1)]; ++ s[A(4, 1)] = s[A(2, 4)]; ++ s[A(2, 4)] = s[A(4, 2)]; ++ s[A(4, 2)] = s[A(0, 4)]; ++ s[A(0, 4)] = s[A(2, 0)]; ++ s[A(2, 0)] = s[A(2, 2)]; ++ s[A(2, 2)] = s[A(3, 2)]; ++ s[A(3, 2)] = s[A(4, 3)]; ++ s[A(4, 3)] = s[A(3, 4)]; ++ s[A(3, 4)] = s[A(0, 3)]; ++ s[A(0, 3)] = s[A(4, 0)]; ++ s[A(4, 0)] = t; ++} ++ ++static inline void keccakp_chi(uint64_t s[25]) ++{ ++ uint64_t t0[5], t1[5]; ++ ++ t0[0] = s[A(0, 0)]; ++ t0[1] = s[A(0, 1)]; ++ t0[2] = s[A(0, 2)]; ++ t0[3] = s[A(0, 3)]; ++ t0[4] = s[A(0, 4)]; ++ ++ t1[0] = s[A(1, 0)]; ++ t1[1] = s[A(1, 1)]; ++ t1[2] = s[A(1, 2)]; ++ t1[3] = s[A(1, 3)]; ++ t1[4] = s[A(1, 4)]; ++ ++ s[A(0, 0)] ^= ~s[A(1, 0)] & s[A(2, 0)]; ++ s[A(0, 1)] ^= ~s[A(1, 1)] & s[A(2, 1)]; ++ s[A(0, 2)] ^= ~s[A(1, 2)] & s[A(2, 2)]; ++ s[A(0, 3)] ^= ~s[A(1, 3)] & s[A(2, 3)]; ++ s[A(0, 4)] ^= ~s[A(1, 4)] & s[A(2, 4)]; ++ ++ s[A(1, 0)] ^= ~s[A(2, 0)] & s[A(3, 0)]; ++ s[A(1, 1)] ^= ~s[A(2, 1)] & s[A(3, 1)]; ++ s[A(1, 2)] ^= ~s[A(2, 2)] & s[A(3, 2)]; ++ s[A(1, 3)] ^= ~s[A(2, 3)] & s[A(3, 3)]; ++ s[A(1, 4)] ^= ~s[A(2, 4)] & s[A(3, 4)]; ++ ++ s[A(2, 0)] ^= ~s[A(3, 0)] & s[A(4, 0)]; ++ s[A(2, 1)] ^= ~s[A(3, 1)] & s[A(4, 1)]; ++ s[A(2, 2)] ^= ~s[A(3, 2)] & s[A(4, 2)]; ++ s[A(2, 3)] ^= ~s[A(3, 3)] & s[A(4, 3)]; ++ s[A(2, 4)] ^= ~s[A(3, 4)] & s[A(4, 4)]; ++ ++ s[A(3, 0)] ^= ~s[A(4, 0)] & t0[0]; ++ s[A(3, 1)] ^= ~s[A(4, 1)] & t0[1]; ++ s[A(3, 2)] ^= ~s[A(4, 2)] & t0[2]; ++ s[A(3, 3)] ^= ~s[A(4, 3)] & t0[3]; ++ s[A(3, 4)] ^= ~s[A(4, 4)] & t0[4]; ++ ++ s[A(4, 0)] ^= ~t0[0] & t1[0]; ++ s[A(4, 1)] ^= ~t0[1] & t1[1]; ++ s[A(4, 2)] ^= ~t0[2] & t1[2]; ++ s[A(4, 3)] ^= ~t0[3] & t1[3]; ++ s[A(4, 4)] ^= ~t0[4] & t1[4]; ++} ++ ++static const uint64_t keccakp_iota_vals[] = { ++ 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, ++ 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL, ++ 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, ++ 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, ++ 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, ++ 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, ++ 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, ++ 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL ++}; ++ ++static inline void keccakp_iota(uint64_t s[25], unsigned int round) ++{ ++ s[0] ^= keccakp_iota_vals[round]; ++} ++ ++static inline void keccakp_1600(uint64_t s[25]) ++{ ++ unsigned int round; ++ ++ for (round = 0; round < 24; round++) { ++ keccakp_theta(s); ++ keccakp_rho(s); ++ keccakp_pi(s); ++ keccakp_chi(s); ++ keccakp_iota(s, round); ++ } ++} ++ ++/*********************************** SHA-3 ************************************/ ++ ++static inline void sha3_init(struct sha_ctx *ctx) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < 25; i++) ++ ctx->state[i] = 0; ++ ctx->msg_len = 0; ++} ++ ++void sha3_256_init(struct sha_ctx *ctx) ++{ ++ sha3_init(ctx); ++ ctx->r = SHA3_256_SIZE_BLOCK; ++ ctx->rword = SHA3_256_SIZE_BLOCK / sizeof(uint64_t); ++ ctx->digestsize = SHA3_256_SIZE_DIGEST; ++} ++ ++static inline void sha3_fill_state(struct sha_ctx *ctx, const uint8_t *in) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ctx->rword; i++) { ++ ctx->state[i] ^= ptr_to_le64(in); ++ in += 8; ++ } ++} ++ ++void sha3_update(struct sha_ctx *ctx, const uint8_t *in, size_t inlen) ++{ ++ size_t partial = ctx->msg_len % ctx->r; ++ ++ ctx->msg_len += inlen; ++ ++ /* Sponge absorbing phase */ ++ ++ /* Check if we have a partial block stored */ ++ if (partial) { ++ size_t todo = ctx->r - partial; ++ ++ /* ++ * If the provided data is small enough to fit in the partial ++ * buffer, copy it and leave it unprocessed. ++ */ ++ if (inlen < todo) { ++ memcpy(ctx->partial + partial, in, inlen); ++ return; ++ } ++ ++ /* ++ * The input data is large enough to fill the entire partial ++ * block buffer. Thus, we fill it and transform it. ++ */ ++ memcpy(ctx->partial + partial, in, todo); ++ inlen -= todo; ++ in += todo; ++ ++ sha3_fill_state(ctx, ctx->partial); ++ keccakp_1600(ctx->state); ++ } ++ ++ /* Perform a transformation of full block-size messages */ ++ for (; inlen >= ctx->r; inlen -= ctx->r, in += ctx->r) { ++ sha3_fill_state(ctx, in); ++ keccakp_1600(ctx->state); ++ } ++ ++ /* If we have data left, copy it into the partial block buffer */ ++ memcpy(ctx->partial, in, inlen); ++} ++ ++void sha3_final(struct sha_ctx *ctx, uint8_t *digest) ++{ ++ size_t partial = ctx->msg_len % ctx->r; ++ unsigned int i; ++ ++ /* Final round in sponge absorbing phase */ ++ ++ /* Fill the unused part of the partial buffer with zeros */ ++ memset(ctx->partial + partial, 0, ctx->r - partial); ++ ++ /* ++ * Add the leading and trailing bit as well as the 01 bits for the ++ * SHA-3 suffix. ++ */ ++ ctx->partial[partial] = 0x06; ++ ctx->partial[ctx->r - 1] |= 0x80; ++ ++ /* Final transformation */ ++ sha3_fill_state(ctx, ctx->partial); ++ keccakp_1600(ctx->state); ++ ++ /* ++ * Sponge squeeze phase - the digest size is always smaller as the ++ * state size r which implies we only have one squeeze round. ++ */ ++ for (i = 0; i < ctx->digestsize / 8; i++, digest += 8) ++ le64_to_ptr(digest, ctx->state[i]); ++ ++ /* Add remaining 4 bytes if we use SHA3-224 */ ++ if (ctx->digestsize % 8) ++ le32_to_ptr(digest, (uint32_t)(ctx->state[i])); ++ ++ memset(ctx->partial, 0, ctx->r); ++ sha3_init(ctx); ++} ++ ++int sha3_tester(void) ++{ ++ HASH_CTX_ON_STACK(ctx); ++ static const uint8_t msg_256[] = { 0x5E, 0x5E, 0xD6 }; ++ static const uint8_t exp_256[] = { 0xF1, 0x6E, 0x66, 0xC0, 0x43, 0x72, ++ 0xB4, 0xA3, 0xE1, 0xE3, 0x2E, 0x07, ++ 0xC4, 0x1C, 0x03, 0x40, 0x8A, 0xD5, ++ 0x43, 0x86, 0x8C, 0xC4, 0x0E, 0xC5, ++ 0x5E, 0x00, 0xBB, 0xBB, 0xBD, 0xF5, ++ 0x91, 0x1E }; ++ uint8_t act[SHA3_256_SIZE_DIGEST] = { 0 }; ++ unsigned int i; ++ ++ sha3_256_init(&ctx); ++ sha3_update(&ctx, msg_256, 3); ++ sha3_final(&ctx, act); ++ ++ for (i = 0; i < SHA3_256_SIZE_DIGEST; i++) { ++ if (exp_256[i] != act[i]) ++ return 1; ++ } ++ ++ return 0; ++} +Index: libgcrypt-1.9.4/random/jitterentropy-sha3.h +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-sha3.h +@@ -0,0 +1,56 @@ ++/* ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * License: see LICENSE file in root directory ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF ++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT ++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ */ ++ ++#ifndef JITTERENTROPY_SHA3_H ++#define JITTERENTROPY_SHA3_H ++ ++#include "jitterentropy.h" ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++ ++#define SHA3_SIZE_BLOCK(bits) ((1600 - 2 * bits) >> 3) ++#define SHA3_256_SIZE_BLOCK SHA3_SIZE_BLOCK(SHA3_256_SIZE_DIGEST_BITS) ++#define SHA3_MAX_SIZE_BLOCK SHA3_256_SIZE_BLOCK ++ ++struct sha_ctx { ++ uint64_t state[25]; ++ size_t msg_len; ++ unsigned int r; ++ unsigned int rword; ++ unsigned int digestsize; ++ uint8_t partial[SHA3_MAX_SIZE_BLOCK]; ++}; ++ ++#define SHA_MAX_CTX_SIZE (sizeof(struct sha_ctx)) ++#define HASH_CTX_ON_STACK(name) \ ++ struct sha_ctx name ++ ++void sha3_256_init(struct sha_ctx *ctx); ++void sha3_update(struct sha_ctx *ctx, const uint8_t *in, size_t inlen); ++void sha3_final(struct sha_ctx *ctx, uint8_t *digest); ++int sha3_tester(void); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* JITTERENTROPY_SHA3_H */ +Index: libgcrypt-1.9.4/random/jitterentropy-timer.c +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-timer.c +@@ -0,0 +1,234 @@ ++/* Jitter RNG: Internal timer implementation ++ * ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * License: see LICENSE file in root directory ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF ++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT ++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ */ ++ ++#include "jitterentropy-base.h" ++#include "jitterentropy-timer.h" ++ ++#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER ++ ++/*************************************************************************** ++ * Thread handler ++ ***************************************************************************/ ++ ++JENT_PRIVATE_STATIC ++int jent_notime_init(void **ctx) ++{ ++ struct jent_notime_ctx *thread_ctx; ++ long ncpu = jent_ncpu(); ++ ++ if (ncpu < 0) ++ return (int)ncpu; ++ ++ /* We need at least two CPUs to enable the timer thread */ ++ if (ncpu < 2) ++ return -EOPNOTSUPP; ++ ++ thread_ctx = calloc(1, sizeof(struct jent_notime_ctx)); ++ if (!thread_ctx) ++ return -errno; ++ ++ *ctx = thread_ctx; ++ ++ return 0; ++} ++ ++JENT_PRIVATE_STATIC ++void jent_notime_fini(void *ctx) ++{ ++ struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx; ++ ++ if (thread_ctx) ++ free(thread_ctx); ++} ++ ++static int jent_notime_start(void *ctx, ++ void *(*start_routine) (void *), void *arg) ++{ ++ struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx; ++ int ret; ++ ++ if (!thread_ctx) ++ return -EINVAL; ++ ++ ret = -pthread_attr_init(&thread_ctx->notime_pthread_attr); ++ if (ret) ++ return ret; ++ ++ return -pthread_create(&thread_ctx->notime_thread_id, ++ &thread_ctx->notime_pthread_attr, ++ start_routine, arg); ++} ++ ++static void jent_notime_stop(void *ctx) ++{ ++ struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx; ++ ++ pthread_join(thread_ctx->notime_thread_id, NULL); ++ pthread_attr_destroy(&thread_ctx->notime_pthread_attr); ++} ++ ++static struct jent_notime_thread jent_notime_thread_builtin = { ++ .jent_notime_init = jent_notime_init, ++ .jent_notime_fini = jent_notime_fini, ++ .jent_notime_start = jent_notime_start, ++ .jent_notime_stop = jent_notime_stop ++}; ++ ++/*************************************************************************** ++ * Timer-less timer replacement ++ * ++ * If there is no high-resolution hardware timer available, we create one ++ * ourselves. This logic is only used when the initialization identifies ++ * that no suitable time source is available. ++ ***************************************************************************/ ++ ++static int jent_force_internal_timer = 0; ++static int jent_notime_switch_blocked = 0; ++ ++void jent_notime_block_switch(void) ++{ ++ jent_notime_switch_blocked = 1; ++} ++ ++static struct jent_notime_thread *notime_thread = &jent_notime_thread_builtin; ++ ++/** ++ * Timer-replacement loop ++ * ++ * @brief The measurement loop triggers the read of the value from the ++ * counter function. It conceptually acts as the low resolution ++ * samples timer from a ring oscillator. ++ */ ++static void *jent_notime_sample_timer(void *arg) ++{ ++ struct rand_data *ec = (struct rand_data *)arg; ++ ++ ec->notime_timer = 0; ++ ++ while (1) { ++ if (ec->notime_interrupt) ++ return NULL; ++ ++ ec->notime_timer++; ++ } ++ ++ return NULL; ++} ++ ++/* ++ * Enable the clock: spawn a new thread that holds a counter. ++ * ++ * Note, although creating a thread is expensive, we do that every time a ++ * caller wants entropy from us and terminate the thread afterwards. This ++ * is to ensure an attacker cannot easily identify the ticking thread. ++ */ ++int jent_notime_settick(struct rand_data *ec) ++{ ++ if (!ec->enable_notime || !notime_thread) ++ return 0; ++ ++ ec->notime_interrupt = 0; ++ ec->notime_prev_timer = 0; ++ ec->notime_timer = 0; ++ ++ return notime_thread->jent_notime_start(ec->notime_thread_ctx, ++ jent_notime_sample_timer, ec); ++} ++ ++void jent_notime_unsettick(struct rand_data *ec) ++{ ++ if (!ec->enable_notime || !notime_thread) ++ return; ++ ++ ec->notime_interrupt = 1; ++ notime_thread->jent_notime_stop(ec->notime_thread_ctx); ++} ++ ++void jent_get_nstime_internal(struct rand_data *ec, uint64_t *out) ++{ ++ if (ec->enable_notime) { ++ /* ++ * Allow the counting thread to be initialized and guarantee ++ * that it ticked since last time we looked. ++ * ++ * Note, we do not use an atomic operation here for reading ++ * jent_notime_timer since if this integer is garbled, it even ++ * adds to entropy. But on most architectures, read/write ++ * of an uint64_t should be atomic anyway. ++ */ ++ while (ec->notime_timer == ec->notime_prev_timer) ++ jent_yield(); ++ ++ ec->notime_prev_timer = ec->notime_timer; ++ *out = ec->notime_prev_timer; ++ } else { ++ jent_get_nstime(out); ++ } ++} ++ ++static inline int jent_notime_enable_thread(struct rand_data *ec) ++{ ++ if (notime_thread) ++ return notime_thread->jent_notime_init(&ec->notime_thread_ctx); ++ return 0; ++} ++ ++void jent_notime_disable(struct rand_data *ec) ++{ ++ if (notime_thread) ++ notime_thread->jent_notime_fini(ec->notime_thread_ctx); ++} ++ ++int jent_notime_enable(struct rand_data *ec, unsigned int flags) ++{ ++ /* Use internal timer */ ++ if (jent_force_internal_timer || (flags & JENT_FORCE_INTERNAL_TIMER)) { ++ /* Self test not run yet */ ++ if (!jent_force_internal_timer && ++ jent_time_entropy_init(flags | JENT_FORCE_INTERNAL_TIMER, ++ ec->osr)) ++ return EHEALTH; ++ ++ ec->enable_notime = 1; ++ return jent_notime_enable_thread(ec); ++ } ++ ++ return 0; ++} ++ ++int jent_notime_switch(struct jent_notime_thread *new_thread) ++{ ++ if (jent_notime_switch_blocked) ++ return -EAGAIN; ++ notime_thread = new_thread; ++ return 0; ++} ++ ++void jent_notime_force(void) ++{ ++ jent_force_internal_timer = 1; ++} ++ ++int jent_notime_forced(void) ++{ ++ return jent_force_internal_timer; ++} ++ ++#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ +Index: libgcrypt-1.9.4/random/jitterentropy-timer.h +=================================================================== +--- /dev/null ++++ libgcrypt-1.9.4/random/jitterentropy-timer.h +@@ -0,0 +1,92 @@ ++/* ++ * Copyright (C) 2021, Stephan Mueller ++ * ++ * License: see LICENSE file in root directory ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF ++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT ++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ */ ++ ++#ifndef JITTERENTROPY_TIMER_H ++#define JITTERENTROPY_TIMER_H ++ ++#include "jitterentropy.h" ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++ ++#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER ++ ++void jent_notime_block_switch(void); ++int jent_notime_settick(struct rand_data *ec); ++void jent_notime_unsettick(struct rand_data *ec); ++void jent_get_nstime_internal(struct rand_data *ec, uint64_t *out); ++int jent_notime_enable(struct rand_data *ec, unsigned int flags); ++void jent_notime_disable(struct rand_data *ec); ++int jent_notime_switch(struct jent_notime_thread *new_thread); ++void jent_notime_force(void); ++int jent_notime_forced(void); ++ ++#else /* JENT_CONF_ENABLE_INTERNAL_TIMER */ ++ ++static inline void jent_notime_block_switch(void) { } ++ ++static inline int jent_notime_settick(struct rand_data *ec) ++{ ++ (void)ec; ++ return 0; ++} ++ ++static inline void jent_notime_unsettick(struct rand_data *ec) { (void)ec; } ++ ++static inline void jent_get_nstime_internal(struct rand_data *ec, uint64_t *out) ++{ ++ (void)ec; ++ jent_get_nstime(out); ++} ++ ++static inline int jent_notime_enable(struct rand_data *ec, unsigned int flags) ++{ ++ (void)ec; ++ ++ /* If we force the timer-less noise source, we return an error */ ++ if (flags & JENT_FORCE_INTERNAL_TIMER) ++ return EHEALTH; ++ ++ return 0; ++} ++ ++static inline void jent_notime_disable(struct rand_data *ec) ++{ ++ (void)ec; ++} ++ ++static inline int jent_notime_switch(struct jent_notime_thread *new_thread) ++{ ++ (void)new_thread; ++ return -EOPNOTSUPP; ++} ++ ++static inline void jent_notime_force(void) { } ++ ++static inline int jent_notime_forced(void) { return 0; } ++ ++#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* JITTERENTROPY-TIMER_H */ +Index: libgcrypt-1.9.4/random/Makefile.am +=================================================================== +--- libgcrypt-1.9.4.orig/random/Makefile.am ++++ libgcrypt-1.9.4/random/Makefile.am +@@ -50,9 +50,14 @@ rndegd.c \ + rndunix.c \ + rndw32.c \ + rndw32ce.c \ ++jitterentropy-gcd.c jitterentropy-gcd.h \ ++jitterentropy-health.c jitterentropy-health.h \ ++jitterentropy-noise.c jitterentropy-noise.h \ ++jitterentropy-sha3.c jitterentropy-sha3.h \ ++jitterentropy-timer.c jitterentropy-timer.h \ ++jitterentropy-base.h \ + jitterentropy-base.c jitterentropy.h jitterentropy-base-user.h + +- + # The rndjent module needs to be compiled without optimization. */ + if ENABLE_O_FLAG_MUNGING + o_flag_munging = sed -e 's/-O\([1-9sg][1-9sg]*\)/-O0/g' -e 's/-Ofast/-O0/g' +@@ -61,9 +66,19 @@ o_flag_munging = cat + endif + + rndjent.o: $(srcdir)/rndjent.c jitterentropy-base-user.h \ ++ $(srcdir)/jitterentropy-gcd.c $(srcdir)/jitterentropy-gcd.h \ ++ $(srcdir)/jitterentropy-health.c $(srcdir)/jitterentropy-health.h \ ++ $(srcdir)/jitterentropy-noise.c $(srcdir)/jitterentropy-noise.h \ ++ $(srcdir)/jitterentropy-sha3.c $(srcdir)/jitterentropy-sha3.h \ ++ $(srcdir)/jitterentropy-timer.c $(srcdir)/jitterentropy-timer.h \ + $(srcdir)/jitterentropy-base.c $(srcdir)/jitterentropy.h + `echo $(COMPILE) -c $(srcdir)/rndjent.c | $(o_flag_munging) ` + + rndjent.lo: $(srcdir)/rndjent.c jitterentropy-base-user.h \ ++ $(srcdir)/jitterentropy-gcd.c $(srcdir)/jitterentropy-gcd.h \ ++ $(srcdir)/jitterentropy-health.c $(srcdir)/jitterentropy-health.h \ ++ $(srcdir)/jitterentropy-noise.c $(srcdir)/jitterentropy-noise.h \ ++ $(srcdir)/jitterentropy-sha3.c $(srcdir)/jitterentropy-sha3.h \ ++ $(srcdir)/jitterentropy-timer.c $(srcdir)/jitterentropy-timer.h \ + $(srcdir)/jitterentropy-base.c $(srcdir)/jitterentropy.h + `echo $(LTCOMPILE) -c $(srcdir)/rndjent.c | $(o_flag_munging) ` +Index: libgcrypt-1.9.4/random/Makefile.in +=================================================================== +--- libgcrypt-1.9.4.orig/random/Makefile.in ++++ libgcrypt-1.9.4/random/Makefile.in +@@ -156,6 +156,11 @@ am__depfiles_remade = ./$(DEPDIR)/jitter + ./$(DEPDIR)/random-csprng.Plo ./$(DEPDIR)/random-daemon.Plo \ + ./$(DEPDIR)/random-drbg.Plo ./$(DEPDIR)/random-system.Plo \ + ./$(DEPDIR)/random.Plo ./$(DEPDIR)/rndegd.Plo \ ++ ./$(DEPDIR)/jitterentropy-gcd.Plo \ ++ ./$(DEPDIR)/jitterentropy-health.Plo \ ++ ./$(DEPDIR)/jitterentropy-noise.Plo \ ++ ./$(DEPDIR)/jitterentropy-sha3.Plo \ ++ ./$(DEPDIR)/jitterentropy-timer.Plo \ + ./$(DEPDIR)/rndhw.Plo ./$(DEPDIR)/rndjent.Plo \ + ./$(DEPDIR)/rndlinux.Plo ./$(DEPDIR)/rndunix.Plo \ + ./$(DEPDIR)/rndw32.Plo ./$(DEPDIR)/rndw32ce.Plo +@@ -391,6 +396,12 @@ rndegd.c \ + rndunix.c \ + rndw32.c \ + rndw32ce.c \ ++jitterentropy-gcd.c jitterentropy-gcd.h \ ++jitterentropy-health.c jitterentropy-health.h \ ++jitterentropy-noise.c jitterentropy-noise.h \ ++jitterentropy-sha3.c jitterentropy-sha3.h \ ++jitterentropy-timer.c jitterentropy-timer.h \ ++jitterentropy-base.h \ + jitterentropy-base.c jitterentropy.h jitterentropy-base-user.h + + @ENABLE_O_FLAG_MUNGING_FALSE@o_flag_munging = cat +@@ -452,6 +463,11 @@ distclean-compile: + -rm -f *.tab.c + + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitterentropy-base.Plo@am__quote@ # am--include-marker ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitterentropy-gcd.Plo@am__quote@ # am--include-marker ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitterentropy-health.Plo@am__quote@ # am--include-marker ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitterentropy-noise.Plo@am__quote@ # am--include-marker ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitterentropy-sha3.Plo@am__quote@ # am--include-marker ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitterentropy-timer.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random-csprng.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random-daemon.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random-drbg.Plo@am__quote@ # am--include-marker +@@ -624,6 +640,11 @@ clean-am: clean-generic clean-libtool cl + + distclean: distclean-am + -rm -f ./$(DEPDIR)/jitterentropy-base.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-gcd.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-health.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-noise.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-sha3.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-timer.Plo + -rm -f ./$(DEPDIR)/random-csprng.Plo + -rm -f ./$(DEPDIR)/random-daemon.Plo + -rm -f ./$(DEPDIR)/random-drbg.Plo +@@ -682,6 +703,11 @@ installcheck-am: + + maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/jitterentropy-base.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-gcd.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-health.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-noise.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-sha3.Plo ++ -rm -f ./$(DEPDIR)/jitterentropy-timer.Plo + -rm -f ./$(DEPDIR)/random-csprng.Plo + -rm -f ./$(DEPDIR)/random-daemon.Plo + -rm -f ./$(DEPDIR)/random-drbg.Plo +@@ -732,10 +758,20 @@ uninstall-am: + + + rndjent.o: $(srcdir)/rndjent.c jitterentropy-base-user.h \ ++ $(srcdir)/jitterentropy-gcd.c $(srcdir)/jitterentropy-gcd.h \ ++ $(srcdir)/jitterentropy-health.c $(srcdir)/jitterentropy-health.h \ ++ $(srcdir)/jitterentropy-noise.c $(srcdir)/jitterentropy-noise.h \ ++ $(srcdir)/jitterentropy-sha3.c $(srcdir)/jitterentropy-sha3.h \ ++ $(srcdir)/jitterentropy-timer.c $(srcdir)/jitterentropy-timer.h \ + $(srcdir)/jitterentropy-base.c $(srcdir)/jitterentropy.h + `echo $(COMPILE) -c $(srcdir)/rndjent.c | $(o_flag_munging) ` + + rndjent.lo: $(srcdir)/rndjent.c jitterentropy-base-user.h \ ++ $(srcdir)/jitterentropy-gcd.c $(srcdir)/jitterentropy-gcd.h \ ++ $(srcdir)/jitterentropy-health.c $(srcdir)/jitterentropy-health.h \ ++ $(srcdir)/jitterentropy-noise.c $(srcdir)/jitterentropy-noise.h \ ++ $(srcdir)/jitterentropy-sha3.c $(srcdir)/jitterentropy-sha3.h \ ++ $(srcdir)/jitterentropy-timer.c $(srcdir)/jitterentropy-timer.h \ + $(srcdir)/jitterentropy-base.c $(srcdir)/jitterentropy.h + `echo $(LTCOMPILE) -c $(srcdir)/rndjent.c | $(o_flag_munging) ` + +Index: libgcrypt-1.9.4/random/random-csprng.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/random-csprng.c ++++ libgcrypt-1.9.4/random/random-csprng.c +@@ -357,6 +357,17 @@ _gcry_rngcsprng_close_fds (void) + _gcry_rndlinux_gather_random (NULL, 0, 0, 0); + pool_filled = 0; /* Force re-open on next use. */ + #endif ++ pool_writepos = 0; ++ pool_readpos = 0; ++ pool_filled = 0; ++ pool_filled_counter = 0; ++ did_initial_extra_seeding = 0; ++ pool_balance = 0; ++ just_mixed = 0; ++ xfree (rndpool); ++ xfree (keypool); ++ rndpool = NULL; ++ keypool = NULL; + unlock_pool (); + } + +Index: libgcrypt-1.9.4/random/random-drbg.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/random-drbg.c ++++ libgcrypt-1.9.4/random/random-drbg.c +@@ -1860,16 +1860,23 @@ _gcry_rngdrbg_reinit (const char *flagst + return ret; + } + +-/* Try to close the FDs of the random gather module. This is +- * currently only implemented for rndlinux. */ ++/* Release resources used by this DRBG module. That is, close the FDs ++ * of the random gather module (if any), and release memory used. ++ */ + void + _gcry_rngdrbg_close_fds (void) + { +-#if USE_RNDLINUX + drbg_lock (); ++#if USE_RNDLINUX + _gcry_rndlinux_gather_random (NULL, 0, 0, 0); +- drbg_unlock (); + #endif ++ if (drbg_state) ++ { ++ drbg_uninstantiate (drbg_state); ++ xfree (drbg_state); ++ drbg_state = NULL; ++ } ++ drbg_unlock (); + } + + /* Print some statistics about the RNG. */ +Index: libgcrypt-1.9.4/random/rndjent.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/rndjent.c ++++ libgcrypt-1.9.4/random/rndjent.c +@@ -43,6 +43,8 @@ + #ifdef HAVE_STDINT_H + # include + #endif ++#include ++#include + + #include "types.h" + #include "g10lib.h" +@@ -84,7 +86,14 @@ + #define JENT_PRIVATE_COMPILE 1 + + #include "jitterentropy-base.c" +- ++#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER ++#include ++#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ ++#include "jitterentropy-gcd.c" ++#include "jitterentropy-health.c" ++#include "jitterentropy-noise.c" ++#include "jitterentropy-sha3.c" ++#include "jitterentropy-timer.c" + + /* This is the lock we use to serialize access to this RNG. The extra + * integer variable is only used to check the locking state; that is, +@@ -291,7 +300,7 @@ _gcry_rndjent_poll (void (*add)(const vo + size_t n = length < sizeof(buffer)? length : sizeof (buffer); + + jent_rng_totalcalls++; +- rc = jent_read_entropy (jent_rng_collector, buffer, n); ++ rc = jent_read_entropy_safe (&jent_rng_collector, buffer, n); + if (rc < 0) + break; + /* We need to hash the output to conform to the BSI diff --git a/libgcrypt-jitterentropy-3.4.0.patch b/libgcrypt-jitterentropy-3.4.0.patch new file mode 100644 index 0000000..a4b1a99 --- /dev/null +++ b/libgcrypt-jitterentropy-3.4.0.patch @@ -0,0 +1,618 @@ +Index: libgcrypt-1.9.4/random/jitterentropy-base.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-base.c ++++ libgcrypt-1.9.4/random/jitterentropy-base.c +@@ -42,7 +42,7 @@ + * require consumer to be updated (as long as this number + * is zero, the API is not considered stable and can + * change without a bump of the major version) */ +-#define MINVERSION 3 /* API compatible, ABI may change, functional ++#define MINVERSION 4 /* API compatible, ABI may change, functional + * enhancements only, consumer can be left unchanged if + * enhancements are not considered */ + #define PATCHLEVEL 0 /* API / ABI compatible, no functional changes, no +@@ -200,29 +200,38 @@ ssize_t jent_read_entropy(struct rand_da + tocopy = (DATA_SIZE_BITS / 8); + else + tocopy = len; +- memcpy(p, &ec->data, tocopy); ++ ++ jent_read_random_block(ec, p, tocopy); + + len -= tocopy; + p += tocopy; + } + + /* +- * To be on the safe side, we generate one more round of entropy +- * which we do not give out to the caller. That round shall ensure +- * that in case the calling application crashes, memory dumps, pages +- * out, or due to the CPU Jitter RNG lingering in memory for long +- * time without being moved and an attacker cracks the application, +- * all he reads in the entropy pool is a value that is NEVER EVER +- * being used for anything. Thus, he does NOT see the previous value +- * that was returned to the caller for cryptographic purposes. ++ * Enhanced backtracking support: At this point, the hash state ++ * contains the digest of the previous Jitter RNG collection round ++ * which is inserted there by jent_read_random_block with the SHA ++ * update operation. At the current code location we completed ++ * one request for a caller and we do not know how long it will ++ * take until a new request is sent to us. To guarantee enhanced ++ * backtracking resistance at this point (i.e. ensure that an attacker ++ * cannot obtain information about prior random numbers we generated), ++ * but still stirring the hash state with old data the Jitter RNG ++ * obtains a new message digest from its state and re-inserts it. ++ * After this operation, the Jitter RNG state is still stirred with ++ * the old data, but an attacker who gets access to the memory after ++ * this point cannot deduce the random numbers produced by the ++ * Jitter RNG prior to this point. + */ + /* +- * If we use secured memory, do not use that precaution as the secure +- * memory protects the entropy pool. Moreover, note that using this +- * call reduces the speed of the RNG by up to half ++ * If we use secured memory, where backtracking support may not be ++ * needed because the state is protected in a different method, ++ * it is permissible to drop this support. But strongly weigh the ++ * pros and cons considering that the SHA3 operation is not that ++ * expensive. + */ + #ifndef JENT_CPU_JITTERENTROPY_SECURE_MEMORY +- jent_random_data(ec); ++ jent_read_random_block(ec, NULL, 0); + #endif + + err: +@@ -379,6 +388,7 @@ static struct rand_data + *jent_entropy_collector_alloc_internal(unsigned int osr, unsigned int flags) + { + struct rand_data *entropy_collector; ++ uint32_t memsize = 0; + + /* + * Requesting disabling and forcing of internal timer +@@ -405,7 +415,7 @@ static struct rand_data + return NULL; + + if (!(flags & JENT_DISABLE_MEMORY_ACCESS)) { +- uint32_t memsize = jent_memsize(flags); ++ memsize = jent_memsize(flags); + + entropy_collector->mem = _gcry_calloc (1, memsize); + +@@ -431,13 +441,19 @@ static struct rand_data + entropy_collector->memaccessloops = JENT_MEMORY_ACCESSLOOPS; + } + ++ if (sha3_alloc(&entropy_collector->hash_state)) ++ goto err; ++ ++ /* Initialize the hash state */ ++ sha3_256_init(entropy_collector->hash_state); ++ + /* verify and set the oversampling rate */ + if (osr < JENT_MIN_OSR) + osr = JENT_MIN_OSR; + entropy_collector->osr = osr; + entropy_collector->flags = flags; + +- if (jent_fips_enabled() || (flags & JENT_FORCE_FIPS)) ++ if ((flags & JENT_FORCE_FIPS) || jent_fips_enabled()) + entropy_collector->fips_enabled = 1; + + /* Initialize the APT */ +@@ -469,7 +485,7 @@ static struct rand_data + + err: + if (entropy_collector->mem != NULL) +- jent_zfree(entropy_collector->mem, JENT_MEMORY_SIZE); ++ jent_zfree(entropy_collector->mem, memsize); + jent_zfree(entropy_collector, sizeof(struct rand_data)); + return NULL; + } +@@ -511,6 +527,7 @@ JENT_PRIVATE_STATIC + void jent_entropy_collector_free(struct rand_data *entropy_collector) + { + if (entropy_collector != NULL) { ++ sha3_dealloc(entropy_collector->hash_state); + jent_notime_disable(entropy_collector); + if (entropy_collector->mem != NULL) { + jent_zfree(entropy_collector->mem, +@@ -664,6 +681,7 @@ static inline int jent_entropy_init_comm + int ret; + + jent_notime_block_switch(); ++ jent_health_cb_block_switch(); + + if (sha3_tester()) + return EHASH; +@@ -710,6 +728,8 @@ int jent_entropy_init_ex(unsigned int os + if (ret) + return ret; + ++ ret = ENOTIME; ++ + /* Test without internal timer unless caller does not want it */ + if (!(flags & JENT_FORCE_INTERNAL_TIMER)) + ret = jent_time_entropy_init(osr, +@@ -732,3 +752,9 @@ int jent_entropy_switch_notime_impl(stru + return jent_notime_switch(new_thread); + } + #endif ++ ++JENT_PRIVATE_STATIC ++int jent_set_fips_failure_callback(jent_fips_failure_cb cb) ++{ ++ return jent_set_fips_failure_callback_internal(cb); ++} +Index: libgcrypt-1.9.4/random/jitterentropy-gcd.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-gcd.c ++++ libgcrypt-1.9.4/random/jitterentropy-gcd.c +@@ -113,12 +113,8 @@ int jent_gcd_analyze(uint64_t *delta_his + goto out; + } + +- /* +- * Ensure that we have variations in the time stamp below 100 for at +- * least 10% of all checks -- on some platforms, the counter increments +- * in multiples of 100, but not always +- */ +- if (running_gcd >= 100) { ++ /* Set a sensible maximum value. */ ++ if (running_gcd >= UINT32_MAX / 2) { + ret = ECOARSETIME; + goto out; + } +Index: libgcrypt-1.9.4/random/jitterentropy-health.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-health.c ++++ libgcrypt-1.9.4/random/jitterentropy-health.c +@@ -19,9 +19,24 @@ + * DAMAGE. + */ + +-#include "jitterentropy.h" + #include "jitterentropy-health.h" + ++static jent_fips_failure_cb fips_cb = NULL; ++static int jent_health_cb_switch_blocked = 0; ++ ++void jent_health_cb_block_switch(void) ++{ ++ jent_health_cb_switch_blocked = 1; ++} ++ ++int jent_set_fips_failure_callback_internal(jent_fips_failure_cb cb) ++{ ++ if (jent_health_cb_switch_blocked) ++ return -EAGAIN; ++ fips_cb = cb; ++ return 0; ++} ++ + /*************************************************************************** + * Lag Predictor Test + * +@@ -434,5 +449,9 @@ unsigned int jent_health_failure(struct + if (!ec->fips_enabled) + return 0; + ++ if (fips_cb && ec->health_failure) { ++ fips_cb(ec, ec->health_failure); ++ } ++ + return ec->health_failure; + } +Index: libgcrypt-1.9.4/random/jitterentropy-health.h +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-health.h ++++ libgcrypt-1.9.4/random/jitterentropy-health.h +@@ -20,11 +20,16 @@ + #ifndef JITTERENTROPY_HEALTH_H + #define JITTERENTROPY_HEALTH_H + ++#include "jitterentropy.h" ++ + #ifdef __cplusplus + extern "C" + { + #endif + ++void jent_health_cb_block_switch(void); ++int jent_set_fips_failure_callback_internal(jent_fips_failure_cb cb); ++ + static inline uint64_t jent_delta(uint64_t prev, uint64_t next) + { + return (next - prev); +Index: libgcrypt-1.9.4/random/jitterentropy-noise.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-noise.c ++++ libgcrypt-1.9.4/random/jitterentropy-noise.c +@@ -33,7 +33,7 @@ + * Update of the loop count used for the next round of + * an entropy collection. + * +- * @ec [in] entropy collector struct -- may be NULL ++ * @ec [in] entropy collector struct + * @bits [in] is the number of low bits of the timer to consider + * @min [in] is the number of bits we shift the timer value to the right at + * the end to make sure we have a guaranteed minimum value +@@ -61,16 +61,13 @@ static uint64_t jent_loop_shuffle(struct + * Mix the current state of the random number into the shuffle + * calculation to balance that shuffle a bit more. + */ +- if (ec) { +- jent_get_nstime_internal(ec, &time); +- time ^= ec->data[0]; +- } ++ jent_get_nstime_internal(ec, &time); + + /* + * We fold the time value as much as possible to ensure that as many + * bits of the time stamp are included as possible. + */ +- for (i = 0; ((DATA_SIZE_BITS + bits - 1) / bits) > i; i++) { ++ for (i = 0; (((sizeof(time) << 3) + bits - 1) / bits) > i; i++) { + shuffle ^= time & mask; + time = time >> bits; + } +@@ -91,11 +88,11 @@ static uint64_t jent_loop_shuffle(struct + * This function injects the individual bits of the time value into the + * entropy pool using a hash. + * +- * @ec [in] entropy collector struct -- may be NULL +- * @time [in] time stamp to be injected ++ * @ec [in] entropy collector struct ++ * @time [in] time delta to be injected + * @loop_cnt [in] if a value not equal to 0 is set, use the given value as + * number of loops to perform the hash operation +- * @stuck [in] Is the time stamp identified as stuck? ++ * @stuck [in] Is the time delta identified as stuck? + * + * Output: + * updated hash context +@@ -104,17 +101,19 @@ static void jent_hash_time(struct rand_d + uint64_t loop_cnt, unsigned int stuck) + { + HASH_CTX_ON_STACK(ctx); +- uint8_t itermediary[SHA3_256_SIZE_DIGEST]; ++ uint8_t intermediary[SHA3_256_SIZE_DIGEST]; + uint64_t j = 0; +- uint64_t hash_loop_cnt; + #define MAX_HASH_LOOP 3 + #define MIN_HASH_LOOP 0 + + /* Ensure that macros cannot overflow jent_loop_shuffle() */ + BUILD_BUG_ON((MAX_HASH_LOOP + MIN_HASH_LOOP) > 63); +- hash_loop_cnt = ++ uint64_t hash_loop_cnt = + jent_loop_shuffle(ec, MAX_HASH_LOOP, MIN_HASH_LOOP); + ++ /* Use the memset to shut up valgrind */ ++ memset(intermediary, 0, sizeof(intermediary)); ++ + sha3_256_init(&ctx); + + /* +@@ -125,35 +124,54 @@ static void jent_hash_time(struct rand_d + hash_loop_cnt = loop_cnt; + + /* +- * This loop basically slows down the SHA-3 operation depending +- * on the hash_loop_cnt. Each iteration of the loop generates the +- * same result. ++ * This loop fills a buffer which is injected into the entropy pool. ++ * The main reason for this loop is to execute something over which we ++ * can perform a timing measurement. The injection of the resulting ++ * data into the pool is performed to ensure the result is used and ++ * the compiler cannot optimize the loop away in case the result is not ++ * used at all. Yet that data is considered "additional information" ++ * considering the terminology from SP800-90A without any entropy. ++ * ++ * Note, it does not matter which or how much data you inject, we are ++ * interested in one Keccack1600 compression operation performed with ++ * the sha3_final. + */ + for (j = 0; j < hash_loop_cnt; j++) { +- sha3_update(&ctx, ec->data, SHA3_256_SIZE_DIGEST); +- sha3_update(&ctx, (uint8_t *)&time, sizeof(uint64_t)); ++ sha3_update(&ctx, intermediary, sizeof(intermediary)); ++ sha3_update(&ctx, (uint8_t *)&ec->rct_count, ++ sizeof(ec->rct_count)); ++ sha3_update(&ctx, (uint8_t *)&ec->apt_cutoff, ++ sizeof(ec->apt_cutoff)); ++ sha3_update(&ctx, (uint8_t *)&ec->apt_observations, ++ sizeof(ec->apt_observations)); ++ sha3_update(&ctx, (uint8_t *)&ec->apt_count, ++ sizeof(ec->apt_count)); ++ sha3_update(&ctx,(uint8_t *) &ec->apt_base, ++ sizeof(ec->apt_base)); + sha3_update(&ctx, (uint8_t *)&j, sizeof(uint64_t)); ++ sha3_final(&ctx, intermediary); ++ } + +- /* +- * If the time stamp is stuck, do not finally insert the value +- * into the entropy pool. Although this operation should not do +- * any harm even when the time stamp has no entropy, SP800-90B +- * requires that any conditioning operation to have an identical +- * amount of input data according to section 3.1.5. +- */ ++ /* ++ * Inject the data from the previous loop into the pool. This data is ++ * not considered to contain any entropy, but it stirs the pool a bit. ++ */ ++ sha3_update(ec->hash_state, intermediary, sizeof(intermediary)); + +- /* +- * The sha3_final operations re-initialize the context for the +- * next loop iteration. +- */ +- if (stuck || (j < hash_loop_cnt - 1)) +- sha3_final(&ctx, itermediary); +- else +- sha3_final(&ctx, ec->data); +- } ++ /* ++ * Insert the time stamp into the hash context representing the pool. ++ * ++ * If the time stamp is stuck, do not finally insert the value into the ++ * entropy pool. Although this operation should not do any harm even ++ * when the time stamp has no entropy, SP800-90B requires that any ++ * conditioning operation to have an identical amount of input data ++ * according to section 3.1.5. ++ */ ++ if (!stuck) ++ sha3_update(ec->hash_state, (uint8_t *)&time, sizeof(uint64_t)); + + jent_memset_secure(&ctx, SHA_MAX_CTX_SIZE); +- jent_memset_secure(itermediary, sizeof(itermediary)); ++ jent_memset_secure(intermediary, sizeof(intermediary)); + } + + #define MAX_ACC_LOOP_BIT 7 +@@ -184,13 +202,12 @@ static inline uint32_t xoshiro128starsta + + static void jent_memaccess(struct rand_data *ec, uint64_t loop_cnt) + { +- uint64_t i = 0; ++ uint64_t i = 0, time = 0; + union { + uint32_t u[4]; + uint8_t b[sizeof(uint32_t) * 4]; + } prngState = { .u = {0x8e93eec0, 0xce65608a, 0xa8d46b46, 0xe83cef69} }; + uint32_t addressMask; +- uint64_t acc_loop_cnt; + + if (NULL == ec || NULL == ec->mem) + return; +@@ -199,7 +216,7 @@ static void jent_memaccess(struct rand_d + + /* Ensure that macros cannot overflow jent_loop_shuffle() */ + BUILD_BUG_ON((MAX_ACC_LOOP_BIT + MIN_ACC_LOOP_BIT) > 63); +- acc_loop_cnt = ++ uint64_t acc_loop_cnt = + jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT); + + /* +@@ -213,8 +230,10 @@ static void jent_memaccess(struct rand_d + * "per-update: timing, it gets you mostly independent "per-update" + * timing, so we can now benefit from the Central Limit Theorem! + */ +- for (i = 0; i < sizeof(prngState); i++) +- prngState.b[i] ^= ec->data[i]; ++ for (i = 0; i < sizeof(prngState); i++) { ++ jent_get_nstime_internal(ec, &time); ++ prngState.b[i] ^= (uint8_t)(time & 0xff); ++ } + + /* + * testing purposes -- allow test app to set the counter, not +@@ -358,21 +377,21 @@ unsigned int jent_measure_jitter(struct + + /** + * Generator of one 256 bit random number +- * Function fills rand_data->data ++ * Function fills rand_data->hash_state + * + * @ec [in] Reference to entropy collector + */ + void jent_random_data(struct rand_data *ec) + { +- unsigned int k = 0, safety_factor = ENTROPY_SAFETY_FACTOR; ++ unsigned int k = 0, safety_factor = 0; + +- if (!ec->fips_enabled) +- safety_factor = 0; ++ if (ec->fips_enabled) ++ safety_factor = ENTROPY_SAFETY_FACTOR; + + /* priming of the ->prev_time value */ + jent_measure_jitter(ec, 0, NULL); + +- while (1) { ++ while (!jent_health_failure(ec)) { + /* If a stuck measurement is received, repeat measurement */ + if (jent_measure_jitter(ec, 0, NULL)) + continue; +@@ -385,3 +404,22 @@ void jent_random_data(struct rand_data * + break; + } + } ++ ++void jent_read_random_block(struct rand_data *ec, char *dst, size_t dst_len) ++{ ++ uint8_t jent_block[SHA3_256_SIZE_DIGEST]; ++ ++ BUILD_BUG_ON(SHA3_256_SIZE_DIGEST != (DATA_SIZE_BITS / 8)); ++ ++ /* The final operation automatically re-initializes the ->hash_state */ ++ sha3_final(ec->hash_state, jent_block); ++ if (dst_len) ++ memcpy(dst, jent_block, dst_len); ++ ++ /* ++ * Stir the new state with the data from the old state - the digest ++ * of the old data is not considered to have entropy. ++ */ ++ sha3_update(ec->hash_state, jent_block, sizeof(jent_block)); ++ jent_memset_secure(jent_block, sizeof(jent_block)); ++} +Index: libgcrypt-1.9.4/random/jitterentropy-noise.h +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-noise.h ++++ libgcrypt-1.9.4/random/jitterentropy-noise.h +@@ -31,6 +31,7 @@ unsigned int jent_measure_jitter(struct + uint64_t loop_cnt, + uint64_t *ret_current_delta); + void jent_random_data(struct rand_data *ec); ++void jent_read_random_block(struct rand_data *ec, char *dst, size_t dst_len); + + #ifdef __cplusplus + } +Index: libgcrypt-1.9.4/random/jitterentropy-sha3.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-sha3.c ++++ libgcrypt-1.9.4/random/jitterentropy-sha3.c +@@ -19,6 +19,7 @@ + */ + + #include "jitterentropy-sha3.h" ++#include "jitterentropy.h" + + /*************************************************************************** + * Message Digest Implementation +@@ -380,3 +381,23 @@ int sha3_tester(void) + + return 0; + } ++ ++int sha3_alloc(void **hash_state) ++{ ++ struct sha_ctx *tmp; ++ ++ tmp = jent_zalloc(SHA_MAX_CTX_SIZE); ++ if (!tmp) ++ return 1; ++ ++ *hash_state = tmp; ++ ++ return 0; ++} ++ ++void sha3_dealloc(void *hash_state) ++{ ++ struct sha_ctx *ctx = (struct sha_ctx *)hash_state; ++ ++ jent_zfree(ctx, SHA_MAX_CTX_SIZE); ++} +Index: libgcrypt-1.9.4/random/jitterentropy-sha3.h +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-sha3.h ++++ libgcrypt-1.9.4/random/jitterentropy-sha3.h +@@ -47,6 +47,8 @@ struct sha_ctx { + void sha3_256_init(struct sha_ctx *ctx); + void sha3_update(struct sha_ctx *ctx, const uint8_t *in, size_t inlen); + void sha3_final(struct sha_ctx *ctx, uint8_t *digest); ++int sha3_alloc(void **hash_state); ++void sha3_dealloc(void *hash_state); + int sha3_tester(void); + + #ifdef __cplusplus +Index: libgcrypt-1.9.4/random/jitterentropy-timer.c +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-timer.c ++++ libgcrypt-1.9.4/random/jitterentropy-timer.c +@@ -202,8 +202,8 @@ int jent_notime_enable(struct rand_data + if (jent_force_internal_timer || (flags & JENT_FORCE_INTERNAL_TIMER)) { + /* Self test not run yet */ + if (!jent_force_internal_timer && +- jent_time_entropy_init(flags | JENT_FORCE_INTERNAL_TIMER, +- ec->osr)) ++ jent_time_entropy_init(ec->osr, ++ flags | JENT_FORCE_INTERNAL_TIMER)) + return EHEALTH; + + ec->enable_notime = 1; +Index: libgcrypt-1.9.4/random/jitterentropy.h +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy.h ++++ libgcrypt-1.9.4/random/jitterentropy.h +@@ -49,7 +49,7 @@ + ***************************************************************************/ + + /* +- * Enable timer-less timer support ++ * Enable timer-less timer support with JENT_CONF_ENABLE_INTERNAL_TIMER + * + * In case the hardware is identified to not provide a high-resolution time + * stamp, this option enables a built-in high-resolution time stamp mechanism. +@@ -166,7 +166,7 @@ struct rand_data + * of the RNG are marked as SENSITIVE. A user must not + * access that information while the RNG executes its loops to + * calculate the next random value. */ +- uint8_t data[SHA3_256_SIZE_DIGEST]; /* SENSITIVE Actual random number */ ++ void *hash_state; /* SENSITIVE hash state entropy pool */ + uint64_t prev_time; /* SENSITIVE Previous time stamp */ + #define DATA_SIZE_BITS (SHA3_256_SIZE_DIGEST_BITS) + +@@ -378,28 +379,34 @@ int jent_entropy_init(void); + JENT_PRIVATE_STATIC + int jent_entropy_init_ex(unsigned int osr, unsigned int flags); + ++/* ++ * Set a callback to run on health failure in FIPS mode. ++ * This function will take an action determined by the caller. ++ */ ++typedef void (*jent_fips_failure_cb)(struct rand_data *ec, ++ unsigned int health_failure); ++JENT_PRIVATE_STATIC ++int jent_set_fips_failure_callback(jent_fips_failure_cb cb); ++ + /* return version number of core library */ + JENT_PRIVATE_STATIC + unsigned int jent_version(void); + +-#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER + /* Set a different thread handling logic for the notimer support */ + JENT_PRIVATE_STATIC + int jent_entropy_switch_notime_impl(struct jent_notime_thread *new_thread); +-#endif + + /* -- END of Main interface functions -- */ + + /* -- BEGIN timer-less threading support functions to prevent code dupes -- */ + +-struct jent_notime_ctx { + #ifdef JENT_CONF_ENABLE_INTERNAL_TIMER ++ ++struct jent_notime_ctx { + pthread_attr_t notime_pthread_attr; /* pthreads library */ + pthread_t notime_thread_id; /* pthreads thread ID */ +-#endif + }; + +-#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER + + JENT_PRIVATE_STATIC + int jent_notime_init(void **ctx); +Index: libgcrypt-1.9.4/random/jitterentropy-base-user.h +=================================================================== +--- libgcrypt-1.9.4.orig/random/jitterentropy-base-user.h ++++ libgcrypt-1.9.4/random/jitterentropy-base-user.h +@@ -216,12 +216,12 @@ static inline void jent_get_cachesize(lo + ext = strstr(buf, "K"); + if (ext) { + shift = 10; +- ext = '\0'; ++ *ext = '\0'; + } else { + ext = strstr(buf, "M"); + if (ext) { + shift = 20; +- ext = '\0'; ++ *ext = '\0'; + } + } + diff --git a/libgcrypt-out-of-core-handler.patch b/libgcrypt-out-of-core-handler.patch new file mode 100644 index 0000000..07790da --- /dev/null +++ b/libgcrypt-out-of-core-handler.patch @@ -0,0 +1,12 @@ +Index: libgcrypt-1.9.4/src/global.c +=================================================================== +--- libgcrypt-1.9.4.orig/src/global.c ++++ libgcrypt-1.9.4/src/global.c +@@ -951,7 +951,6 @@ _gcry_set_outofcore_handler (int (*f)(vo + + if (fips_mode () ) + { +- log_info ("out of core handler ignored in FIPS mode\n"); + return; + } + diff --git a/libgcrypt-pthread-in-t-lock-test.patch b/libgcrypt-pthread-in-t-lock-test.patch new file mode 100644 index 0000000..34da2cb --- /dev/null +++ b/libgcrypt-pthread-in-t-lock-test.patch @@ -0,0 +1,13 @@ +Index: libgcrypt-1.9.3/tests/Makefile.am +=================================================================== +--- libgcrypt-1.9.3.orig/tests/Makefile.am ++++ libgcrypt-1.9.3/tests/Makefile.am +@@ -74,7 +74,7 @@ prime_LDADD = $(standard_ldadd) @LDADD_F + t_mpi_bit_LDADD = $(standard_ldadd) @LDADD_FOR_TESTS_KLUDGE@ + t_secmem_LDADD = $(standard_ldadd) @LDADD_FOR_TESTS_KLUDGE@ + testapi_LDADD = $(standard_ldadd) @LDADD_FOR_TESTS_KLUDGE@ +-t_lock_LDADD = $(standard_ldadd) $(GPG_ERROR_MT_LIBS) @LDADD_FOR_TESTS_KLUDGE@ ++t_lock_LDADD = $(standard_ldadd) $(GPG_ERROR_MT_LIBS) -lpthread @LDADD_FOR_TESTS_KLUDGE@ + t_lock_CFLAGS = $(GPG_ERROR_MT_CFLAGS) + testdrv_LDADD = $(LDADD_FOR_TESTS_KLUDGE) + diff --git a/libgcrypt-random_selftests-testentropy.patch b/libgcrypt-random_selftests-testentropy.patch new file mode 100644 index 0000000..17f968e --- /dev/null +++ b/libgcrypt-random_selftests-testentropy.patch @@ -0,0 +1,15 @@ +Index: libgcrypt-1.8.2/random/random-drbg.c +=================================================================== +--- libgcrypt-1.8.2.orig/random/random-drbg.c ++++ libgcrypt-1.8.2/random/random-drbg.c +@@ -2428,6 +2428,10 @@ drbg_healthcheck_sanity (struct gcry_drb + + /* if the following tests fail, it is likely that there is a buffer + * overflow and we get a SIGSEV */ ++ test_data.testentropy = &testentropy; ++ test_data.fail_seed_source = 0; ++ drbg_string_fill (&testentropy, test->entropy, test->entropylen); ++ drbg->test_data = &test_data; + ret = drbg_instantiate (drbg, NULL, coreref, 1); + if (ret) + goto outbuf; diff --git a/libgcrypt-rsa-no-blinding.patch b/libgcrypt-rsa-no-blinding.patch new file mode 100644 index 0000000..04d9ab0 --- /dev/null +++ b/libgcrypt-rsa-no-blinding.patch @@ -0,0 +1,92 @@ +--- libgcrypt-1.8.2.orig/cipher/rsa.c 2020-03-26 07:23:17.392861551 +0100 ++++ libgcrypt-1.8.2.orig/cipher/rsa.c 2020-03-26 15:43:29.556282072 +0100 +@@ -91,10 +91,16 @@ static const char sample_secret_key[] = + " 79C974A6FA69E4D52FE796650623DE70622862713932AA2FD9F2EC856EAEAA77" + " 88B4EA6084DC81C902F014829B18EA8B2666EC41586818E0589E18876065F97E" + " 8D22CE2DA53A05951EC132DCEF41E70A9C35F4ACC268FFAC2ADF54FA1DA110B919#)" ++"))"; ++/* We need to get rid of the u value, in order to end in ++ * secret_core_std when called from secret. It's not used anyway. */ ++ ++/* + " (u #67CF0FD7635205DD80FA814EE9E9C267C17376BF3209FB5D1BC42890D2822A04" + " 479DAF4D5B6ED69D0F8D1AF94164D07F8CD52ECEFE880641FA0F41DDAB1785E4" + " A37A32F997A516480B4CD4F6482B9466A1765093ED95023CA32D5EDC1E34CEE9" + " AF595BC51FE43C4BF810FA225AF697FB473B83815966188A4312C048B885E3F7#)))"; ++*/ + + /* A sample 2048 bit RSA key used for the selftests (public only). */ + static const char sample_public_key[] = +@@ -1252,8 +1258,8 @@ rsa_check_secret_key (gcry_sexp_t keypar + RSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL, NULL}; + + /* To check the key we need the optional parameters. */ +- rc = sexp_extract_param (keyparms, NULL, "nedpqu", +- &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u, ++ rc = sexp_extract_param (keyparms, NULL, "npq", ++ &sk.n, &sk.p, &sk.q, + NULL); + if (rc) + goto leave; +@@ -1263,11 +1269,8 @@ rsa_check_secret_key (gcry_sexp_t keypar + + leave: + _gcry_mpi_release (sk.n); +- _gcry_mpi_release (sk.e); +- _gcry_mpi_release (sk.d); + _gcry_mpi_release (sk.p); + _gcry_mpi_release (sk.q); +- _gcry_mpi_release (sk.u); + if (DBG_CIPHER) + log_debug ("rsa_testkey => %s\n", gpg_strerror (rc)); + return rc; +@@ -1710,11 +1713,11 @@ static const char * + selftest_sign_2048 (gcry_sexp_t pkey, gcry_sexp_t skey) + { + static const char sample_data[] = +- "(data (flags pkcs1)" ++ "(data (flags pkcs1 no-blinding)" + " (hash sha256 #11223344556677889900aabbccddeeff" + /**/ "102030405060708090a0b0c0d0f01121#))"; + static const char sample_data_bad[] = +- "(data (flags pkcs1)" ++ "(data (flags pkcs1 no-blinding)" + " (hash sha256 #11223344556677889900aabbccddeeff" + /**/ "802030405060708090a0b0c0d0f01121#))"; + +@@ -1857,7 +1860,7 @@ selftest_encr_2048 (gcry_sexp_t pkey, gc + gcry_mpi_t ref_mpi = NULL; + + /* Put the plaintext into an S-expression. */ +- err = sexp_build (&plain, NULL, "(data (flags raw) (value %s))", plaintext); ++ err = sexp_build (&plain, NULL, "(data (flags raw no-blinding) (value %s))", plaintext); + if (err) + { + errtxt = "converting data failed"; +@@ -1897,6 +1900,26 @@ selftest_encr_2048 (gcry_sexp_t pkey, gc + goto leave; + } + ++ /* This sexp trickery is to prevent the use of blinding. ++ * The flag doesn't get inherited by encr, so we have to ++ * derive a new sexp from the ciphertext */ ++ char buf[1024]; ++ memset(buf, 0, sizeof(buf)); ++ err = _gcry_mpi_print (GCRYMPI_FMT_STD, buf, sizeof buf, NULL, ciphertext); ++ if (err) ++ { ++ errtxt = "Dumping ciphertext mpi to buffer failed"; ++ goto leave; ++ } ++ ++ sexp_release (encr); ++ err = sexp_build (&encr, NULL, "(enc-val (flags no-blinding) (rsa (a %s)))", buf); ++ if (err) ++ { ++ errtxt = "Adding no-blinding flag to ciphertext failed"; ++ goto leave; ++ } ++ + /* Decrypt. */ + err = _gcry_pk_decrypt (&decr, encr, skey); + if (err) diff --git a/libgcrypt.changes b/libgcrypt.changes new file mode 100644 index 0000000..567d2c4 --- /dev/null +++ b/libgcrypt.changes @@ -0,0 +1,1106 @@ +* Thu Nov 24 2022 pmonreal@suse.com +- POWER10 performance enhancements for cryptography [jsc#PED-566] + * Backport upstream fixes: + - AES-GCM: Bulk implementation of AES-GCM acceleration for ppc64le + - hwf-ppc: fix missing HWF_PPC_ARCH_3_10 in HW feature + - Chacha20/poly1305: Optimized chacha20/poly1305 for P10 operation + * Add patches: + - libgcrypt-Bulk-implementation-of-AES-GCM-acceleration-ppc64le.patch + - libgcrypt-hwf-ppc-fix-missing-HWF_PPC_ARCH_3_10-in-HW-feature.patch + - libgcrypt-Optimized-chacha20-poly1305-for-P10-operation.patch +* Thu Sep 8 2022 pmonreal@suse.com +- FIPS: Get most of the entropy from rndjent_poll [bsc#1202117] + * Add libgcrypt-FIPS-rndjent_poll.patch +* Wed Sep 7 2022 pmonreal@suse.com +- FIPS: Check keylength in gcry_fips_indicator_kdf() [bsc#1190700] + * Consider approved keylength greater or equal to 112 bits. + * Add libgcrypt-FIPS-kdf-leylength.patch +* Wed Sep 7 2022 pmonreal@suse.com +- FIPS: Zeroize buffer and digest in check_binary_integrity() + * Add libgcrypt-FIPS-Zeroize-hmac.patch [bsc#1191020] +* Tue Aug 23 2022 pmonreal@suse.com +- FIPS: gpg/gpg2 gets out of core handler in FIPS mode while + typing Tab key to Auto-Completion. [bsc#1182983] + * Add libgcrypt-out-of-core-handler.patch +* Mon Aug 8 2022 pmonreal@suse.com +- FIPS: Port libgcrypt to use jitterentropy [bsc#1202117, jsc#SLE-24941] + * Enable the jitter based entropy generator by default in random.conf + - Add libgcrypt-jitterentropy-3.3.0.patch + * Update the internal jitterentropy to version 3.4.0 + - Add libgcrypt-jitterentropy-3.4.0.patch +* Thu Apr 14 2022 dennis.knorr@suse.com +- FIPS: extend the service indicator [bsc#1190700] + * introduced a pk indicator function + * adapted the approved and non approved ciphersuites + * Add libgcrypt_indicators_changes.patch + * Add libgcrypt-indicate-shake.patch +* Tue Mar 22 2022 pmonreal@suse.com +- FIPS: Implement a service indicator for asymmetric ciphers [bsc#1190700] + * Mark RSA public key encryption and private key decryption with + padding (e.g. OAEP, PKCS) as non-approved since RSA-OAEP lacks + peer key assurance validation requirements per SP800-56Brev2. + * Mark ECC as approved only for NIST curves P-224, P-256, P-384 + and P-521 with check for common NIST names and aliases. + * Mark DSA, ELG, EDDSA, ECDSA and ECDH as non-approved. + * Add libgcrypt-FIPS-SLI-pk.patch + * Rebase libgcrypt-FIPS-service-indicators.patch +- Run the regression tests also in FIPS mode. + * Disable tests for non-FIPS approved algos. + * Rebase: libgcrypt-FIPS-verify-unsupported-KDF-test.patch +* Tue Feb 1 2022 pmonreal@suse.com +- FIPS: Disable DSA in FIPS mode [bsc#1195385] + * Upstream task: https://dev.gnupg.org/T5710 + * Add libgcrypt-FIPS-disable-DSA.patch +* Wed Jan 19 2022 pmonreal@suse.com +- FIPS: Service level indicator [bsc#1190700] + * Provide an indicator to check wether the service utilizes an + approved cryptographic algorithm or not. + * Add patches: + - libgcrypt-FIPS-service-indicators.patch + - libgcrypt-FIPS-verify-unsupported-KDF-test.patch + - libgcrypt-FIPS-HMAC-short-keylen.patch +* Tue Dec 7 2021 pmonreal@suse.com +- FIPS: Fix gcry_mpi_sub_ui subtraction [bsc#1193480] + * gcry_mpi_sub_ui: fix subtracting from negative value + * Add libgcrypt-FIPS-fix-gcry_mpi_sub_ui.patch +* Tue Nov 30 2021 pmonreal@suse.com +- FIPS: Define an entropy source SP800-90B compliant [bsc#1185140] + * Disable jitter entropy by default in random.conf + * Disable only-urandom option by default in random.conf +* Fri Nov 26 2021 pmonreal@suse.com +- FIPS: RSA KeyGen/SigGen fail with 4096 bit key sizes [bsc#1192240] + * rsa: Check RSA keylen constraints for key operations. + * rsa: Fix regression in not returning an error for prime generation. + * tests: Add 2k RSA key working in FIPS mode. + * tests: pubkey: Replace RSA key to one of 2k. + * tests: pkcs1v2: Skip tests with small keys in FIPS. + * Add patches: + - libgcrypt-FIPS-RSA-keylen.patch + - libgcrypt-FIPS-RSA-keylen-tests.patch +* Mon Nov 8 2021 pmonreal@suse.com +- FIPS: Disable 3DES/Triple-DES in FIPS mode [bsc#1185138] + * Add libgcrypt-FIPS-disable-3DES.patch +* Tue Nov 2 2021 pmonreal@suse.com +- FIPS: PBKDF requirements [bsc#1185137] + * The PBKDF2 selftests were introduced in libgcrypt version + 1.9.1 in the function selftest_pbkdf2() + * Upstream task: https://dev.gnupg.org/T5182 +* Thu Oct 28 2021 pmonreal@suse.com +- FIPS: Fix regression tests in FIPS mode [bsc#1192131] + * Add libgcrypt-FIPS-fix-regression-tests.patch + * Upstream task: https://dev.gnupg.org/T5520 +* Tue Sep 21 2021 pmonreal@suse.com +- FIPS: Provide a module name/identifier and version that can be + mapped to the validation records. [bsc#1190706] + * Add libgcrypt-FIPS-module-version.patch + * Upstream task: https://dev.gnupg.org/T5600 +* Tue Sep 21 2021 pmonreal@suse.com +- FIPS: Enable hardware support also in FIPS mode [bsc#1187110] + * Add libgcrypt-FIPS-hw-optimizations.patch + * Upstream task: https://dev.gnupg.org/T5508 +* Mon Aug 23 2021 pmonreal@suse.com +- Update to 1.9.4: [jsc#SLE-17558, jsc#SLE-18135, jsc#SLE-20734] + * Bug fixes: + - Fix Elgamal encryption for other implementations. [CVE-2021-33560] + - Fix alignment problem on macOS. + - Check the input length of the point in ECDH. + - Fix an abort in gcry_pk_get_param for "Curve25519". + * Other features: + - Add GCM and CCM to OID mapping table for AES. + * Upstream libgcrypt-CVE-2021-33560-fix-ElGamal-enc.patch +* Mon Aug 23 2021 pmonreal@suse.com +- Remove not needed patch libgcrypt-sparcv9.diff +* Fri Jul 16 2021 pmonreal@suse.com +- libgcrypt 1.9.3: [jsc#SLE-17558, jsc#SLE-19413] + * Bug fixes: + - Fix build problems on i386 using gcc-4.7. + - Fix checksum calculation in OCB decryption for AES on s390. + - Fix a regression in gcry_mpi_ec_add related to certain usages + of curve 25519. + - Fix a symbol not found problem on Apple M1. + - Fix for Apple iOS getentropy peculiarity. + - Make keygrip computation work for compressed points. + * Performance: + - Add x86_64 VAES/AVX2 accelerated implementation of Camellia. + - Add x86_64 VAES/AVX2 accelerated implementation of AES. + - Add VPMSUMD acceleration for GCM mode on PPC. + * Internal changes. + - Harden MPI conditional code against EM leakage. + - Harden Elgamal by introducing exponent blinding. + * Remove libgcrypt-CVE-2021-33560-ElGamal-exponent-blinding.patch +* Thu Jul 15 2021 pmonreal@suse.com +- Fix building test t-lock with pthread. [bsc#1189745] + * Explicitly add -lpthread to compile the t-lock test. + * Add libgcrypt-pthread-in-t-lock-test.patch +* Fri Jun 11 2021 pmonreal@suse.com +- Security fix: [bsc#1187212, CVE-2021-33560] + * Libgcrypt mishandles ElGamal encryption because it lacks exponent + blinding to address a side-channel attack against mpi_powm +- Add patches: + * libgcrypt-CVE-2021-33560-ElGamal-exponent-blinding.patch + * libgcrypt-CVE-2021-33560-fix-ElGamal-enc.patch +* Tue Apr 13 2021 pmonreal@suse.com +- Upgrade to 1.9.2 in SLE-15-SP4 [jsc#SLE-17558, jsc#SLE-19413] +- Remove patches: + * CVE-2018-0495.patch + * libgcrypt-CVE-2019-13627.patch + * libgcrypt-AES-KW-fix-in-place-encryption.patch + * libgcrypt-ECDSA_check_coordinates_range.patch + * libgcrypt-check-re-open-dev_random-after-fork.patch +* Wed Feb 17 2021 andreas.stieger@gmx.de +- libgcrypt 1.9.2: + * Fix building with --disable-asm on x86 + * Check public key for ECDSA verify operation + * Make sure gcry_get_config (NULL) returns a nul-terminated + string + * Fix a memory leak in the ECDH code + * Fix a reading beyond end of input buffer in SHA2-avx2 +- remove obsolete texinfo packaging macros +* Tue Feb 2 2021 pmonreal@suse.com +- Update to 1.9.1 + * *Fix exploitable bug* in hash functions introduced with + 1.9.0. [bsc#1181632, CVE-2021-3345] + * Return an error if a negative MPI is used with sexp scan + functions. + * Check for operational FIPS in the random and KDF functions. + * Fix compile error on ARMv7 with NEON disabled. + * Fix self-test in KDF module. + * Improve assembler checks for better LTO support. + * Fix 32-bit cross build on x86. + * Fix non-NEON ARM assembly implementation for SHA512. + * Fix build problems with the cipher_bulk_ops_t typedef. + * Fix Ed25519 private key handling for preceding ZEROs. + * Fix overflow in modular inverse implementation. + * Fix register access for AVX/AVX2 implementations of Blake2. + * Add optimized cipher and hash functions for s390x/zSeries. + * Use hardware bit counting functionx when available. + * Update DSA functions to match FIPS 186-3. + * New self-tests for CMACs and KDFs. + * Add bulk cipher functions for OFB and GCM modes. +- Update libgpg-error required version +* Mon Feb 1 2021 pmonreal@suse.com +- Use the suffix variable correctly in get_hmac_path() +- Rebase libgcrypt-fips_selftest_trigger_file.patch +* Mon Jan 25 2021 pmonreal@suse.com +- Add the global config file /etc/gcrypt/random.conf + * This file can be used to globally change parameters of the random + generator with the options: only-urandom and disable-jent. +* Thu Jan 21 2021 pmonreal@suse.com +- Update to 1.9.0: + New stable branch of Libgcrypt with full API and ABI compatibility + to the 1.8 series. Release-info: https://dev.gnupg.org/T4294 + * New and extended interfaces: + - New curves Ed448, X448, and SM2. + - New cipher mode EAX. + - New cipher algo SM4. + - New hash algo SM3. + - New hash algo variants SHA512/224 and SHA512/256. + - New MAC algos for Blake-2 algorithms, the new SHA512 variants, + SM3, SM4 and for a GOST variant. + - New convenience function gcry_mpi_get_ui. + - gcry_sexp_extract_param understands new format specifiers to + directly store to integers and strings. + - New function gcry_ecc_mul_point and curve constants for Curve448 + and Curve25519. + - New function gcry_ecc_get_algo_keylen. + - New control code GCRYCTL_AUTO_EXPAND_SECMEM to allow growing the + secure memory area. + * Performance optimizations and bug fixes: See Release-info. + * Other features: + - Add OIDs from RFC-8410 as aliases for Ed25519 and Curve25519. + - Add mitigation against ECC timing attack CVE-2019-13627. + - Internal cleanup of the ECC implementation. + - Support reading EC point in compressed format for some curves. +- Rebase patches: + * libgcrypt-1.4.1-rijndael_no_strict_aliasing.patch + * libgcrypt-1.5.0-LIBGCRYPT_FORCE_FIPS_MODE-env.diff + * libgcrypt-1.6.1-use-fipscheck.patch + * drbg_test.patch + * libgcrypt-fipsdrv-enable-algo-for-dsa-sign.patch + * libgcrypt-FIPS-RSA-DSA-ECDSA-hashing-operation.patch + * libgcrypt-1.8.4-fips-keygen.patch + * libgcrypt-1.8.4-getrandom.patch + * libgcrypt-fix-tests-fipsmode.patch + * libgcrypt-global_init-constructor.patch + * libgcrypt-ecc-ecdsa-no-blinding.patch + * libgcrypt-PCT-RSA.patch + * libgcrypt-PCT-ECC.patch +- Remove patches: + * libgcrypt-unresolved-dladdr.patch + * libgcrypt-CVE-2019-12904-GCM-Prefetch.patch + * libgcrypt-CVE-2019-12904-GCM.patch + * libgcrypt-CVE-2019-12904-AES.patch + * libgcrypt-CMAC-AES-TDES-selftest.patch + * libgcrypt-1.6.1-fips-cfgrandom.patch + * libgcrypt-fips_rsa_no_enforced_mode.patch +* Sat Oct 24 2020 andreas.stieger@gmx.de +- libgcrypt 1.8.7: + * Support opaque MPI with gcry_mpi_print + * Fix extra entropy collection via clock_gettime, a fallback code + path for legacy hardware +* Tue Jul 7 2020 pmonrealgonzalez@suse.com +- Update to 1.8.6 + * mpi: Consider +0 and -0 the same in mpi_cmp + * mpi: Fix flags in mpi_copy for opaque MPI + * mpi: Fix the return value of mpi_invm_generic + * mpi: DSA,ECDSA: Fix use of mpi_invm + - Call mpi_invm before _gcry_dsa_modify_k + - Call mpi_invm before _gcry_ecc_ecdsa_sign + * mpi: Constant time mpi_inv with some conditions + - mpi/mpi-inv.c (mpih_add_n_cond, mpih_sub_n_cond, mpih_swap_cond) + - New: mpih_abs_cond, mpi_invm_odd + - Rename from _gcry_mpi_invm: mpi_invm_generic + - Use mpi_invm_odd for usual odd cases: _gcry_mpi_invm + * mpi: Abort on division by zero also in _gcry_mpi_tdiv_qr + * Fix wrong code execution in Poly1305 ARM/NEON implementation + - Set r14 to -1 at function entry: (_gcry_poly1305_armv7_neon_init_ext) + * Set vZZ.16b register to zero before use in armv8 gcm implementation + * random: Fix include of config.h + * Fix declaration of internal function _gcry_mpi_get_ui: Don't use ulong + * ecc: Fix wrong handling of shorten PK bytes + - Zeros are already recovered: (_gcry_ecc_mont_decodepoint) +- Update libgcrypt-ecc-ecdsa-no-blinding.patch +* Tue May 19 2020 pmonrealgonzalez@suse.com +- FIPS: RSA/DSA/ECC test_keys() print out debug messages [bsc#1171872] + * Print the debug messages in test_keys() only in debug mode. +- Update patches: libgcrypt-PCT-RSA.patch libgcrypt-PCT-DSA.patch + libgcrypt-PCT-ECC.patch +* Mon Apr 27 2020 pmonrealgonzalez@suse.com +- FIPS: libgcrypt: Double free in test_keys() on failed signature + verification [bsc#1169944] + * Use safer gcry_mpi_release() instead of mpi_free() +- Update patches: + * libgcrypt-PCT-DSA.patch + * libgcrypt-PCT-RSA.patch + * libgcrypt-PCT-ECC.patch +* Thu Apr 16 2020 vcizek@suse.com +- Ship the FIPS checksum file in the shared library package and + create a separate trigger file for the FIPS selftests (bsc#1169569) + * add libgcrypt-fips_selftest_trigger_file.patch + * refresh libgcrypt-global_init-constructor.patch +- Remove libgcrypt-binary_integrity_in_non-FIPS.patch obsoleted + by libgcrypt-global_init-constructor.patch +* Wed Apr 15 2020 pmonrealgonzalez@suse.com +- FIPS: Verify that the generated signature and the original input + differ in test_keys function for RSA, DSA and ECC: [bsc#1165539] +- Add zero-padding when qx and qy have different lengths when + assembling the Q point from affine coordinates. +- Refreshed patches: + * libgcrypt-PCT-DSA.patch + * libgcrypt-PCT-RSA.patch + * libgcrypt-PCT-ECC.patch +* Mon Mar 30 2020 pmonrealgonzalez@suse.com +- FIPS: Switch the PCT to use the new signature operation [bsc#1165539] + * Patches for DSA, RSA and ECDSA test_keys functions: + - libgcrypt-PCT-DSA.patch + - libgcrypt-PCT-RSA.patch + - libgcrypt-PCT-ECC.patch +- Update patch: libgcrypt-FIPS-RSA-DSA-ECDSA-hashing-operation.patch +* Thu Mar 26 2020 pmonrealgonzalez@suse.com +- FIPS: Fix drbg to be threadsafe [bsc#1167674] + * Detect fork and re-open devices in_gcry_rndlinux_gather_random + * libgcrypt-check-re-open-dev_random-after-fork.patch +* Thu Mar 26 2020 pmonrealgonzalez@suse.com +- FIPS: Run self-tests from constructor during power-on [bsc#1166748] + * Set up global_init as the constructor function: + - libgcrypt-global_init-constructor.patch + * Relax the entropy requirements on selftest. This is especially + important for virtual machines to boot properly before the RNG + is available: + - libgcrypt-random_selftests-testentropy.patch + - libgcrypt-rsa-no-blinding.patch + - libgcrypt-ecc-ecdsa-no-blinding.patch + * Fix benchmark regression test in FIPS mode: + - libgcrypt-FIPS-GMAC_AES-benckmark.patch +* Thu Mar 12 2020 pmonrealgonzalez@suse.com +- Remove check not needed in _gcry_global_constructor [bsc#1164950] + * Update libgcrypt-Restore-self-tests-from-constructor.patch +* Thu Mar 12 2020 pmonrealgonzalez@suse.com +- FIPS: Restore the full _gcry_global_constructor function to run + the self-test from the constructor [bsc#1164950] + * Add libgcrypt-Restore-self-tests-from-constructor.patch +* Tue Feb 25 2020 pmonrealgonzalez@suse.com +- FIPS: Run the self-tests from the constructor [bsc#1164950] + * Add libgcrypt-invoke-global_init-from-constructor.patch +* Mon Jan 20 2020 vcizek@suse.com +- ECDSA: Check range of coordinates (bsc#1161216) + * add libgcrypt-ECDSA_check_coordinates_range.patch +* Fri Jan 17 2020 pmonrealgonzalez@suse.com +- FIPS: libgcrypt DSA PQG parameter generation: Missing value [bsc#1161219] +- FIPS: libgcrypt DSA PQG verification incorrect results [bsc#1161215] +- FIPS: libgcrypt RSA siggen/keygen: 4k not supported [bsc#1161220] + * Add patch from Fedora libgcrypt-1.8.4-fips-keygen.patch +* Fri Jan 17 2020 pmonrealgonzalez@suse.com +- FIPS: keywrap gives incorrect results [bsc#1161218] + * Add libgcrypt-AES-KW-fix-in-place-encryption.patch +* Wed Dec 11 2019 pmonrealgonzalez@suse.com +- FIPS: RSA/DSA/ECDSA are missing hashing operation [bsc#1155337] + * Add libgcrypt-FIPS-RSA-DSA-ECDSA-hashing-operation.patch +* Wed Nov 27 2019 pmonrealgonzalez@suse.com +- Fix tests in FIPS mode: + * Fix tests: basic benchmark bench-slope pubkey t-cv25519 t-secmem + * Add patch libgcrypt-fix-tests-fipsmode.patch +* Tue Nov 26 2019 pmonrealgonzalez@suse.com +- Fix test dsa-rfc6979 in FIPS mode: + * Disable tests in elliptic curves with 192 bits which are not + recommended in FIPS mode + * Add patch libgcrypt-dsa-rfc6979-test-fix.patch +* Tue Nov 12 2019 pmonrealgonzalez@suse.com +- CMAC AES and TDES FIPS self-tests: + * CMAC AES self test missing [bsc#1155339] + * CMAC TDES self test missing [bsc#1155338] +- Add libgcrypt-CMAC-AES-TDES-selftest.patch +* Mon Sep 2 2019 pmonrealgonzalez@suse.com +- Security fix: [bsc#1148987,CVE-2019-13627] + * Mitigation against an ECDSA timing attack + * Added libgcrypt-CVE-2019-13627.patch +* Fri Aug 30 2019 andreas.stieger@gmx.de +- libgcrypt 1.8.5: + * CVE-2019-13627: mitigation against an ECDSA timing attack (boo#1148987) + * Improve ECDSA unblinding + * Provide a pkg-config file +* Wed Jul 31 2019 jsikes@suse.com +- Fixed an issue created by incomplete implementation of previous change - [bsc#1097073] + * Removed section of libgcrypt-binary_integrity_in_non-FIPS.patch + that caused some tests to be executed more than once. +* Thu Jul 18 2019 jsikes@suse.de +- Fixed a race condition in initialization. + * Added libgcrypt-1.8.4-allow_FSM_same_state.patch +* Tue Jul 2 2019 jsikes@suse.de +- Fixed redundant fips tests in some situations causing sudo to stop + working when pam-kwallet is installed. bsc#1133808 + * Added libgcrypt-1.8.4-fips_ctor_skip_integrity_check.patch + * Removed libgcrypt-fips_ignore_FIPS_MODULE_PATH.patch + because it was obsoleted by libgcrypt-1.8.4-fips_ctor_skip_integrity_check.patch +* Fri Jun 21 2019 pmonrealgonzalez@suse.com +- Fixed env-script-interpreter in cavs_driver.pl +* Fri Jun 21 2019 pmonrealgonzalez@suse.com +- Security fix: [bsc#1138939, CVE-2019-12904] + * The C implementation of AES is vulnerable to a flush-and-reload + side-channel attack because physical addresses are available to + other processes. (The C implementation is used on platforms where + an assembly-language implementation is unavailable.) + * Added patches: + - libgcrypt-CVE-2019-12904-GCM-Prefetch.patch + - libgcrypt-CVE-2019-12904-GCM.patch + - libgcrypt-CVE-2019-12904-AES.patch +* Fri Apr 26 2019 jsikes@suse.de +- do not try to open /dev/urandom if getrandom() works + * Added libgcrypt-1.8.4-getrandom.patch +- Drop libgcrypt-init-at-elf-load-fips.patch obsoleted + by libgcrypt-1.8.3-fips-ctor.patch +* Tue Apr 23 2019 jsikes@suse.de +- Restored libgcrypt-binary_integrity_in_non-FIPS.patch sans section that + was partially causing bsc#1131183. +- Fixed race condition in multi-threaded applications by allowing a FSM state + transition to the current state. This means some tests are run twice. + * Added libgcrypt-1.8.4-allow_FSM_same_state.patch +- Fixed an issue in malloc/free wrappers so that memory created by the malloc() + wrappers will be destroyed using the free() wrappers. + * Added libgcrypt-1.8.4-use_xfree.patch +* Mon Apr 15 2019 jsikes@suse.de +- remove section of libgcrypt-binary_integrity_in_non-FIPS.patch that caused + some tests to be executed twice. +* Fri Apr 5 2019 jsikes@suse.de +- removed libgcrypt-binary_integrity_in_non-FIPS.patch since it was breaking + libotr. bsc#1131183 +* Tue Mar 26 2019 vcizek@suse.com +- libgcrypt-1.8.3-fips-ctor.patch changed the way the fips selftests + are invoked as well as the state transition, adjust the code so + a missing checksum file is not an issue in non-FIPS mode (bsc#1097073) + * update libgcrypt-binary_integrity_in_non-FIPS.patch +* Tue Mar 26 2019 vcizek@suse.com +- Enforce the minimal RSA keygen size in fips mode (bsc#1125740) + * add libgcrypt-fips_rsa_no_enforced_mode.patch +* Fri Mar 22 2019 vcizek@suse.com +- Don't run full self-tests from constructor (bsc#1097073) + * Don't call global_init() from the constructor, _gcry_global_constructor() + from libgcrypt-1.8.3-fips-ctor.patch takes care of the binary + integrity check instead. + * Only the binary checksum will be verified, the remaining + self-tests will be run upon the library initialization +- Add libgcrypt-fips_ignore_FIPS_MODULE_PATH.patch +- Drop libgcrypt-init-at-elf-load-fips.patch and + libgcrypt-fips_run_selftest_at_constructor.patch obsoleted + by libgcrypt-1.8.3-fips-ctor.patch +* Thu Mar 7 2019 pmonrealgonzalez@suse.com +- Skip all the self-tests except for binary integrity when called + from the constructor (bsc#1097073) + * Added libgcrypt-1.8.3-fips-ctor.patch +* Wed Nov 28 2018 pmonrealgonzalez@suse.com +- Fail selftests when checksum file is missing in FIPS mode only + (bsc#1117355) + * add libgcrypt-binary_integrity_in_non-FIPS.patch +* Sun Oct 28 2018 astieger@suse.com +- libgcrypt 1.8.4: + * Fix infinite loop with specific application implementations + * Fix possible leak of a few bits of secret primes to pageable + memory + * Fix possible hang in the RNG (1.8.3) + * Always make use of getrandom if possible and then use + its /dev/urandom behaviour +* Mon Jul 2 2018 schwab@suse.de +- libgcrypt-1.6.3-aliasing.patch, libgcrypt-ppc64.patch, + libgcrypt-strict-aliasing.patch: Remove obsolete patches +- libgcrypt-1.4.1-rijndael_no_strict_aliasing.patch: Rediff +- Reenable testsuite +* Wed Jun 20 2018 psimons@suse.com +- Apply "CVE-2018-0495.patch" from upstream to enable blinding for + ECDSA signing. This change mitigates a novel side-channel attack. + [CVE-2018-0495, bsc#1097410] +* Wed Jun 13 2018 kbabioch@suse.com +- Update to version 1.8.3: + - Use blinding for ECDSA signing to mitigate a novel side-channel + attack. (CVE-2018-0495 bsc#1097410) + - Fix incorrect counter overflow handling for GCM when using an IV + size other than 96 bit. + - Fix incorrect output of AES-keywrap mode for in-place encryption + on some platforms. + - Fix the gcry_mpi_ec_curve_point point validation function. + - Fix rare assertion failure in gcry_prime_check. +- Applied spec-cleaner +* Wed May 2 2018 pmonrealgonzalez@suse.com +- Suggest libgcrypt20-hmac for package libgcrypt20 to ensure they + are installed in the right order. [bsc#1090766] +* Thu Mar 29 2018 pmonrealgonzalez@suse.com +- Extended the fipsdrv dsa-sign and dsa-verify commands with the + - -algo parameter for the FIPS testing of DSA SigVer and SigGen + (bsc#1064455). + * Added libgcrypt-fipsdrv-enable-algo-for-dsa-sign.patch + * Added libgcrypt-fipsdrv-enable-algo-for-dsa-verify.patch +* Thu Feb 22 2018 fvogt@suse.com +- Use %%license (boo#1082318) +* Wed Dec 13 2017 astieger@suse.com +- libgcrypt 1.8.2: + * Fix fatal out of secure memory status in the s-expression + parser on heavy loaded systems. + * Add auto expand secmem feature or use by GnuPG 2.2.4 +* Mon Aug 28 2017 astieger@suse.com +- libgcrypt 1.8.1: + * Mitigate a local side-channel attack on Curve25519 dubbed "May + the Fourth be With You" CVE-2017-0379 bsc#1055837 + * Add more extra bytes to the pool after reading a seed file + * Add the OID SHA384WithECDSA from RFC-7427 to SHA-384 + * Fix build problems with the Jitter RNG + * Fix assembler code build problems on Rasbian (ARMv8/AArch32-CE) +* Mon Jul 24 2017 jengelh@inai.de +- RPM group fixes. +* Fri Jul 21 2017 astieger@suse.com +- libgcrypt 1.8.0: + * New cipher mode XTS + * New hash function Blake-2 + * New function gcry_mpi_point_copy. + * New function gcry_get_config. + * GCRYCTL_REINIT_SYSCALL_CLAMP allows to init nPth after Libgcrypt. + * New gobal configuration file /etc/gcrypt/random.conf. + * GCRYCTL_PRINT_CONFIG does now also print build information for + libgpg-error and the used compiler version. + * GCRY_CIPHER_MODE_CFB8 is now supported. + * A jitter based entropy collector is now used in addition to the + other entropy collectors. + * Optimized gcry_md_hash_buffers for SHA-256 and SHA-512. + random pool lock). + * Interface changes relative to the 1.7.0 release: + gcry_get_config NEW function. + gcry_mpi_point_copy NEW function. + GCRYCTL_REINIT_SYSCALL_CLAMP NEW macro. + GCRY_MD_BLAKE2B_512 NEW constant. + GCRY_MD_BLAKE2B_384 NEW constant. + GCRY_MD_BLAKE2B_256 NEW constant. + GCRY_MD_BLAKE2B_160 NEW constant. + GCRY_MD_BLAKE2S_256 NEW constant. + GCRY_MD_BLAKE2S_224 NEW constant. + GCRY_MD_BLAKE2S_160 NEW constant. + GCRY_MD_BLAKE2S_128 NEW constant. + GCRY_CIPHER_MODE_XTS NEW constant. + gcry_md_info DEPRECATED. +- Refresh patch libgcrypt-1.6.3-aliasing.patch +* Thu Jun 29 2017 astieger@suse.com +- libgcrypt 1.7.8: + * CVE-2017-7526: Mitigate a flush+reload side-channel attack on + RSA secret keys (bsc#1046607) +* Sun Jun 4 2017 astieger@suse.com +- libgcrypt 1.7.7: + * Fix possible timing attack on EdDSA session key (previously + patched, drop libgcrypt-secure-EdDSA-session-key.patch) + * Fix long standing bug in secure memory implementation which + could lead to a segv on free +* Fri Jun 2 2017 pmonrealgonzalez@suse.com +- Added libgcrypt-secure-EdDSA-session-key.patch [bsc#1042326] + * Store the session key in secure memory to ensure that constant + time point operations are used in the MPI library. +* Fri Jan 20 2017 rmaliska@suse.com +- libgcrypt 1.7.6: + * Fix counter operand from read-only to read/write + * Fix too large jump alignment in mpih-rshift +* Thu Dec 15 2016 astieger@suse.com +- libgcrypt 1.7.5: + * Fix regression in mlock detection introduced with 1.7.4 +* Tue Dec 13 2016 astieger@suse.com +- libgcrypt 1.7.4: + * ARMv8/AArch32 performance improvements for AES, GCM, SHA-256, + and SHA-1. + * Add ARMv8/AArch32 assembly implementation for Twofish and + Camellia. + * Add bulk processing implementation for ARMv8/AArch32. + * Add Stribog OIDs. + * Improve the DRBG performance and sync the code with the Linux + version. + * When secure memory is requested by the MPI functions or by + gcry_xmalloc_secure, they do not anymore lead to a fatal error + if the secure memory pool is used up. Instead new pools are + allocated as needed. These new pools are not protected against + being swapped out (mlock can't be used). Mitigation for + minor confidentiality issues is encryption swap space. + * Fix GOST 28147 CryptoPro-B S-box. + * Fix error code handling of mlock calls. +* Sat Aug 20 2016 mpluskal,vcizek,astieger}@suse.com +- libgcrypt 1.7.3: + * security issue already fixes with 1.6.6 + * Fix building of some asm modules with older compilers and CPUs. + * ARMv8/AArch32 improvements for AES, GCM, SHA-256, and SHA-1. +- includes changes from libgcrypt 1.7.2: + * Bug fixes: + - Fix setting of the ECC cofactor if parameters are specified. + - Fix memory leak in the ECC code. + - Remove debug message about unsupported getrandom syscall. + - Fix build problems related to AVX use. + - Fix bus errors on ARM for Poly1305, ChaCha20, AES, and SHA-512. + * Internal changes: + - Improved fatal error message for wrong use of gcry_md_read. + - Disallow symmetric encryption/decryption if key is not set. +- includes changes from 1.7.1: + * Bug fixes: + - Fix ecc_verify for cofactor support. + - Fix portability bug when using gcc with Solaris 9 SPARC. + - Build fix for OpenBSD/amd64 + - Add OIDs to the Serpent ciphers. + * Internal changes: + - Use getrandom system call on Linux if available. + - Blinding is now also used for RSA signature creation. + - Changed names of debug envvars +- includes changes from 1.7.0: + * New algorithms and modes: + - SHA3-224, SHA3-256, SHA3-384, SHA3-512, and MD2 hash algorithms. + - SHAKE128 and SHAKE256 extendable-output hash algorithms. + - ChaCha20 stream cipher. + - Poly1305 message authentication algorithm + - ChaCha20-Poly1305 Authenticated Encryption with Associated Data + mode. + - OCB mode. + - HMAC-MD2 for use by legacy applications. + * New curves for ECC: + - Curve25519. + - sec256k1. + - GOST R 34.10-2001 and GOST R 34.10-2012. + * Performance: + - Improved performance of KDF functions. + - Assembler optimized implementations of Blowfish and Serpent on + ARM. + - Assembler optimized implementation of 3DES on x86. + - Improved AES using the SSSE3 based vector permutation method by + Mike Hamburg. + - AVX/BMI is used for SHA-1 and SHA-256 on x86. This is for SHA-1 + about 20%% faster than SSSE3 and more than 100%% faster than the + generic C implementation. + - 40%% speedup for SHA-512 and 72%% for SHA-1 on ARM Cortex-A8. + - 60-90%% speedup for Whirlpool on x86. + - 300%% speedup for RIPE MD-160. + - Up to 11 times speedup for CRC functions on x86. + * Other features: + - Improved ECDSA and FIPS 186-4 compliance. + - Support for Montgomery curves. + - gcry_cipher_set_sbox to tweak S-boxes of the gost28147 cipher + algorithm. + - gcry_mpi_ec_sub to subtract two points on a curve. + - gcry_mpi_ec_decode_point to decode an MPI into a point object. + - Emulation for broken Whirlpool code prior to 1.6.0. [from 1.6.1] + - Flag "pkcs1-raw" to enable PCKS#1 padding with a user supplied + hash part. + - Parameter "saltlen" to set a non-default salt length for RSA PSS. + - A SP800-90A conforming DRNG replaces the former X9.31 alternative + random number generator. + - Map deprecated RSA algo number to the RSA algo number for better + backward compatibility. [from 1.6.2] + - Use ciphertext blinding for Elgamal decryption [CVE-2014-3591]. + See http://www.cs.tau.ac.il/~tromer/radioexp/ for details. + [from 1.6.3] + - Fixed data-dependent timing variations in modular exponentiation + [related to CVE-2015-0837, Last-Level Cache Side-Channel Attacks + are Practical]. [from 1.6.3] + - Flag "no-keytest" for ECC key generation. Due to a bug in + the parser that flag will also be accepted but ignored by older + version of Libgcrypt. [from 1.6.4] + - Speed up the random number generator by requiring less extra + seeding. [from 1.6.4] + - Always verify a created RSA signature to avoid private key leaks + due to hardware failures. [from 1.6.4] + - Mitigate side-channel attack on ECDH with Weierstrass curves + [CVE-2015-7511]. See http://www.cs.tau.ac.IL/~tromer/ecdh/ for + details. [from 1.6.5] + * Internal changes: + - Moved locking out to libgpg-error. + - Support of the SYSROOT envvar in the build system. + - Refactor some code. + - The availability of a 64 bit integer type is now mandatory. + * Bug fixes: + - Fixed message digest lookup by OID (regression in 1.6.0). + - Fixed a build problem on NetBSD + - Fixed some asm build problems and feature detection bugs. + * Interface changes relative to the 1.6.0 release: + gcry_cipher_final NEW macro. + GCRY_CIPHER_MODE_CFB8 NEW constant. + GCRY_CIPHER_MODE_OCB NEW. + GCRY_CIPHER_MODE_POLY1305 NEW. + gcry_cipher_set_sbox NEW macro. + gcry_mac_get_algo NEW. + GCRY_MAC_HMAC_MD2 NEW. + GCRY_MAC_HMAC_SHA3_224 NEW. + GCRY_MAC_HMAC_SHA3_256 NEW. + GCRY_MAC_HMAC_SHA3_384 NEW. + GCRY_MAC_HMAC_SHA3_512 NEW. + GCRY_MAC_POLY1305 NEW. + GCRY_MAC_POLY1305_AES NEW. + GCRY_MAC_POLY1305_CAMELLIA NEW. + GCRY_MAC_POLY1305_SEED NEW. + GCRY_MAC_POLY1305_SERPENT NEW. + GCRY_MAC_POLY1305_TWOFISH NEW. + gcry_md_extract NEW. + GCRY_MD_FLAG_BUGEMU1 NEW [from 1.6.1]. + GCRY_MD_GOSTR3411_CP NEW. + GCRY_MD_SHA3_224 NEW. + GCRY_MD_SHA3_256 NEW. + GCRY_MD_SHA3_384 NEW. + GCRY_MD_SHA3_512 NEW. + GCRY_MD_SHAKE128 NEW. + GCRY_MD_SHAKE256 NEW. + gcry_mpi_ec_decode_point NEW. + gcry_mpi_ec_sub NEW. + GCRY_PK_EDDSA NEW constant. + GCRYCTL_GET_TAGLEN NEW. + GCRYCTL_SET_SBOX NEW. + GCRYCTL_SET_TAGLEN NEW. +- Apply libgcrypt-1.6.3-aliasing.patch only on big-endian + architectures +- update drbg_test.patch and install cavs testing directory again +- As DRBG is upstream, drop pateches: + v9-0001-SP800-90A-Deterministic-Random-Bit-Generator.patch + 0002-Compile-DRBG.patch + 0003-Function-definitions-of-interfaces-for-random.c.patch + 0004-Invoke-DRBG-from-common-libgcrypt-RNG-code.patch + 0005-Function-definitions-for-gcry_control-callbacks.patch + 0006-DRBG-specific-gcry_control-requests.patch + v9-0007-User-interface-to-DRBG.patch + libgcrypt-fix-rng.patch +- drop obsolete: + libgcrypt-fips-dsa.patch + libgcrypt-fips_ecdsa.patch +* Wed Aug 17 2016 astieger@suse.com +- libgcrypt 1.6.6: + * fix CVE-2016-6313: Issue in the mixing functions of the random + number generators allowed an attacker who obtained a number of + bytes from the standard RNG to predict some of the next ouput. + (bsc#994157) +* Mon May 16 2016 pjanouch@suse.de +- remove conditionals for unsupported distributions (before 13.2), + it would not build anyway because of new dependencies +* Mon May 16 2016 pjanouch@suse.de +- make the -hmac package depend on the same version of the library, + fixing bsc#979629 FIPS: system fails to reboot after installing + fips pattern +* Tue Feb 9 2016 astieger@suse.com +- update to 1.6.5: + * CVE-2015-7511: Mitigate side-channel attack on ECDH with + Weierstrass curves (boo#965902) +* Sat Oct 10 2015 astieger@suse.com +- follow-up to libgcrypt 1.6.4 update: sosuffix is 20.0.4 +* Tue Sep 8 2015 vcizek@suse.com +- update to 1.6.4 +- fixes libgcrypt equivalent of CVE-2015-5738 (bsc#944456) + * Speed up the random number generator by requiring less extra + seeding. + * New flag "no-keytest" for ECC key generation. Due to a bug in the + parser that flag will also be accepted but ignored by older version + of Libgcrypt. + * Always verify a created RSA signature to avoid private key leaks + due to hardware failures. + * Other minor bug fixes. +* Tue Jun 23 2015 dvaleev@suse.com +- Fix gpg2 tests on BigEndian architectures: s390x ppc64 + libgcrypt-1.6.3-aliasing.patch +* Sun Mar 1 2015 astieger@suse.com +- fix sosuffix for 1.6.3 (20.0.3) +* Sat Feb 28 2015 astieger@suse.com +- libgcrypt 1.6.3 [bnc#920057]: + * Use ciphertext blinding for Elgamal decryption [CVE-2014-3591]. + * Fixed data-dependent timing variations in modular exponentiation + [related to CVE-2015-0837, Last-Level Cache Side-Channel Attacks + are Practical]. +- update upstream signing keyring +* Fri Feb 6 2015 coolo@suse.com +- making the build reproducible - see + http://lists.gnupg.org/pipermail/gnupg-commits/2014-September/010683.html + for a very similiar problem +* Fri Feb 6 2015 dimstar@opensuse.org +- Move %%install_info_delete calls from postun to preun: the files + must still be present to be parsed. +- Fix the names passed to install_info for gcrypt.info-[12].gz + instead of gcrypt-[12].info.gz. +* Fri Feb 6 2015 coolo@suse.com +- fix filename for info pages in %%post scripts +* Wed Nov 5 2014 andreas.stieger@gmx.de +- libgcrypt 1.6.2: + * Map deprecated RSA algo number to the RSA algo number for better + backward compatibility. + * Support a 0x40 compression prefix for EdDSA. + * Improve ARM hardware feature detection and building. + * Fix building for the x32 ABI platform. + * Fix some possible NULL deref bugs. +- remove libgcrypt-1.6.0-use-intenal-functions.patch, upstream + via xtrymalloc macro +- remove libgcrypt-fixed-sizet.patch, upstream +- adjust libgcrypt-1.6.1-use-fipscheck.patch for xtrymalloc change +* Sun Sep 21 2014 vcizek@suse.com +- disabled curve P-192 in FIPS mode (bnc#896202) + * added libgcrypt-fips_ecdsa.patch +- don't use SHA-1 for ECDSA in FIPS mode +- also run the fips self tests only in FIPS mode +* Tue Sep 16 2014 vcizek@suse.com +- run the fips self tests at the constructor code + * added libgcrypt-fips_run_selftest_at_constructor.patch +* Tue Sep 16 2014 vcizek@suse.com +- rewrite the DSA-2 code to be FIPS 186-4 compliant (bnc#894216) + * added libgcrypt-fips-dsa.patch + * install fips186_dsa +- use 2048 bit keys in selftests_dsa +* Mon Sep 1 2014 vcizek@suse.com +- fix an issue in DRBG patchset + * size_t type is 32-bit on 32-bit systems +- fix a potential NULL pointer deference in DRBG patchset + * patches from https://bugs.g10code.com/gnupg/issue1701 +- added v9-0001-SP800-90A-Deterministic-Random-Bit-Generator.patch +- added v9-0007-User-interface-to-DRBG.patch +- removed v7-0001-SP800-90A-Deterministic-Random-Bit-Generator.patch +- removed v7-0007-User-interface-to-DRBG.patch +- add a subpackage for CAVS testing + * add cavs_driver.pl and cavs-test.sh from the kernel cavs package + * added drbg_test.patch +* Tue Aug 12 2014 meissner@suse.com +- split off the -hmac package that contains the checksums +* Mon May 26 2014 meissner@suse.com +- libgcrypt-fix-rng.patch: make drbg work again in FIPS mode. +- libgcrypt-1.6.1-use-fipscheck.patch: library to test is libgcrypt.so.20 + and not libgcrypt.so.11 +- libgcrypt-init-at-elf-load-fips.patch: initialize globally on ELF + DSO loading to meet FIPS requirements. +* Tue May 13 2014 vcizek@suse.com +- add new 0007-User-interface-to-DRBG.patch from upstream + * fixes bnc#877233 + * supersedes the patch from previous entry +* Mon May 12 2014 tittiatcoke@gmail.com +- Correct patch 0007-User-interface-to-DRBG.patch so that the + struct used in the route matches the header of the function +* Tue May 6 2014 vcizek@suse.com +- add support for SP800-90A DRBG (fate#316929, bnc#856312) + * patches by Stephan Mueller (http://www.chronox.de/drbg.html): + 0001-SP800-90A-Deterministic-Random-Bit-Generator.patch.bz2 + 0002-Compile-DRBG.patch + 0003-Function-definitions-of-interfaces-for-random.c.patch + 0004-Invoke-DRBG-from-common-libgcrypt-RNG-code.patch + 0005-Function-definitions-for-gcry_control-callbacks.patch + 0006-DRBG-specific-gcry_control-requests.patch + 0007-User-interface-to-DRBG.patch + * only after 13.1 (the patches need libgpg-error 1.13) +- drop libgcrypt-fips-allow-legacy.patch (not needed and wasn't + applied anyway) +* Thu Apr 3 2014 tchvatal@suse.com +- Cleanup with spec-cleaner to sort out. +- Really apply ppc64 patch as it was ommited probably by mistake. +* Thu Mar 27 2014 meissner@suse.com +- FIPS changes (from Fedora): + - replaced libgcrypt-1.5.0-etc_gcrypt_rngseed-symlink.diff by + libgcrypt-1.6.1-fips-cfgrandom.patch + - libgcrypt-fixed-sizet.patch: fixed an int type for -flto + - libgcrypt-1.6.1-use-fipscheck.patch: use the fipscheck binary + - libgcrypt-1.6.1-fips-cavs.patch: add CAVS tests +- use fipscheck only after 13.1 +- libgcrypt-fips-allow-legacy.patch: attempt to allow some + legacy algorithms for gpg2 usage even in FIPS mode. + (currently not applied) +* Thu Jan 30 2014 idonmez@suse.com +- Drop arm-missing-files.diff, fixed upstream +* Wed Jan 29 2014 andreas.stieger@gmx.de +- libgcrypt 1.6.1, a bugfix release with the folloging fixes: + * Added emulation for broken Whirlpool code prior to 1.6.0. + * Improved performance of KDF functions. + * Improved ECDSA compliance. + * Fixed message digest lookup by OID (regression in 1.6.0). + * Fixed memory leaks in ECC code. + * Fixed some asm build problems and feature detection bugs. + * Interface changes relative to the 1.6.0 release: + GCRY_MD_FLAG_BUGEMU1 NEW (minor API change). +* Fri Jan 3 2014 dmueller@suse.com +- add arm-missing-files.diff: Add missing files to fix build +* Fri Jan 3 2014 mvyskocil@suse.com +- fix bnc#856915: can't open /dev/urandom + * correct libgcrypt-1.5.0-etc_gcrypt_rngseed-symlink.diff +- require libgpg-error 1.11 or higher +* Thu Dec 19 2013 mvyskocil@suse.com +- fix dependency for 32bit devel package +- name hmac files according soname +- fix hmac subpackage dependency +* Thu Dec 19 2013 mvyskocil@suse.com +- update to 1.6. + * Removed the long deprecated gcry_ac interface. Thus Libgcrypt is + not anymore ABI compatible to previous versions if they used the ac + interface. Check NEWS in libgcrypt-devel for removed interfaces. + * Removed the module register subsystem. + * The deprecated message digest debug macros have been removed. Use + gcry_md_debug instead. + * Removed deprecated control codes. + * Improved performance of most cipher algorithms as well as for the + SHA family of hash functions. + * Added support for the IDEA cipher algorithm. + * Added support for the Salsa20 and reduced Salsa20/12 stream ciphers. + * Added limited support for the GOST 28147-89 cipher algorithm. + * Added support for the GOST R 34.11-94 and R 34.11-2012 (Stribog) + hash algorithms. + * Added a random number generator to directly use the system's RNG. + Also added an interface to prefer the use of a specified RNG. + * Added support for the SCRYPT algorithm. + * Mitigated the Yarom/Falkner flush+reload side-channel attack on RSA + secret keys. See [CVE-2013-4242]. + * Added support for Deterministic DSA as per RFC-6969. + * Added support for curve Ed25519. + * Added a scatter gather hash convenience function. + * Added several MPI amd SEXP helper functions. + * Added support for negative numbers to gcry_mpi_print, + gcry_mpi_aprint and gcry_mpi_scan. + * The algorithm ids GCRY_PK_ECDSA and GCRY_PK_ECDH are now + deprecated. Use GCRY_PK_ECC if you need an algorithm id. + * Changed gcry_pk_genkey for "ecc" to only include the curve name and + not the parameters. The flag "param" may be used to revert this. + * Added a feature to globally disable selected hardware features. + * Added debug helper functions. +- rebased patches + * libgcrypt-1.5.0-etc_gcrypt_rngseed-symlink.diff + * libgcrypt-ppc64.patch +- add libgcrypt-1.6.0-use-intenal-functions.patch to fix fips.c build +- Move all documentation to -devel package +* Fri Jul 26 2013 andreas.stieger@gmx.de +- update to 1.5.3 [bnc#831359] CVE-2013-4242 + * Mitigate the Yarom/Falkner flush+reload side-channel attack on + RSA secret keys. See . +* Thu Jul 25 2013 mvyskocil@suse.com +- port SLE enhancenments to Factory (bnc#831028) + * add libgcrypt-unresolved-dladdr.patch (bnc#701267) + * add libgcrypt-1.5.0-etc_gcrypt_rngseed-symlink.diff (bnc#724841) + * add libgcrypt-1.5.0-LIBGCRYPT_FORCE_FIPS_MODE-env.diff +- install .hmac256.hmac (bnc#704068) +- enable varuous new options in configure (m-guard, hmac binary check and + random device linux) +- build with all ciphers, pubkeys and digest by default as whitelist + simply allowed them all +* Mon Jun 17 2013 coolo@suse.com +- avoid gpg-offline in bootstrap packages +* Sun Jun 16 2013 crrodriguez@opensuse.org +- Library must be built with large file support in + 32 bit archs. +* Thu Apr 18 2013 andreas.stieger@gmx.de +- update to 1.5.2 + * The upstream sources now contain the IDEA algorithm, dropping: + idea.c.gz + libgcrypt-1.5.0-idea.patch + libgcrypt-1.5.0-idea_codecleanup.patch + * Made the Padlock code work again (regression since 1.5.0). + * Fixed alignment problems for Serpent. + * Fixed two bugs in ECC computations. +* Fri Mar 22 2013 mvyskocil@suse.com +- add GPL3.0+ to License tag because of dumpsexp (bnc#810759) +* Mon Mar 18 2013 andreas.stieger@gmx.de +- update to 1.5.1 + * Allow empty passphrase with PBKDF2. + * Do not abort on an invalid algorithm number in + gcry_cipher_get_algo_keylen and gcry_cipher_get_algo_blklen. + * Fixed some Valgrind warnings. + * Fixed a problem with select and high fd numbers. + * Improved the build system + * Various minor bug fixes. + * Interface changes relative to the 1.5.0 release: + GCRYCTL_SET_ENFORCED_FIPS_FLAG NEW. + GCRYPT_VERSION_NUMBER NEW. +- add verification of source code signatures +- now requires automake 1.11 to build +* Sat Feb 2 2013 coolo@suse.com +- update license to new format +* Tue Jun 12 2012 chris@computersalat.de +- fix deps + * libgpg-error-devel >= 1.8 +- add libsoname macro +* Sun Feb 12 2012 crrodriguez@opensuse.org +- Libraries back into %%{_libdir}, /usr merge project +* Sat Dec 24 2011 opensuse@dstoecker.de +- add the missing IDEA algorithm after the patent is no longer relevant +* Sun Nov 13 2011 jengelh@medozas.de +- Remove redundant/unwanted tags/section (cf. specfile guidelines) +* Sun Nov 13 2011 coolo@suse.com +- add libtool as explicit buildrequire to avoid implicit dependency from prjconf +* Sun Oct 2 2011 crrodriguez@opensuse.org +- Update to version 1.5.0, most important changes + * Uses the Intel AES-NI instructions if available + * Support ECDH. +* Fri Nov 19 2010 mvyskocil@suse.cz +- update to 1.4.6 + * Fixed minor memory leak in DSA key generation. + * No more switching to FIPS mode if /proc/version is not readable. + * Fixed a sigill during Padlock detection on old CPUs. + * Boosted SHA-512 performance by 30%% on ia32 boxes and gcc 4.3; + SHA-256 went up by 25%%. + * New variants of the TIGER algorithm. + * New cipher algorithm mode for AES-WRAP. + * Interface changes relative to the 1.4.2 release: + GCRY_MD_TIGER1 NEW + GCRY_MD_TIGER2 NEW + GCRY_CIPHER_MODE_AESWRAP NEW +* Sun Jul 4 2010 jengelh@medozas.de +- add missing definition of udiv_qrnnd for sparcv9:32 +- use %%_smp_mflags +* Sat Dec 19 2009 jengelh@medozas.de +- add baselibs.conf as a source +- disable the use of hand-coded assembler functions on sparc - + this is giving me an infinite loop with ./tests/prime + (specifically ./sparc32v8/mpih-mul1.S:_gcry_mpih_mul_1. + Fedora disables this too. +* Tue Apr 7 2009 crrodriguez@suse.de +- update to version 1.4.4 + * Publish GCRY_MODULE_ID_USER and GCRY_MODULE_ID_USER_LAST constants. + This functionality has been in Libgcrypt since 1.3.0. + * MD5 may now be used in non-enforced fips mode. + * Fixed HMAC for SHA-384 and SHA-512 with keys longer than 64 bytes. + * In fips mode, RSA keys are now generated using the X9.31 algorithm + and DSA keys using the FIPS 186-2 algorithm. + * The transient-key flag is now also supported for DSA key + generation. DSA domain parameters may be given as well. +* Thu Jan 29 2009 olh@suse.de +- obsolete libgcrypt-error-XXbit in the library subpackage +* Wed Dec 10 2008 olh@suse.de +- use Obsoletes: -XXbit only for ppc64 to help solver during distupgrade + (bnc#437293) +* Tue Nov 11 2008 mkoenig@suse.de +- build rijndael.c with -fno-strict-aliasing [bnc#443693] +* Thu Oct 30 2008 olh@suse.de +- obsolete old -XXbit packages (bnc#437293) +* Mon Jun 30 2008 mkoenig@suse.de +- update to version 1.4.1 + * Fixed a bug which led to the comsumption of far too much + entropy for the intial seeding + * Improved AES performance for CFB and CBC modes +* Sun May 11 2008 coolo@suse.de +- fix rename of xxbit packages +* Thu Apr 10 2008 ro@suse.de +- added baselibs.conf file to build xxbit packages + for multilib support +* Thu Jan 17 2008 mkoenig@suse.de +- update to version 1.4.0: + * The entire library is now under the LGPL. The helper programs and + the manual are under the GPL + * New control code GCRYCTL_PRINT_CONFIG + * Experimental support for ECDSA + * Assembler support for the AMD64 architecture + * Non executable stack support is now used by default + * New configure option --enable-random-daemon + * The new function gcry_md_debug should be used instead of the + gcry_md_start_debug and gcry_md_stop_debug macros. + * Support for DSA2 + * Reserved algorithm ranges for use by applications + * gcry_mpi_rshift does not anymore truncate the shift count + * Support for OFB encryption mode + * Support for the Camellia cipher + * Support for the SEED cipher + * Support for SHA-224 and HMAC using SHA-384 and SHA-512 + * Reading and writing the random seed file is now protected by a + fcntl style file lock + * Made the RNG immune against fork without exec + * Changed the way the RNG gets initialized + * The ASN.1 DER template for SHA-224 has been fixed + * The ACE engine of VIA processors is now used for AES-128 +- changed package layout to conform shlib policy: + new subpackage libgcrypt11 +- disable static library +- for reference: bugzilla entry of last change #304749 +* Wed Sep 12 2007 ltinkl@suse.cz +- add sanity check for mpi of size 0 (#304479) +* Mon Feb 5 2007 mkoenig@suse.de +- update to version 1.2.4: + * Fixed a bug in the memory allocator which could have been the + reason for some of non-duplicable bugs. + * Other minor bug fixes. +* Wed Dec 13 2006 mkoenig@suse.de +- get rid of .la file and fix devel so link +* Tue Dec 5 2006 mkoenig@suse.de +- move shared lib to /%%_lib +* Thu Aug 31 2006 mkoenig@suse.de +- update to version 1.2.3: + * Rewrote gcry_mpi_rshift to allow arbitrary shift counts. + * Minor bug fixes. +- added libgpg-error-devel and glibc-devel to Requires tag + of devel subpackage +* Wed Jan 25 2006 mls@suse.de +- converted neededforbuild to BuildRequires +* Wed Nov 2 2005 hvogel@suse.de +- enable noexecstack +- build ac.c with fno-strict-aliasing +* Tue Oct 25 2005 hvogel@suse.de +- update to version 1.2.2 +* Thu Jun 23 2005 hvogel@suse.de +- call install_info macro in post/postun of the devel package +- depend on libgcrypt +- add clean section +* Tue Jan 18 2005 hvogel@suse.de +- update to version 1.2.1 +* Tue Jan 11 2005 schwab@suse.de +- Fix info dir entry. +* Wed Nov 17 2004 hvogel@suse.de +- require libgpg-error-devel (Bug #48271) +- get rid of the NLD parts +* Wed Jul 14 2004 adrian@suse.de +- create -devel subpackage +- prepare for nld +* Wed May 19 2004 hvogel@suse.de +- update to version 1.2.0 +* Mon Mar 22 2004 meissner@suse.de +- disable make check, because it uses /dev/random whihc is + not filled on some server machines. +* Wed Mar 17 2004 meissner@suse.de +- fixed too over enthusiastic powerpc switches to make it work + on ppc64. (It compiled before, but did not work). +- enabled make check. +* Wed Feb 18 2004 kukuk@suse.de +- Build against system pthread library, not pth. +* Tue Feb 17 2004 hvogel@suse.de +- update to version 1.1.91 +- fix autoconf quotations +* Sat Jan 10 2004 adrian@suse.de +- add %%run_ldconfig to %%postun +* Sun Jul 27 2003 poeml@suse.de +- add libgcrypt-1.1.12-sexp-valgrind-error.patch from SLEC +* Thu Apr 24 2003 ro@suse.de +- fix install_info --delete call and move from preun to postun +* Mon Feb 10 2003 mmj@suse.de +- Use %%install_info macro [#23433] +* Mon Feb 10 2003 mc@suse.de +- switch to version 1.1.12 +- gcry_pk_sign, gcry_pk_verify and gcry_pk_encrypt can now handle an + optional pkcs1 flags parameter in the S-expression. A similar flag + may be passed to gcry_pk_decrypt but it is only syntactically + implemented. +- New convenience macro gcry_md_get_asnoid. +- There is now some real stuff in the manual. +- New algorithm: MD4 +- Implemented ciphertext stealing. +- Support for plain old DES +- Smaller bugs fixes and a few new OIDs. +* Tue Jan 14 2003 nadvornik@suse.cz +- fixed multi-line string literals +* Thu Aug 1 2002 poeml@suse.de +- create package diff --git a/libgcrypt.keyring b/libgcrypt.keyring new file mode 100644 index 0000000..3f00d96 --- /dev/null +++ b/libgcrypt.keyring @@ -0,0 +1,65 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQENBE0ti4EBCACqGtKlX9jI/enhlBdy2cyQP6Q7JoyxtaG6/ckAKWHYrqFTQk3I +Ue8TuDrGT742XFncG9PoMBfJDUNltIPgKFn8E9tYQqAOlpSA25bOb30cA2ADkrjg +jvDAH8cZ+fkIayWtObTxwqLfPivjFxEM//IdShFFVQj+QHmXYBJggWyEIil8Bje7 +KRw6B5ucs4qSzp5VH4CqDr9PDnLD8lBGHk0x8jpwh4V/yEODJKATY0Vj00793L8u +qA35ZiyczUvvJSLYvf7STO943GswkxdAfqxXbYifiK2gjE/7SAmB+2jFxsonUDOB +1BAY5s3FKqrkaxZr3BBjeuGGoCuiSX/cXRIhABEBAAG0Fldlcm5lciBLb2NoIChk +aXN0IHNpZymJAVUEEwEIAD8CGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAFiEE +2GkhI8QGXepeDzq1JJs50k8l47YFAl4MxBkFCRShVzYACgkQJJs50k8l47YImQf9 +HaqHWor+aSmaEwQnaAN0zRa4kPbAWya182aJtsFzLZJf6BbS0aoiMhwtREN/DMvB +jzxARKep/cELaM+mc7oDK4mEwqSX/u6BE8D7FaNA9sut8P+4xjpoLPU+UzILMg29 +t1remjyT9rs6sbu8BqufIxueArkjoi4WCOSRiVTdw+YDd88volPkXlPfS8hg9Rct +wZ8kEEDywa+NrxiLx+kDgDNTNdk3PJdfcnesf8S1a+KLUTNRds5+xGTYz0JSQ9BZ +7Q9r4VQ/NL55muQZi5W7lVxdp3HxQFUNjHzzBfGtkpS4xqZpJvNjW50Wh5Vi5RYZ +LZ3M1EuIHXHmRiY4dmqqcpkBDQRUUDsjAQgA5hBwN9F3OqKf+9mXCXUDK4lb5wMj +dti96xG04gAn7wWo7On6c5ntriZQuRdR5GHcdw73XC6CFehHeo/eSVYiWqBNBAfE +9UzbkES+cY+4wDzqVacqhKxd70XmHQgyK7ppRG/MwkL1UyArCGGAKN6MV/2fzO6I +GQw3jntRue3/2PGGnGaisNAKlvttHWZ91uy4KY5fBM19uQCgZdx4v8/rP0+yQqsW +TwJUKvymx5GIfNaCJvgF+v+aPrwspxBMf9jpHXqDXnh4Lo8C/GsQMD6GClVfQjsv +vzUHKH2eoL4oNfku+Ua5BuAHYi+uAuzqV9TdpF9PCpQMyPfuuZclMPLdMwARAQAB +tDJOSUlCRSBZdXRha2EgKEdudVBHIFJlbGVhc2UgS2V5KSA8Z25paWJlQGZzaWou +b3JnPokBPAQTAQgAJgIbAwULBwgJAwQVCAkKBRYCAwEAAh4BAheABQJYDxRZBQkL +S5A2AAoJECBxsIozvT8GvG8IAMBIlGz9voYcSSXAdQOuvz2gM2kOjvMHzN6VlS9V +P06IjnTz2DnejFZwLmxJw8e8mZjUo0jw22uo1HREQhDrne3S1IazPMeTUCUNzpWF +MxXNc6SAyrw9apWa8gouGUWJv3HOwVs8EFA2E9UdtDJ2uG7MY/+eC5K/aeOAyudZ +EbvS8rgZypTFrBtBcNKUWZhz7FRn63HxEmYLE3p6I19ZDXrc1WTazF2oz18zym6c +uURr6waRbdSemUTshpLnKCBZXzJ82bXBgXNnfdmc3gtS24ZmM3ZfK/rYztEDkiTk +s2R1gwDwf5RtDpaf5LD2ufESdbLuT+8blAlscbgYLBcwDquZAY0EWMu6rgEMAKcz +vM1IhpUwBpxPCNdrlMZh7XeLqKUd7hUvQ1KHOuDONxCDnfXdxGCKKI0Ds5I7Kkyp +Wzvcl7PplRy2fYZWwcGtL+Kj01y4L2lXB/xrrVaVwRr4S0FrcbseUGYRafBpR0C1 +Yo24CL1ef4ivsfbER2SyaZ3lrT9Ccv6xfvTluhU8X+2li1ssak/Frvy02u3EORLD +LxaaLQgANgsjnIjv/JQZ4l3xFIJT98tEoL18btg5lGrS2w4yFU1aa1SNsbp7vcu7 +wsqcJmCzX98LyG8/IBGJ5JXmZ03yzWhZ3uhhy1+Avi4GV4Mi0ADwaGMp6O63Mc3w +SL8A/DoCKJLISOc+D5xNfw6C8sYlaOSzQfqY9l4HW/+QbJmEFL2+bnjSHb8yaVU3 +ae2IIrlNkZ5Jamp12Kq6x9Vei0xGk3gd4sqhmHhECdxoJtkX9L5gt436QxdjiTcW +q3V+NNfq94UJu2Ej2kN0fNT0t9RU2n0P/mS0L+1gw5Ex6BX7BIzGL0bZhYomQwAR +AQABiQHOBB8BCAA4FiEEW4DFdUKY8MtV2O1qvO9+KUsJLigFAljLwN0XDIABlKXJ +oDwv5co7CV2OH99yPPRitrECBwAACgkQvO9+KUsJLig2Cgv/T4rXEjHwlbsuTkzp +tgK80Dh92URzBAhPhSJ0kUz2b6y7FgVYgZ95u8elGUS4lOB0GOQSK3y4sCgldTQF +GQpMuvNMX6oNQTv1Z/H9H7Sc6AntozKRA6LQC+7DMxjPh2DEhVLYNqi7gMXtuH8o +Xz5+quarw/xbVmuS4UNqcxakd4A/HW6PayRhuju4+oV2+UmGU0etzGVwKSN/UicC +3Re3mUy8SwJFQ9/3EAfiY0SGzSWH1z7bTRg9Ga2ctYDNzUpyQsgLxD6ZRHcONkOo +GUMEQ96BeSsjT4yW9ED70CcCbhg+pMxR+lnpk4BZ4WML/plBjEb8B1YaRvhYWKd3 +OSVB/JsS6J6Q/y9TTsAJDBLAfw9h7RQKibViuVFSNftAuSdktah5mDwFnL0ZMzVS +3tDVDa5PDqbHEhK55/5EWBg4eNbAukVZmmoLzzERGXuj+LOIRElG3/n3chy1uM73 +B6da3al4gDDNHifPsuozpkVN1EAROZx1K9hGGDZC3yFQTjsJtCRBbmRyZSBIZWlu +ZWNrZSAoUmVsZWFzZSBTaWduaW5nIEtleSmJAdQEEwEIAD4WIQRbgMV1Qpjwy1XY +7Wq8734pSwkuKAUCWMu6rgIbAwUJEswDAAULCQgHAgYVCAkKCwIEFgIDAQIeAQIX +gAAKCRC8734pSwkuKEL9DACEIL5IS9wUty62Bnwd9wK2hmwihXNkTLsOOoi8aCdO +ywPwcIucgAcIO+c/t0lbe4y4sJ1KrKbdyOUQiJAyxobLCSV/MkhIDAmsZB1ZIpF3 +nfmNekRdCVcMpqX8jAwoBS3Q9m2UJz1LeDCLFCvLF0nbyUnqHZP19UOvxmzAyZMA +Ub3W5y1+GMo4yA+3xSFI8ZbjzhawixCCRs69/4p+zCXR4e7LBf6koAHllD/0ZULp +SDjF+t2IkvRrMlM+e+Mxjklinr8v1FRGzmE/kCcdHaP88+iwC2wUKOZtFs4yIBLO +SWdQk9tLPmR8uWgNZmatRJyNvOaxd6EbK3jfckbJGFkmXjH+M9vMqFpoAewZ359F +qjq+Us7AXLAMNUynom7IrtR5Rvsjx6RNtKQYUD6XY5rc7r9js9iGruHDAAW5lyRg +j3wikc0IbV9L1bTsXIp29BsrU9sXUkVEp+xQJZgwqoOduoSjmOK88QdkibDqJiGF +dzIRiXx+Nxv1Pr9L7A4/tq+YMwRfQ+WJFgkrBgEEAdpHDwEBB0DPvkeV6RzXomGF +8jQwp0RXEt2TGFwwI7RkbpYwECY2l7QfV2VybmVyIEtvY2ggKGRpc3Qgc2lnbmlu +ZyAyMDIwKYiaBBMWCgBCFiEEbapuZKdtKEBXG0kCUoiXuCZAOtoFAl9D7DUCGwMF +CRKFxxEFCwkIBwIDIgIBBhUKCQgLAgQWAgMBAh4HAheAAAoJEFKIl7gmQDraea4A +/24v8c50HSC/Basf4WlREkuzhudplo8iT0BGtTQRdGAmAP9gIZ8dBekg9PRlpe7A +l7ErThn6owVH9szWrUt6jkKOBg== +=h7e4 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/libgcrypt.spec b/libgcrypt.spec new file mode 100644 index 0000000..74f9104 --- /dev/null +++ b/libgcrypt.spec @@ -0,0 +1,289 @@ +# +# spec file for package libgcrypt +# +# Copyright (c) 2022-2023 ZhuningOS +# + + +%define build_hmac256 1 +%define separate_hmac256_binary 0 +%define libsover 20 +%define libsoname %{name}%{libsover} +%define cavs_dir %{_libexecdir}/%{name}/cavs +Name: libgcrypt +Version: 1.9.4 +Release: 150500.10.19 +Summary: The GNU Crypto Library +License: GPL-2.0-or-later AND LGPL-2.1-or-later AND GPL-3.0-or-later +Group: Development/Libraries/C and C++ +URL: https://gnupg.org/software/libgcrypt +Source: https://gnupg.org/ftp/gcrypt/libgcrypt/%{name}-%{version}.tar.bz2 +Source1: https://gnupg.org/ftp/gcrypt/libgcrypt/%{name}-%{version}.tar.bz2.sig +Source2: baselibs.conf +Source3: random.conf +# https://www.gnupg.org/signature_key.en.html +Source4: libgcrypt.keyring +# cavs test framework +Source5: cavs-test.sh +Source6: cavs_driver.pl +Source99: libgcrypt.changes +Patch1: libgcrypt-1.4.1-rijndael_no_strict_aliasing.patch +Patch3: libgcrypt-1.5.0-LIBGCRYPT_FORCE_FIPS_MODE-env.diff +Patch4: libgcrypt-1.6.1-use-fipscheck.patch +Patch5: libgcrypt-1.6.1-fips-cavs.patch +Patch6: libgcrypt-fix-rng.patch +#PATCH-FIX-SUSE add FIPS CAVS test app for DRBG +Patch7: drbg_test.patch +#PATCH-FIX-UPSTREAM bsc#1064455 fipsdrv patch to enable --algo for dsa-sign +Patch8: libgcrypt-fipsdrv-enable-algo-for-dsa-sign.patch +#PATCH-FIX-UPSTREAM bsc#1064455 fipsdrv patch to enable --algo for dsa-verify +Patch9: libgcrypt-fipsdrv-enable-algo-for-dsa-verify.patch +Patch10: libgcrypt-1.8.3-fips-ctor.patch +Patch11: libgcrypt-1.8.4-use_xfree.patch +Patch12: libgcrypt-1.8.4-allow_FSM_same_state.patch +Patch13: libgcrypt-1.8.4-getrandom.patch +Patch14: libgcrypt-1.8.4-fips_ctor_skip_integrity_check.patch +#PATCH-FIX-SUSE Fix test in FIPS mode +Patch15: libgcrypt-dsa-rfc6979-test-fix.patch +Patch16: libgcrypt-fix-tests-fipsmode.patch +#PATCH-FIX-SUSE bsc#1155337 FIPS: RSA/DSA/ECDSA are missing hashing operation +Patch17: libgcrypt-FIPS-RSA-DSA-ECDSA-hashing-operation.patch +#PATCH-FIX-SUSE bsc#1161220 FIPS: libgcrypt RSA siggen/keygen: 4k not supported +Patch18: libgcrypt-1.8.4-fips-keygen.patch +#PATCH-FIX-SUSE bsc#1164950 Run self-tests from the constructor +Patch19: libgcrypt-invoke-global_init-from-constructor.patch +#PATCH-FIX-SUSE bsc#1164950 Restore the self-tests from the constructor +Patch20: libgcrypt-Restore-self-tests-from-constructor.patch +Patch21: libgcrypt-FIPS-GMAC_AES-benckmark.patch +Patch22: libgcrypt-global_init-constructor.patch +Patch23: libgcrypt-random_selftests-testentropy.patch +Patch24: libgcrypt-rsa-no-blinding.patch +Patch25: libgcrypt-ecc-ecdsa-no-blinding.patch +#PATCH-FIX-SUSE bsc#1165539 FIPS: Use the new signature operation in PCT +Patch26: libgcrypt-PCT-RSA.patch +Patch27: libgcrypt-PCT-DSA.patch +Patch28: libgcrypt-PCT-ECC.patch +Patch29: libgcrypt-fips_selftest_trigger_file.patch +#PATCH-FIX-SUSE bsc#1189745 The t-lock test is not build with phtread in gcc7, works in gcc11 +Patch30: libgcrypt-pthread-in-t-lock-test.patch +#PATCH-FIX-UPSTREAM bsc#1187110 FIPS: Enable hardware support also in FIPS mode +Patch31: libgcrypt-FIPS-hw-optimizations.patch +#PATCH-FIX-UPSTREAM bsc#1190706 FIPS: Provide module name/identifier and version +Patch32: libgcrypt-FIPS-module-version.patch +#PATCH-FIX-SUSE bsc#1185138 FIPS: Disable 3DES/Triple-DES in FIPS mode +Patch33: libgcrypt-FIPS-disable-3DES.patch +#PATCH-FIX-UPSTREAM bsc#1192131 FIPS: Fix regression tests in FIPS mode +Patch34: libgcrypt-FIPS-fix-regression-tests.patch +#PATCH-FIX-UPSTREAM bsc#1192240 FIPS: RSA KeyGen/SigGen fail with 4096 bit key sizes +Patch35: libgcrypt-FIPS-RSA-keylen.patch +Patch36: libgcrypt-FIPS-RSA-keylen-tests.patch +#PATCH-FIX-UPSTREAM bsc#1193480 FIPS: gcry_mpi_sub_ui: fix subtracting from negative value +Patch37: libgcrypt-FIPS-fix-gcry_mpi_sub_ui.patch +#PATCH-FIX-UPSTREAM bsc#1190700 FIPS: Provide a service-level indicator +Patch38: libgcrypt-FIPS-verify-unsupported-KDF-test.patch +Patch39: libgcrypt-FIPS-HMAC-short-keylen.patch +Patch40: libgcrypt-FIPS-service-indicators.patch +#PATCH-FIX-UPSTREAM bsc#1195385 FIPS: Disable DSA in FIPS mode +Patch41: libgcrypt-FIPS-disable-DSA.patch +#PATCH-FIX-UPSTREAM bsc#1190700 FIPS: Provide a service-level indicator for PK +Patch42: libgcrypt-FIPS-SLI-pk.patch +#PATCH-FIX-SUSE bsc#1190700 FIPS add indicators +Patch43: libgcrypt_indicators_changes.patch +#PATCH-FIX-SUSE bsc#1190700 FIPS allow shake +Patch44: libgcrypt-indicate-shake.patch +#PATCH-FIX-UPSTREAM bsc#1202117 jsc#SLE-24941 FIPS: Port libgcrypt to use jitterentropy +Patch45: libgcrypt-jitterentropy-3.3.0.patch +Patch46: libgcrypt-jitterentropy-3.4.0.patch +#PATCH-FIX-SUSE bsc#1182983 gpg: out of core handler ignored in FIPS mode while typing Tab key to Auto-Completion +Patch47: libgcrypt-out-of-core-handler.patch +#PATCH-FIX-SUSE bsc#1191020 FIPS: Zeroize buffer and digest in check_binary_integrity() +Patch48: libgcrypt-FIPS-Zeroize-hmac.patch +#PATCH-FIX-SUSE bsc#1190700 FIPS: Check keylength in gcry_fips_indicator_kdf() +Patch49: libgcrypt-FIPS-kdf-leylength.patch +#PATCH-FIX-SUSE bsc#1202117 FIPS: Get most of the entropy from rndjent_poll +Patch50: libgcrypt-FIPS-rndjent_poll.patch +#PATCH-FIX-UPSTREAM jsc#PED-566 POWER10 performance enhancements for cryptography +Patch51: libgcrypt-Bulk-implementation-of-AES-GCM-acceleration-ppc64le.patch +Patch52: libgcrypt-hwf-ppc-fix-missing-HWF_PPC_ARCH_3_10-in-HW-feature.patch +Patch53: libgcrypt-Optimized-chacha20-poly1305-for-P10-operation.patch +BuildRequires: automake >= 1.14 +BuildRequires: fipscheck +BuildRequires: libgpg-error-devel >= 1.27 +BuildRequires: libtool +BuildRequires: makeinfo +BuildRequires: pkgconfig + +%description +Libgcrypt is a general purpose library of cryptographic building +blocks. It is originally based on code used by GnuPG. It does not +provide any implementation of OpenPGP or other protocols. Thorough +understanding of applied cryptography is required to use Libgcrypt. + +%package -n %{libsoname} +Summary: The GNU Crypto Library +License: GPL-2.0-or-later AND LGPL-2.1-or-later +Group: System/Libraries +Suggests: %{libsoname}-hmac = %{version}-%{release} + +%description -n %{libsoname} +Libgcrypt is a general purpose crypto library based on the code used in +GnuPG (alpha version). + +%package -n %{libsoname}-hmac +Summary: HMAC checksums for the GNU Crypto Library +License: GPL-2.0-or-later AND LGPL-2.1-or-later +Group: System/Libraries +Requires: %{libsoname} = %{version}-%{release} + +%description -n %{libsoname}-hmac +Libgcrypt is a general purpose crypto library based on the code used in +GnuPG (alpha version). This package contains the HMAC checksum files +for integrity checking the library, as required by FIPS 140-2. + +%package devel +Summary: The GNU Crypto Library +License: GFDL-1.1-only AND GPL-2.0-or-later AND LGPL-2.1-or-later AND MIT +Group: Development/Libraries/C and C++ +Requires: %{libsoname} = %{version} +Requires: glibc-devel +Requires: libgpg-error-devel >= 1.27 + +%description devel +Libgcrypt is a general purpose library of cryptographic building +blocks. It is originally based on code used by GnuPG. It does not +provide any implementation of OpenPGP or other protocols. Thorough +understanding of applied cryptography is required to use Libgcrypt. + +This package contains needed files to compile and link against the +library. + +%package cavs +Summary: The GNU Crypto Library +License: GFDL-1.1-only AND GPL-2.0-or-later AND LGPL-2.1-or-later AND MIT +Group: Development/Libraries/C and C++ +Requires: %{libsoname} = %{version} +Requires: %{libsoname}-hmac + +%description cavs +CAVS testing framework for libgcrypt + +%if 0%{?separate_hmac256_binary} +%package hmac256 +Summary: The GNU Crypto Library +License: GPL-2.0-or-later AND LGPL-2.1-or-later +Group: Development/Libraries/C and C++ +Requires: %{libsoname} = %{version} +Requires: libgpg-error-devel >= 1.27 + +%description hmac256 +Libgcrypt is a general purpose library of cryptographic building +blocks. It is originally based on code used by GnuPG. It does not +provide any implementation of OpenPGP or other protocols. Thorough +understanding of applied cryptography is required to use Libgcrypt. +%endif + +%prep +%setup -q +%autopatch -p1 + +%build +echo building with build_hmac256 set to %{build_hmac256} +autoreconf -fi +date=$(date -u +%{Y}-%{m}-%{dT}%{H}:%{M}+0000 -r %{SOURCE99}) +sed -e "s,BUILD_TIMESTAMP=.*,BUILD_TIMESTAMP=$date," -i configure +export CFLAGS="%{optflags} $(getconf LFS_CFLAGS)" +%configure \ + --with-fips-module-version="Libgcrypt version %{version}-%{release}" \ + --enable-noexecstack \ + --disable-static \ + --enable-m-guard \ +%ifarch %{sparc} + --disable-asm \ +%endif + --enable-hmac-binary-check \ + --enable-random=linux + +%make_build + +%if 0%{?build_hmac256} +# this is a hack that re-defines the __os_install_post macro +# for a simple reason: the macro strips the binaries and thereby +# invalidates a HMAC that may have been created earlier. +# solution: create the hashes _after_ the macro runs. +# +# this shows up earlier because otherwise the %%expand of +# the macro is too late. +%{expand:%%global __os_install_post {%__os_install_post + fipshmac %{buildroot}/%{_bindir}/hmac256 + fipshmac %{buildroot}/%{_libdir}/*.so.?? +}} +%endif + +%check +fipshmac src/.libs/libgcrypt.so.?? +%make_build check + +# run the regression tests also in FIPS mode +LIBGCRYPT_FORCE_FIPS_MODE=1 make -k check VERBOSE=1 || true + +%install +%make_install +rm %{buildroot}%{_libdir}/%{name}.la + +# cavs +install -m 0755 -d %{buildroot}%{cavs_dir} +install -m 0755 %{SOURCE5} %{buildroot}%{cavs_dir} +install -m 0755 %{SOURCE6} %{buildroot}%{cavs_dir} + +mv %{buildroot}%{_bindir}/fipsdrv %{buildroot}%{cavs_dir} +mv %{buildroot}%{_bindir}/drbg_test %{buildroot}%{cavs_dir} + +# create the FIPS "module is complete" trigger file +%if 0%{?build_hmac256} +touch %{buildroot}/%{_libdir}/.%{name}.so.%{libsover}.fips +%endif + +# Create /etc/gcrypt directory and install random.conf +mkdir -p -m 0755 %{buildroot}%{_sysconfdir}/gcrypt +install -m 644 %{SOURCE3} %{buildroot}%{_sysconfdir}/gcrypt/random.conf + +%post -n %{libsoname} -p /sbin/ldconfig +%postun -n %{libsoname} -p /sbin/ldconfig + +%files -n %{libsoname} +%license COPYING.LIB +%{_libdir}/%{name}.so.* +%dir %{_sysconfdir}/gcrypt +%config(noreplace) %{_sysconfdir}/gcrypt/random.conf +%if 0%{?build_hmac256} +%{_libdir}/.libgcrypt.so.*.hmac +%endif + +%files -n %{libsoname}-hmac +%if 0%{?build_hmac256} +%{_libdir}/.libgcrypt.so.*.fips +%endif + +%files devel +%license COPYING COPYING.LIB +%doc AUTHORS ChangeLog NEWS README THANKS TODO +%{_infodir}/gcrypt.info*%{ext_info} +%{_bindir}/dumpsexp +%{_bindir}/mpicalc +%{_bindir}/%{name}-config +%{_libdir}/%{name}.so +%{_includedir}/gcrypt*.h +%{_datadir}/aclocal/%{name}.m4 +%{_libdir}/pkgconfig/libgcrypt.pc + +%if 0%{?separate_hmac256_binary} +%files hmac256 +%endif +%{_bindir}/hmac256 +%{_bindir}/.hmac256.hmac +%doc %{_mandir}/man1/hmac256.1* + +%files cavs +%{_libexecdir}/%{name} + +%changelog diff --git a/libgcrypt_indicators_changes.patch b/libgcrypt_indicators_changes.patch new file mode 100644 index 0000000..4dd3d9c --- /dev/null +++ b/libgcrypt_indicators_changes.patch @@ -0,0 +1,238 @@ +diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi +index afb8a05..c613577 100644 +--- a/doc/gcrypt.texi ++++ b/doc/gcrypt.texi +@@ -968,23 +968,39 @@ is approved under the current FIPS 140-3 certification. If the + combination is approved, this function returns @code{GPG_ERR_NO_ERROR}. + Otherwise @code{GPG_ERR_NOT_SUPPORTED} is returned. + ++@item GCRYCTL_FIPS_SERVICE_INDICATOR_HASH; Arguments: enum gcry_md_algos ++ ++Check if the given HASH is approved under the current FIPS 140-3 ++certification. If the HASH is approved, this function returns ++@code{GPS_ERR_NO_ERROR}. Otherwise @code{GPG_ERR_NOT_SUPPORTED} ++is returned. ++ ++@item GCRYCTL_FIPS_SERVICE_INDICATOR_MAC; Arguments: enum gcry_mac_algos [, unsigned int] ++ ++Check if the given MAC is approved under the current FIPS 140-3 ++certification. The second parameter provides the keylen (if the ++algorithm supports different key sizes). If the MAC is approved, ++this function returns @code{GPS_ERR_NO_ERROR}. Otherwise @code{GPG_ERR_NOT_SUPPORTED} ++is returned. ++ + @item GCRYCTL_FIPS_SERVICE_INDICATOR_KDF; Arguments: enum gcry_kdf_algos + + Check if the given KDF is approved under the current FIPS 140-3 +-certification. If the KDF is approved, this function returns +-@code{GPG_ERR_NO_ERROR}. Otherwise @code{GPG_ERR_NOT_SUPPORTED} +-is returned. ++certification. If the KDF is approved, this function returns @code{GPG_ERR_NO_ERROR}. ++Otherwise @code{GPG_ERR_NOT_SUPPORTED} is returned. + + @item GCRYCTL_FIPS_SERVICE_INDICATOR_PK; Arguments: enum gcry_pk_algos +-[, enum pk_operation (only for GCRY_PK_RSA)] [, const char * (only for +-GCRY_PK_ECC, GCRY_PK_ECDH or GCRY_PK_ECDSA)] ++[, constants GCRY_PK_USAGE_ENCR or GCRY_PK_USAGE_SIGN, unsigned int (only for GCRY_PK_RSA)] ++[, const char * (only for GCRY_PK_ECC, GCRY_PK_ECDH or GCRY_PK_ECDSA)] + + Check if the given asymmetric cipher is approved under the current FIPS +-140-3 certification. For GCRY_PK_RSA, an additional parameter for the +-operation mode @code{enum pk_operation} is required. For GCRY_PK_ECC, +-GCRY_PK_ECDH and GCRY_PK_ECDSA, the additional parameter is the curve +-name or its alias as @code{const char *}. If the combination is +-approved, this function returns @code{GPG_ERR_NO_ERROR}. Otherwise ++140-3 certification. For GCRY_PK_RSA, two additional parameter are required: ++first describes the purpose of the algorithm through one of the constants ++(GCRY_PK_USAGE_ENCR for encryption or decryption operations; GCRY_PK_USAGE_SIGN for ++sign or verify operations). ++Second one is the key length. For GCRY_PK_ECC, GCRY_PK_ECDH and GCRY_PK_ECDSA, ++only a single parameter is needed: the curve name or its alias as @code{const char *}. ++If the combination is approved, this function returns @code{GPG_ERR_NO_ERROR}. Otherwise + @code{GPG_ERR_NOT_SUPPORTED} is returned. + + @end table +diff --git a/src/fips.c b/src/fips.c +index f523e7d..d5ca482 100644 +--- a/src/fips.c ++++ b/src/fips.c +@@ -452,6 +452,7 @@ _gcry_fips_indicator_cipher (va_list arg_ptr) + mode = va_arg (arg_ptr, enum gcry_cipher_modes); + switch (mode) + { ++ case GCRY_CIPHER_MODE_AESWRAP: + case GCRY_CIPHER_MODE_ECB: + case GCRY_CIPHER_MODE_CBC: + case GCRY_CIPHER_MODE_CFB: +@@ -459,7 +460,6 @@ _gcry_fips_indicator_cipher (va_list arg_ptr) + case GCRY_CIPHER_MODE_OFB: + case GCRY_CIPHER_MODE_CTR: + case GCRY_CIPHER_MODE_CCM: +- case GCRY_CIPHER_MODE_GCM: + case GCRY_CIPHER_MODE_XTS: + return GPG_ERR_NO_ERROR; + default: +@@ -519,11 +519,25 @@ static const struct + { NULL, NULL} + }; + ++enum pk_operation convert_from_pk_usage(unsigned int pk_usage) ++{ ++ switch (pk_usage) ++ { ++ case GCRY_PK_USAGE_SIGN: ++ return PUBKEY_OP_SIGN; ++ case GCRY_PK_USAGE_ENCR: ++ return PUBKEY_OP_ENCRYPT; ++ default: ++ return PUBKEY_OP_DECRYPT; ++ } ++} ++ + int + _gcry_fips_indicator_pk (va_list arg_ptr) + { + enum gcry_pk_algos alg = va_arg (arg_ptr, enum gcry_pk_algos); + enum pk_operation oper; ++ unsigned int keylen; + const char *curve_name; + + switch (alg) +@@ -531,13 +545,17 @@ _gcry_fips_indicator_pk (va_list arg_ptr) + case GCRY_PK_RSA: + case GCRY_PK_RSA_E: + case GCRY_PK_RSA_S: +- oper = va_arg (arg_ptr, enum pk_operation); ++ oper = convert_from_pk_usage(va_arg (arg_ptr, unsigned int)); + switch (oper) + { + case PUBKEY_OP_ENCRYPT: + case PUBKEY_OP_DECRYPT: + return GPG_ERR_NOT_SUPPORTED; + default: ++ keylen = va_arg (arg_ptr, unsigned int); ++ if (keylen < 2048) { ++ return GPG_ERR_NOT_SUPPORTED; ++ } + return GPG_ERR_NO_ERROR; + } + case GCRY_PK_ECC: +@@ -557,6 +575,60 @@ _gcry_fips_indicator_pk (va_list arg_ptr) + } + } + ++int ++_gcry_fips_indicator_hash (va_list arg_ptr) ++{ ++ enum gcry_md_algos alg = va_arg (arg_ptr, enum gcry_md_algos); ++ ++ switch (alg) ++ { ++ case GCRY_MD_SHA1: ++ case GCRY_MD_SHA224: ++ case GCRY_MD_SHA256: ++ case GCRY_MD_SHA384: ++ case GCRY_MD_SHA512: ++ case GCRY_MD_SHA512_224: ++ case GCRY_MD_SHA512_256: ++ case GCRY_MD_SHA3_224: ++ case GCRY_MD_SHA3_256: ++ case GCRY_MD_SHA3_384: ++ case GCRY_MD_SHA3_512: ++ return GPG_ERR_NO_ERROR; ++ default: ++ return GPG_ERR_NOT_SUPPORTED; ++ } ++} ++ ++int ++_gcry_fips_indicator_mac (va_list arg_ptr) ++{ ++ enum gcry_mac_algos alg = va_arg (arg_ptr, enum gcry_mac_algos); ++ unsigned int keylen = va_arg (arg_ptr, unsigned int); ++ ++ switch (alg) ++ { ++ case GCRY_MAC_HMAC_SHA1: ++ case GCRY_MAC_HMAC_SHA224: ++ case GCRY_MAC_HMAC_SHA256: ++ case GCRY_MAC_HMAC_SHA384: ++ case GCRY_MAC_HMAC_SHA512: ++ case GCRY_MAC_HMAC_SHA512_224: ++ case GCRY_MAC_HMAC_SHA512_256: ++ case GCRY_MAC_HMAC_SHA3_224: ++ case GCRY_MAC_HMAC_SHA3_256: ++ case GCRY_MAC_HMAC_SHA3_384: ++ case GCRY_MAC_HMAC_SHA3_512: ++ if (keylen >= 112) { ++ return GPG_ERR_NO_ERROR; ++ } ++ case GCRY_MAC_CMAC_AES: ++ if (keylen == 128 || keylen == 192 || keylen == 256) { ++ return GPG_ERR_NO_ERROR; ++ } ++ default: ++ return GPG_ERR_NOT_SUPPORTED; ++ } ++} + + /* This is a test on whether the library is in the error or + operational state. */ +diff --git a/src/g10lib.h b/src/g10lib.h +index 9fc868b..92c24a5 100644 +--- a/src/g10lib.h ++++ b/src/g10lib.h +@@ -488,7 +488,9 @@ void _gcry_fips_signal_error (const char *srcfile, + #endif + + int _gcry_fips_indicator_cipher (va_list arg_ptr); ++int _gcry_fips_indicator_hash (va_list arg_ptr); + int _gcry_fips_indicator_kdf (va_list arg_ptr); ++int _gcry_fips_indicator_mac (va_list arg_ptr); + int _gcry_fips_indicator_pk (va_list arg_ptr); + + int _gcry_fips_is_operational (void); +diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in +index 7704d17..344f879 100644 +--- a/src/gcrypt.h.in ++++ b/src/gcrypt.h.in +@@ -337,7 +337,9 @@ enum gcry_ctl_cmds + GCRYCTL_SET_ALLOW_WEAK_KEY = 79, + GCRYCTL_FIPS_SERVICE_INDICATOR_CIPHER = 81, + GCRYCTL_FIPS_SERVICE_INDICATOR_KDF = 82, +- GCRYCTL_FIPS_SERVICE_INDICATOR_PK = 83 ++ GCRYCTL_FIPS_SERVICE_INDICATOR_PK = 83, ++ GCRYCTL_FIPS_SERVICE_INDICATOR_HASH = 84, ++ GCRYCTL_FIPS_SERVICE_INDICATOR_MAC = 85 + }; + + /* Perform various operations defined by CMD. */ +diff --git a/src/global.c b/src/global.c +index c01b424..03756ea 100644 +--- a/src/global.c ++++ b/src/global.c +@@ -762,12 +762,24 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr) + rc = _gcry_fips_indicator_cipher (arg_ptr); + break; + ++ case GCRYCTL_FIPS_SERVICE_INDICATOR_HASH: ++ /* Get FIPS Service Indicator for a given HASH. Returns GPG_ERR_NO_ERROR ++ * if algorithm is allowed or GPG_ERR_NOT_SUPPORTED otherwise */ ++ rc = _gcry_fips_indicator_hash (arg_ptr); ++ break; ++ + case GCRYCTL_FIPS_SERVICE_INDICATOR_KDF: + /* Get FIPS Service Indicator for a given KDF. Returns GPG_ERR_NO_ERROR + * if algorithm is allowed or GPG_ERR_NOT_SUPPORTED otherwise */ + rc = _gcry_fips_indicator_kdf (arg_ptr); + break; + ++ case GCRYCTL_FIPS_SERVICE_INDICATOR_MAC: ++ /* Get FIPS Service Indicator for a given HMAC. Returns GPG_ERR_NO_ERROR ++ * if algorithm is allowed or GPG_ERR_NOT_SUPPORTED otherwise */ ++ rc = _gcry_fips_indicator_mac (arg_ptr); ++ break; ++ + case GCRYCTL_FIPS_SERVICE_INDICATOR_PK: + /* Get FIPS Service Indicator for a given asymmetric algorithm. For + * GCRY_PK_RSA, an additional parameter for the operation mode is diff --git a/random.conf b/random.conf new file mode 100644 index 0000000..980efc8 --- /dev/null +++ b/random.conf @@ -0,0 +1,9 @@ +# This file can be used to globally change parameters of +# the random generator. Supported options are: + +# Always use the non-blocking /dev/urandom or the respective +# system call instead of the blocking /dev/random. +# only-urandom + +# Disable the use of the jitter based entropy generator. +# disable-jent