commit f9fd52029257db9f0a3f33f4266974e222f1d7ef
Author: zyppe <210hcl@gmail.com>
Date:   Sat Feb 10 22:23:48 2024 +0800

    Initialize for libgcrypt

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-<targettype> <= <version>"
+  provides "libgcrypt-<targettype> = <version>"
+libgcrypt20-hmac
+libgcrypt-devel
+ requires -libgcrypt-<targettype>
+ requires "libgcrypt20-<targettype> = <version>"
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 <sm@atsec.com>
+# (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/<testvectors>
+	# 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 <sm@atsec.com>
+#	      Werner Koch <wk@g10code.com> (libgcrypt interface)
+#	      Tomas Mraz <tmraz@redhat.com> (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 <FILE>.rep
+# 3. send the resulting file <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] <CAVS-test vector file>
+
+-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(<IN>) {
+
+		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 <smueller@chronox.de>
++
++   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 <config.h>
++#endif
++#include <getopt.h>
++#include <stdint.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <asm/types.h>
++#include <types.h>
++#include <unistd.h>
++#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 <sm@atsec.com>
++#	      Werner Koch <wk@g10code.com> (libgcrypt interface)
++#	      Tomas Mraz <tmraz@redhat.com> (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 <process.h>
+ #endif
++#if defined(__linux__) && defined(HAVE_SYSCALL)
++# include <sys/syscall.h>
++# include <linux/random.h>
++#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 <sys/syscall.h>
++# include <linux/random.h>
+ # 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 0000000..abfb42f
Binary files /dev/null and b/libgcrypt-1.9.4.tar.bz2.sig differ
diff --git a/libgcrypt-Bulk-implementation-of-AES-GCM-acceleration-ppc64le.patch b/libgcrypt-Bulk-implementation-of-AES-GCM-acceleration-ppc64le.patch
new file mode 100644
index 0000000..69a713f
--- /dev/null
+++ b/libgcrypt-Bulk-implementation-of-AES-GCM-acceleration-ppc64le.patch
@@ -0,0 +1,1658 @@
+From 7205c715b3e0f6fd0b853e8916d174048f43c03b Mon Sep 17 00:00:00 2001
+From: Danny Tsen <dtsen@us.ibm.com>
+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 <dtsen@us.ibm.com>
+[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 <jussi.kivilinna@iki.fi>
+
+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 <http://www.gnu.org/licenses/>.
++#
++#===================================================================================
++# Written by Danny Tsen <dtsen@us.ibm.com>
++#
++# 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 <http://www.gnu.org/licenses/>.
++ *
++ * 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 <config.h>
++
++#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 <gniibe@fsij.org>
+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 <gniibe@fsij.org>
+---
+ 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 <gniibe@fsij.org>
+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 <gniibe@fsij.org>
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ 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 <gniibe@fsij.org>
+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 <gniibe@fsij.org>
+---
+ 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 <gniibe@fsij.org>
+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 <gniibe@fsij.org>
+---
+ 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 <jjelen@redhat.com>
+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 <gniibe@fsij.org>
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ 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 <jjelen@redhat.com>
+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 <jjelen@redhat.com>
+---
+ 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 <jussi.kivilinna@iki.fi>
+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 <guidovranken@gmail.com>
+Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
+---
+ 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 <gniibe@fsij.org>
+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 <gniibe@fsij.org>
+---
+ 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 <jjelen@redhat.com>
+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 <jjelen@redhat.com>
+---
+ 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 <gniibe@fsij.org>
+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 <jjelen@redhat.com>
+GnuPG-bug-id: 5508
+Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
+---
+ 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 <jjelen@redhat.com>
+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 <jjelen@redhat.com>
+
+Moved the module version to a 3rd field to keep the semantics of that
+line.
+
+Signed-off-by: Werner Koch <wk@gnupg.org>
+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 <jjelen@redhat.com>
+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 <jjelen@redhat.com>
+---
+ 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 <dtsen@us.ibm.com>
+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 <dtsen@us.ibm.com>
+[jk: cosmetic changes to C code]
+[jk: fix building on ppc64be]
+Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
+
+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 <http://www.gnu.org/licenses/>.
++#
++#===================================================================================
++# Written by Danny Tsen <dtsen@us.ibm.com>
++#
++# 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 <http://www.gnu.org/licenses/>.
++#
++#===================================================================================
++# Written by Danny Tsen <dtsen@us.ibm.com>
++#
++# 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 <jussi.kivilinna@iki.fi>
+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 <jussi.kivilinna@iki.fi>
+
+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 <smueller@chronox.de>, 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 <smueller@chronox.de>
++
++ 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<<bits) - 1;
+-
+-	jent_get_nstime(&time);
+-	/*
+-	 * Mix the current state of the random number into the shuffle
+-	 * calculation to balance that shuffle a bit more.
+-	 */
+-	if (ec)
+-		time ^= ec->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<<min));
+-}
+-
+ /***************************************************************************
+- * Noise sources
++ * Helper
+  ***************************************************************************/
+ 
+-/**
+- * CPU Jitter noise source -- this is the noise source based on the CPU
+- * 			      execution time jitter
+- *
+- * This function injects the individual bits of the time value into the
+- * entropy pool using an LFSR.
+- *
+- * The code is deliberately inefficient with respect to the bit shifting
+- * and shall stay that way. This function is the root cause why the code
+- * shall be compiled without optimization. This function not only acts as
+- * folding operation, but this function's execution is used to measure
+- * the CPU execution time jitter. Any change to the loop in this function
+- * implies that careful retesting must be done.
+- *
+- * Input:
+- * @ec entropy collector struct -- may be NULL
+- * @time time stamp to be injected
+- * @loop_cnt if a value not equal to 0 is set, use the given value as number of
+- *	     loops to perform the folding
+- *
+- * Output:
+- * updated ec->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 <smueller@chronox.de>
++ *
++ * 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 <fcntl.h>
++#include <limits.h>
++
+ #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 <sched.h>
++
++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 <josh@keypair.us>
++ * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de>
++ *
++ * 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 <smueller@chronox.de>
++ *
++ * 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_MEMORY_BITS)
++# endif
++#else /* JENT_RANDOM_MEMACCESS */
++# ifndef JENT_MEMORY_BLOCKS
++#  define JENT_MEMORY_BLOCKS 512
++# endif
++# ifndef JENT_MEMORY_BLOCKSIZE
++#  define JENT_MEMORY_BLOCKSIZE 128
++# endif
++# ifndef JENT_MEMORY_SIZE
++#  define JENT_MEMORY_SIZE (JENT_MEMORY_BLOCKS*JENT_MEMORY_BLOCKSIZE)
++# endif
++#endif /* JENT_RANDOM_MEMACCESS */
++
+ #define JENT_MEMORY_ACCESSLOOPS 128
+-#define JENT_MEMORY_SIZE (JENT_MEMORY_BLOCKS*JENT_MEMORY_BLOCKSIZE)
+-	unsigned char *mem;	/* Memory access location with size of
+-				 * memblocks * memblocksize */
+-	unsigned int memlocation; /* Pointer to byte in *mem */
+-	unsigned int memblocks;	/* Number of memory blocks in *mem */
+-	unsigned int memblocksize; /* Size of one memory block in bytes */
+-	unsigned int memaccessloops; /* Number of memory accesses per random
+-				      * bit generation */
++	unsigned char *mem;		/* Memory access location with size of
++					 * JENT_MEMORY_SIZE or memsize */
++#ifdef JENT_RANDOM_MEMACCESS
++	uint32_t memmask;		/* Memory mask (size of memory - 1) */
++#else
++	unsigned int memlocation; 	/* Pointer to byte in *mem */
++	unsigned int memblocks;		/* Number of memory blocks in *mem */
++	unsigned int memblocksize; 	/* Size of one memory block in bytes */
++#endif
++	unsigned int memaccessloops;	/* Number of memory accesses per random
++					 * bit generation */
++
++	/* Repetition Count Test */
++	int rct_count;			/* Number of stuck values */
++
++	/* Adaptive Proportion Test for a significance level of 2^-30 */
++	unsigned int apt_cutoff;	/* Calculated using a corrected version
++					 * of the SP800-90B sec 4.4.2 formula */
++#define JENT_APT_WINDOW_SIZE	512	/* Data window size */
++	unsigned int apt_observations;	/* Number of collected observations in
++					 * current window. */
++	unsigned int apt_count;		/* The number of times the reference
++					 * symbol been encountered in the
++					 * window. */
++	uint64_t apt_base;		/* APT base reference */
++	unsigned int health_failure;	/* Permanent health failure */
++
++	unsigned int apt_base_set:1;	/* APT base reference set? */
++	unsigned int fips_enabled:1;
++	unsigned int enable_notime:1;	/* Use internal high-res timer */
++	unsigned int max_mem_set:1;	/* Maximum memory configured by user */
++
++#ifdef JENT_CONF_ENABLE_INTERNAL_TIMER
++	volatile uint8_t notime_interrupt;	/* indicator to interrupt ctr */
++	volatile uint64_t notime_timer;		/* high-res timer mock-up */
++	uint64_t notime_prev_timer;		/* previous timer value */
++	void *notime_thread_ctx;		/* register thread data */
++#endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */
++
++	uint64_t jent_common_timer_gcd;	/* Common divisor for all time deltas */
++
++#ifdef JENT_HEALTH_LAG_PREDICTOR
++	/* Lag predictor test to look for re-occurring patterns. */
++
++	/* The lag global cutoff selected based on the selection of osr. */
++	unsigned int lag_global_cutoff;
++
++	/* The lag local cutoff selected based on the selection of osr. */
++	unsigned int lag_local_cutoff;
++
++	/*
++	 * The number of times the lag predictor was correct. Compared to the
++	 * global cutoff.
++	 */
++	unsigned int lag_prediction_success_count;
++
++	/*
++	 * The size of the current run of successes. Compared to the local
++	 * cutoff.
++	 */
++	unsigned int lag_prediction_success_run;
++
++	/*
++	 * The total number of collected observations since the health test was
++	 * last reset.
++	 */
++	unsigned int lag_best_predictor;
++
++	/*
++	 * The total number of collected observations since the health test was
++	 * last reset.
++	 */
++	unsigned int lag_observations;
++
++	/*
++	 * This is the size of the window used by the predictor. The predictor
++	 * is reset between windows.
++	 */
++#define JENT_LAG_WINDOW_SIZE (1U<<17)
++
++	/*
++	 * The amount of history to base predictions on. This must be a power
++	 * of 2. Must be 4 or greater.
++	 */
++#define JENT_LAG_HISTORY_SIZE 8
++#define JENT_LAG_MASK (JENT_LAG_HISTORY_SIZE - 1)
++
++	/* The delta history for the lag predictor. */
++	uint64_t lag_delta_history[JENT_LAG_HISTORY_SIZE];
++
++	/* The scoreboard that tracks how successful each predictor lag is. */
++	unsigned int lag_scoreboard[JENT_LAG_HISTORY_SIZE];
++#endif /* JENT_HEALTH_LAG_PREDICTOR */
+ };
+ 
+ /* Flags that can be used to initialize the RNG */
+-#define JENT_DISABLE_STIR (1<<0) /* Disable stirring the entropy pool */
+-#define JENT_DISABLE_UNBIAS (1<<1) /* Disable the Von-Neuman Unbiaser */
++#define JENT_DISABLE_STIR (1<<0) 	/* UNUSED */
++#define JENT_DISABLE_UNBIAS (1<<1) 	/* UNUSED */
+ #define JENT_DISABLE_MEMORY_ACCESS (1<<2) /* Disable memory access for more
+ 					     entropy, saves MEMORY_SIZE RAM for
+ 					     entropy collector */
++#define JENT_FORCE_INTERNAL_TIMER (1<<3)  /* Force the use of the internal
++					     timer */
++#define JENT_DISABLE_INTERNAL_TIMER (1<<4)  /* Disable the potential use of
++					       the internal timer. */
++#define JENT_FORCE_FIPS (1<<5)		  /* Force FIPS compliant mode
++					     including full SP800-90B
++					     compliance. */
++
++/* Flags field limiting the amount of memory to be used for memory access */
++#define JENT_FLAGS_TO_MEMSIZE_SHIFT	28
++#define JENT_FLAGS_TO_MAX_MEMSIZE(val)	(val >> 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 <josh@keypair.us>
++ * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de>
++ *
++ * 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 <smueller@chronox.de>
++ *
++ * 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 <smueller@chronox.de>
++ *
++ * 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)<<min);
++
++#else /* JENT_CONF_DISABLE_LOOP_SHUFFLE */
++
++	uint64_t time = 0;
++	uint64_t shuffle = 0;
++	uint64_t mask = (UINT64_C(1)<<bits) - 1;
++	unsigned int i = 0;
++
++	/*
++	 * 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];
++	}
++
++	/*
++	 * 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)<<min));
++
++#endif /* JENT_CONF_DISABLE_LOOP_SHUFFLE */
++}
++
++/**
++ * CPU Jitter noise source -- this is the noise source based on the CPU
++ * 			      execution time jitter
++ *
++ * 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
++ * @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?
++ *
++ * Output:
++ * updated hash context
++ */
++static void jent_hash_time(struct rand_data *ec, uint64_t time,
++			   uint64_t loop_cnt, unsigned int stuck)
++{
++	HASH_CTX_ON_STACK(ctx);
++	uint8_t itermediary[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 =
++		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 <smueller@chronox.de>
++ *
++ * 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 <smueller@chronox.de>
++ *
++ * 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 <smueller@chronox.de>
++ *
++ * 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 <smueller@chronox.de>
++ *
++ * 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 <smueller@chronox.de>
++ *
++ * 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 <stdint.h>
+ #endif
++#include <unistd.h>
++#include <errno.h>
+ 
+ #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 <pthread.h>
++#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 <http://eprint.iacr.org/2013/448> [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 <http://eprint.iacr.org/2013/448>.
+* 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