diff --git a/.gitignore b/.gitignore index 3ea085c..791d596 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ libgcrypt-1.4.5-hobbled.tar.bz2 /libgcrypt-1.5.3-hobbled.tar.xz /libgcrypt-1.6.1-hobbled.tar.xz /libgcrypt-1.6.2-hobbled.tar.xz +/libgcrypt-1.6.3-hobbled.tar.xz diff --git a/libgcrypt-1.6.1-fips-cavs.patch b/libgcrypt-1.6.1-fips-cavs.patch deleted file mode 100644 index 55aa66a..0000000 --- a/libgcrypt-1.6.1-fips-cavs.patch +++ /dev/null @@ -1,1123 +0,0 @@ -diff -up libgcrypt-1.6.1/tests/cavs_driver.pl.cavs libgcrypt-1.6.1/tests/cavs_driver.pl ---- libgcrypt-1.6.1/tests/cavs_driver.pl.cavs 2013-03-15 20:25:38.000000000 +0100 -+++ libgcrypt-1.6.1/tests/cavs_driver.pl 2014-02-28 14:46:16.436544639 +0100 -@@ -1,9 +1,11 @@ - #!/usr/bin/env perl - # --# $Id: cavs_driver.pl 1497 2009-01-22 14:01:29Z smueller $ -+# $Id: cavs_driver.pl 2124 2010-12-20 07:56:30Z smueller $ - # - # CAVS test driver (based on the OpenSSL driver) - # Written by: Stephan Müller -+# Werner Koch (libgcrypt interface) -+# Tomas Mraz (addition of DSA2) - # Copyright (c) atsec information security corporation - # - # Permission is hereby granted, free of charge, to any person obtaining a copy -@@ -85,13 +87,16 @@ - # T[CBC|CFB??|ECB|OFB]varkey - # T[CBC|CFB??|ECB|OFB]invperm - # T[CBC|CFB??|ECB|OFB]vartext -+# WARNING: TDES in CFB and OFB mode problems see below - # - # ANSI X9.31 RNG - # ANSI931_AES128MCT - # ANSI931_AES128VST - # --# DSA -+# DSA2 - # PQGGen -+# PQGVer -+# KeyPair - # SigGen - # SigVer - # -@@ -101,6 +106,36 @@ - # RC4PltBD - # RC4REGT - # -+# -+# TDES MCT for CFB and OFB: -+# ------------------------- -+# The inner loop cannot be handled by this script. If you want to have tests -+# for these cipher types, implement your own inner loop and add it to -+# crypto_mct. -+# -+# the value $next_source in crypto_mct is NOT set by the standard implementation -+# of this script. It would need to be set as follows for these two (code take -+# from fipsdrv.c from libgcrypt - the value input at the end will contain the -+# the value for $next_source: -+# -+# ... inner loop ... -+# ... -+# get_current_iv (hd, last_iv, blocklen); -+# ... encrypt / decrypt (input is the data to be en/decrypted and output is the -+# result of operation) ... -+# if (encrypt_mode && (cipher_mode == GCRY_CIPHER_MODE_CFB)) -+# memcpy (input, last_iv, blocklen); -+# else if (cipher_mode == GCRY_CIPHER_MODE_OFB) -+# memcpy (input, last_iv, blocklen); -+# else if (!encrypt_mode && cipher_mode == GCRY_CIPHER_MODE_CFB) -+# { -+# /* Reconstruct the output vector. */ -+# int i; -+# for (i=0; i < blocklen; i++) -+# input[i] ^= output[i]; -+# } -+# ... inner loop ends ... -+# ==> now, the value of input is to be put into $next_source - - use strict; - use warnings; -@@ -226,6 +261,8 @@ my $hmac; - # Generate the P, Q, G, Seed, counter, h (value used to generate g) values - # for DSA - # $1: modulus size -+# $2: q size -+# $3: seed (might be empty string) - # return: string with the calculated values in hex format, where each value - # is separated from the previous with a \n in the following order: - # P\n -@@ -236,6 +273,19 @@ my $hmac; - # h - my $dsa_pqggen; - -+# Generate the G value from P and Q -+# for DSA -+# $1: modulus size -+# $2: q size -+# $3: P in hex form -+# $4: Q in hex form -+# return: string with the calculated values in hex format, where each value -+# is separated from the previous with a \n in the following order: -+# P\n -+# Q\n -+# G\n -+my $dsa_ggen; -+ - # - # Generate an DSA public key from the provided parameters: - # $1: Name of file to create -@@ -255,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; -diff -up libgcrypt-1.6.1/tests/cavs_tests.sh.cavs libgcrypt-1.6.1/tests/cavs_tests.sh ---- libgcrypt-1.6.1/tests/cavs_tests.sh.cavs 2013-03-15 20:25:38.000000000 +0100 -+++ libgcrypt-1.6.1/tests/cavs_tests.sh 2014-02-28 14:46:16.437544662 +0100 -@@ -55,7 +55,7 @@ function run_one_test () { - [ -d "$respdir" ] || mkdir "$respdir" - [ -f "$rspfile" ] && rm "$rspfile" - -- if echo "$reqfile" | grep '/DSA/req/' >/dev/null 2>/dev/null; then -+ if echo "$reqfile" | grep '/DSA.\?/req/' >/dev/null 2>/dev/null; then - dflag="-D" - fi - -diff -up libgcrypt-1.6.1/tests/fipsdrv.c.cavs libgcrypt-1.6.1/tests/fipsdrv.c ---- libgcrypt-1.6.1/tests/fipsdrv.c.cavs 2013-12-16 18:44:32.000000000 +0100 -+++ libgcrypt-1.6.1/tests/fipsdrv.c 2014-02-28 14:46:16.437544662 +0100 -@@ -893,6 +893,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; - -@@ -1675,14 +1678,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)); -@@ -1700,7 +1703,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; -@@ -1709,10 +1712,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)); -@@ -1720,6 +1724,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); - -@@ -1732,7 +1767,7 @@ dsa_gen_with_seed (int keysize, const vo - 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; -@@ -1768,6 +1803,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) -@@ -1819,38 +1857,106 @@ print_dsa_domain_parameters (gcry_sexp_t - } - - --/* 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) -@@ -1863,6 +1969,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. */ -@@ -1872,11 +2025,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, -@@ -1887,8 +2045,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) - { -@@ -1964,13 +2120,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; -+ -+ s_key = read_sexp_from_file (keyfile); -+ algo = dsa_hash_from_key(s_key); - -- gcry_md_hash_buffer (GCRY_MD_SHA1, hash, data, datalen); -+ 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, -@@ -1981,7 +2142,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); -@@ -2014,7 +2174,7 @@ usage (int show_help) - "Run a crypto operation using hex encoded input and output.\n" - "MODE:\n" - " encrypt, decrypt, digest, random, hmac-sha,\n" -- " rsa-{derive,gen,sign,verify}, dsa-{pqg-gen,gen,sign,verify}\n" -+ " rsa-{derive,gen,sign,verify}, dsa-{pq-gen,g-gen,gen,sign,verify}\n" - "OPTIONS:\n" - " --verbose Print additional information\n" - " --binary Input and output is in binary form\n" -@@ -2024,6 +2184,7 @@ usage (int show_help) - " --dt DT Use the hex encoded DT for the RNG\n" - " --algo NAME Use algorithm 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" -@@ -2050,6 +2211,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; -@@ -2143,6 +2305,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++; -@@ -2463,23 +2633,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"); -- 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"); -+ 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"); -+ 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.2-rsa-fips-keygen.patch b/libgcrypt-1.6.2-rsa-fips-keygen.patch deleted file mode 100644 index f9a3e5f..0000000 --- a/libgcrypt-1.6.2-rsa-fips-keygen.patch +++ /dev/null @@ -1,375 +0,0 @@ -diff -up libgcrypt-1.6.2/cipher/primegen.c.fips-keygen libgcrypt-1.6.2/cipher/primegen.c ---- libgcrypt-1.6.2/cipher/primegen.c.fips-keygen 2014-12-08 16:55:56.425077059 +0100 -+++ libgcrypt-1.6.2/cipher/primegen.c 2014-12-08 16:59:26.039817665 +0100 -@@ -1198,6 +1198,22 @@ _gcry_prime_check (gcry_mpi_t x, unsigne - return rc; - } - -+/* Check whether the number X is prime according to FIPS 186-4 table C.2. */ -+gcry_err_code_t -+_gcry_fips186_4_prime_check (gcry_mpi_t x, unsigned int bits) -+{ -+ gcry_err_code_t ec = GPG_ERR_NO_ERROR; -+ gcry_mpi_t val_2 = mpi_alloc_set_ui (2); /* Used by the Fermat test. */ -+ -+ /* We use 5 or 4 rounds as specified in table C.2 */ -+ if (! check_prime (x, val_2, bits > 1024 ? 4 : 5, NULL, NULL)) -+ ec = GPG_ERR_NO_PRIME; -+ -+ mpi_free (val_2); -+ -+ return ec; -+} -+ - /* Find a generator for PRIME where the factorization of (prime-1) is - in the NULL terminated array FACTORS. Return the generator as a - newly allocated MPI in R_G. If START_G is not NULL, use this as s -diff -up libgcrypt-1.6.2/cipher/rsa.c.fips-keygen libgcrypt-1.6.2/cipher/rsa.c ---- libgcrypt-1.6.2/cipher/rsa.c.fips-keygen 2014-12-08 16:55:56.407076652 +0100 -+++ libgcrypt-1.6.2/cipher/rsa.c 2014-12-08 17:11:06.770665261 +0100 -@@ -339,6 +339,279 @@ generate_std (RSA_secret_key *sk, unsign - } - - -+/**************** -+ * Generate a key pair with a key of size NBITS. -+ * USE_E = 0 let Libcgrypt decide what exponent to use. -+ * = 1 request the use of a "secure" exponent; this is required by some -+ * specification to be 65537. -+ * > 2 Use this public exponent. If the given exponent -+ * is not odd one is internally added to it. -+ * TESTPARMS: If set, do not generate but test whether the p,q is probably prime -+ * Returns key with zeroes to not break code calling this function. -+ * TRANSIENT_KEY: If true, generate the primes using the standard RNG. -+ * Returns: 2 structures filled with all needed values -+ */ -+static gpg_err_code_t -+generate_fips (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e, -+ gcry_sexp_t testparms, int transient_key) -+{ -+ gcry_mpi_t p, q; /* the two primes */ -+ gcry_mpi_t d; /* the private key */ -+ gcry_mpi_t u; -+ gcry_mpi_t p1, q1; -+ gcry_mpi_t n; /* the public key */ -+ gcry_mpi_t e; /* the exponent */ -+ gcry_mpi_t g; -+ gcry_mpi_t minp; -+ gcry_mpi_t diff, mindiff; -+ gcry_random_level_t random_level; -+ unsigned int pbits = nbits/2; -+ unsigned int i; -+ int pqswitch; -+ gpg_err_code_t ec = GPG_ERR_NO_PRIME; -+ -+ if (nbits < 1024 || (nbits & 0x1FF)) -+ return GPG_ERR_INV_VALUE; -+ if (_gcry_enforced_fips_mode() && nbits != 2048 && nbits != 3072) -+ 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; -+ -+ if (testparms) -+ { -+ /* Parameters to derive the key are given. */ -+ /* Note that we explicitly need to setup the values of tbl -+ because some compilers (e.g. OpenWatcom, IRIX) don't allow -+ to initialize a structure with automatic variables. */ -+ struct { const char *name; gcry_mpi_t *value; } tbl[] = { -+ { "e" }, -+ { "p" }, -+ { "q" }, -+ { NULL } -+ }; -+ int idx; -+ gcry_sexp_t oneparm; -+ -+ tbl[0].value = &e; -+ tbl[1].value = &p; -+ tbl[2].value = &q; -+ -+ for (idx=0; tbl[idx].name; idx++) -+ { -+ oneparm = sexp_find_token (testparms, tbl[idx].name, 0); -+ if (oneparm) -+ { -+ *tbl[idx].value = sexp_nth_mpi (oneparm, 1, -+ GCRYMPI_FMT_USG); -+ sexp_release (oneparm); -+ } -+ } -+ for (idx=0; tbl[idx].name; idx++) -+ if (!*tbl[idx].value) -+ break; -+ if (tbl[idx].name) -+ { -+ /* At least one parameter is missing. */ -+ for (idx=0; tbl[idx].name; idx++) -+ _gcry_mpi_release (*tbl[idx].value); -+ return GPG_ERR_MISSING_VALUE; -+ } -+ } -+ else -+ { -+ if (use_e < 65537) -+ use_e = 65537; /* This is the smallest value allowed by FIPS */ -+ -+ e = mpi_alloc( (32+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB ); -+ -+ use_e |= 1; /* make sure this is odd */ -+ mpi_set_ui (e, use_e); -+ -+ p = mpi_snew (pbits); -+ q = mpi_snew (pbits); -+ } -+ -+ n = mpi_new (nbits); -+ d = mpi_snew (nbits); -+ u = mpi_snew (nbits); -+ -+ /* prepare approximate minimum p and q */ -+ minp = mpi_new (pbits); -+ mpi_set_ui (minp, 0xB504F334); -+ mpi_lshift (minp, minp, pbits - 32); -+ -+ /* prepare minimum p and q difference */ -+ diff = mpi_new (pbits); -+ mindiff = mpi_new (pbits - 99); -+ mpi_set_ui (mindiff, 1); -+ mpi_lshift (mindiff, mindiff, pbits - 100); -+ -+ p1 = mpi_snew (pbits); -+ q1 = mpi_snew (pbits); -+ g = mpi_snew (pbits); -+ -+retry: -+ /* generate p and q */ -+ for (i = 0; i < 5 * pbits; i++) -+ { -+ ploop: -+ if (!testparms) -+ { -+ _gcry_mpi_randomize (p, pbits, random_level); -+ } -+ if (mpi_cmp (p, minp) < 0) -+ { -+ if (testparms) goto err; -+ goto ploop; -+ } -+ -+ mpi_sub_ui (p1, p, 1); -+ if (mpi_gcd (g, p1, e)) -+ { -+ if (_gcry_fips186_4_prime_check (p, pbits) != GPG_ERR_NO_ERROR) -+ { -+ /* not a prime */ -+ if (testparms) goto err; -+ } -+ else -+ break; -+ } -+ else if (testparms) goto err; -+ } -+ if (i >= 5 * pbits) -+ goto err; -+ -+ for (i = 0; i < 5 * pbits; i++) -+ { -+ qloop: -+ if (!testparms) -+ { -+ _gcry_mpi_randomize (q, pbits, random_level); -+ } -+ if (mpi_cmp (q, minp) < 0) -+ { -+ if (testparms) goto err; -+ goto qloop; -+ } -+ if (mpi_cmp (p, q) < 0) -+ { -+ pqswitch = 1; -+ mpi_sub (diff, q, p); -+ } -+ else -+ { -+ pqswitch = 0; -+ mpi_sub (diff, p, q); -+ } -+ if (mpi_cmp (diff, mindiff) < 0) -+ { -+ if (testparms) goto err; -+ goto qloop; -+ } -+ -+ mpi_sub_ui (q1, q, 1); -+ if (mpi_gcd (g, q1, e)) -+ { -+ if (_gcry_fips186_4_prime_check (q, pbits) != GPG_ERR_NO_ERROR) -+ { -+ /* not a prime */ -+ if (testparms) goto err; -+ } -+ else -+ break; -+ } -+ else if (testparms) goto err; -+ } -+ if (i >= 5 * pbits) -+ goto err; -+ -+ if (testparms) -+ { -+ mpi_clear (p); -+ mpi_clear (q); -+ } -+ else -+ { -+ gcry_mpi_t f; -+ -+ if (pqswitch) -+ { -+ gcry_mpi_t tmp; -+ -+ tmp = p; -+ p = q; -+ q = tmp; -+ } -+ -+ f = mpi_snew (nbits); -+ -+ /* calculate the modulus */ -+ mpi_mul(n, p, q); -+ -+ /* calculate the secret key d = e^1 mod phi */ -+ mpi_gcd (g, p1, q1); -+ mpi_fdiv_q (f, p1, g); -+ mpi_mul (f, f, q1); -+ -+ mpi_invm (d, e, f); -+ -+ _gcry_mpi_release (f); -+ -+ if (mpi_get_nbits (d) < pbits) goto retry; -+ -+ /* calculate the inverse of p and q (used for chinese remainder theorem)*/ -+ mpi_invm(u, p, q ); -+ } -+ -+ ec = 0; -+ -+ if( DBG_CIPHER ) -+ { -+ log_mpidump(" p= ", p ); -+ log_mpidump(" q= ", q ); -+ log_mpidump(" n= ", n ); -+ log_mpidump(" e= ", e ); -+ log_mpidump(" d= ", d ); -+ log_mpidump(" u= ", u ); -+ } -+ -+err: -+ -+ _gcry_mpi_release (p1); -+ _gcry_mpi_release (q1); -+ _gcry_mpi_release (g); -+ _gcry_mpi_release (minp); -+ _gcry_mpi_release (mindiff); -+ _gcry_mpi_release (diff); -+ -+ sk->n = n; -+ sk->e = e; -+ sk->p = p; -+ sk->q = q; -+ sk->d = d; -+ sk->u = u; -+ -+ /* Now we can test our keys. */ -+ if (ec || (!testparms && test_keys (sk, nbits - 64))) -+ { -+ _gcry_mpi_release (sk->n); sk->n = NULL; -+ _gcry_mpi_release (sk->e); sk->e = NULL; -+ _gcry_mpi_release (sk->p); sk->p = NULL; -+ _gcry_mpi_release (sk->q); sk->q = NULL; -+ _gcry_mpi_release (sk->d); sk->d = NULL; -+ _gcry_mpi_release (sk->u); sk->u = NULL; -+ if (!ec) -+ { -+ fips_signal_error ("self-test after key generation failed"); -+ return GPG_ERR_SELFTEST_FAILED; -+ } -+ } -+ -+ return ec; -+} -+ -+ - /* Helper for generate_x931. */ - static gcry_mpi_t - gen_x931_parm_xp (unsigned int nbits) -@@ -799,7 +1072,7 @@ rsa_generate (const gcry_sexp_t genparms - } - } - -- if (deriveparms || (flags & PUBKEY_FLAG_USE_X931) || fips_mode ()) -+ if (deriveparms || (flags & PUBKEY_FLAG_USE_X931)) - { - int swapped; - ec = generate_x931 (&sk, nbits, evalue, deriveparms, &swapped); -@@ -819,9 +1092,14 @@ rsa_generate (const gcry_sexp_t genparms - sexp_release (l1); - } - } -+ deriveparms = (genparms? -+ sexp_find_token (genparms, "test-parms", 0) : NULL); - /* Generate. */ -- ec = generate_std (&sk, nbits, evalue, -- !!(flags & PUBKEY_FLAG_TRANSIENT_KEY)); -+ if (deriveparms || fips_mode()) -+ ec = generate_fips (&sk, nbits, evalue, deriveparms, !!(flags & PUBKEY_FLAG_TRANSIENT_KEY)); -+ else -+ ec = generate_std (&sk, nbits, evalue, !!(flags & PUBKEY_FLAG_TRANSIENT_KEY)); -+ sexp_release (deriveparms); - } - - if (!ec) -diff -up libgcrypt-1.6.2/src/g10lib.h.fips-keygen libgcrypt-1.6.2/src/g10lib.h ---- libgcrypt-1.6.2/src/g10lib.h.fips-keygen 2014-08-21 12:29:09.000000000 +0200 -+++ libgcrypt-1.6.2/src/g10lib.h 2014-12-08 16:55:56.426077081 +0100 -@@ -259,6 +259,9 @@ gpg_err_code_t _gcry_generate_fips186_3_ - int *r_counter, - void **r_seed, size_t *r_seedlen, int *r_hashalgo); - -+gpg_err_code_t _gcry_fips186_4_prime_check -+ (const gcry_mpi_t x, unsigned int bits); -+ - - /* Replacements of missing functions (missing-string.c). */ - #ifndef HAVE_STPCPY -diff -up libgcrypt-1.6.2/tests/keygen.c.fips-keygen libgcrypt-1.6.2/tests/keygen.c ---- libgcrypt-1.6.2/tests/keygen.c.fips-keygen 2014-12-08 16:55:56.407076652 +0100 -+++ libgcrypt-1.6.2/tests/keygen.c 2014-12-08 17:13:29.449892067 +0100 -@@ -215,12 +215,12 @@ check_rsa_keys (void) - - - if (verbose) -- show ("creating 1024 bit RSA key with e=257\n"); -+ show ("creating 1024 bit RSA key with e=65539\n"); - rc = gcry_sexp_new (&keyparm, - "(genkey\n" - " (rsa\n" - " (nbits 4:1024)\n" -- " (rsa-use-e 3:257)\n" -+ " (rsa-use-e 5:65539)\n" - " ))", 0, 1); - if (rc) - die ("error creating S-expression: %s\n", gpg_strerror (rc)); -@@ -229,7 +229,7 @@ check_rsa_keys (void) - if (rc) - die ("error generating RSA key: %s\n", gpg_strerror (rc)); - -- check_generated_rsa_key (key, 257); -+ check_generated_rsa_key (key, 65539); - gcry_sexp_release (key); - - if (verbose) diff --git a/libgcrypt-1.6.3-rsa-fips-keygen.patch b/libgcrypt-1.6.3-rsa-fips-keygen.patch new file mode 100644 index 0000000..6d2243e --- /dev/null +++ b/libgcrypt-1.6.3-rsa-fips-keygen.patch @@ -0,0 +1,378 @@ +diff -up libgcrypt-1.6.3/cipher/primegen.c.fips-keygen libgcrypt-1.6.3/cipher/primegen.c +--- libgcrypt-1.6.3/cipher/primegen.c.fips-keygen 2015-03-06 16:38:56.698052602 +0100 ++++ libgcrypt-1.6.3/cipher/primegen.c 2015-03-06 16:45:45.848193024 +0100 +@@ -1199,6 +1199,25 @@ _gcry_prime_check (gcry_mpi_t x, unsigne + return GPG_ERR_NO_PRIME; + } + ++/* Check whether the number X is prime according to FIPS 186-4 table C.2. */ ++gcry_err_code_t ++_gcry_fips186_4_prime_check (gcry_mpi_t x, unsigned int bits) ++{ ++ gcry_err_code_t ec = GPG_ERR_NO_ERROR; ++ ++ switch (mpi_cmp_ui (x, 2)) ++ { ++ case 0: return ec; /* 2 is a prime */ ++ case -1: return GPG_ERR_NO_PRIME; /* Only numbers > 1 are primes. */ ++ } ++ ++ /* We use 5 or 4 rounds as specified in table C.2 */ ++ if (! check_prime (x, mpi_const (MPI_C_TWO), bits > 1024 ? 4 : 5, NULL, NULL)) ++ ec = GPG_ERR_NO_PRIME; ++ ++ return ec; ++} ++ + /* Find a generator for PRIME where the factorization of (prime-1) is + in the NULL terminated array FACTORS. Return the generator as a + newly allocated MPI in R_G. If START_G is not NULL, use this as s +diff -up libgcrypt-1.6.3/cipher/rsa.c.fips-keygen libgcrypt-1.6.3/cipher/rsa.c +--- libgcrypt-1.6.3/cipher/rsa.c.fips-keygen 2015-03-06 16:38:56.661052411 +0100 ++++ libgcrypt-1.6.3/cipher/rsa.c 2015-03-06 16:38:56.699052607 +0100 +@@ -339,6 +339,279 @@ generate_std (RSA_secret_key *sk, unsign + } + + ++/**************** ++ * Generate a key pair with a key of size NBITS. ++ * USE_E = 0 let Libcgrypt decide what exponent to use. ++ * = 1 request the use of a "secure" exponent; this is required by some ++ * specification to be 65537. ++ * > 2 Use this public exponent. If the given exponent ++ * is not odd one is internally added to it. ++ * TESTPARMS: If set, do not generate but test whether the p,q is probably prime ++ * Returns key with zeroes to not break code calling this function. ++ * TRANSIENT_KEY: If true, generate the primes using the standard RNG. ++ * Returns: 2 structures filled with all needed values ++ */ ++static gpg_err_code_t ++generate_fips (RSA_secret_key *sk, unsigned int nbits, unsigned long use_e, ++ gcry_sexp_t testparms, int transient_key) ++{ ++ gcry_mpi_t p, q; /* the two primes */ ++ gcry_mpi_t d; /* the private key */ ++ gcry_mpi_t u; ++ gcry_mpi_t p1, q1; ++ gcry_mpi_t n; /* the public key */ ++ gcry_mpi_t e; /* the exponent */ ++ gcry_mpi_t g; ++ gcry_mpi_t minp; ++ gcry_mpi_t diff, mindiff; ++ gcry_random_level_t random_level; ++ unsigned int pbits = nbits/2; ++ unsigned int i; ++ int pqswitch; ++ gpg_err_code_t ec = GPG_ERR_NO_PRIME; ++ ++ if (nbits < 1024 || (nbits & 0x1FF)) ++ return GPG_ERR_INV_VALUE; ++ if (_gcry_enforced_fips_mode() && nbits != 2048 && nbits != 3072) ++ 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; ++ ++ if (testparms) ++ { ++ /* Parameters to derive the key are given. */ ++ /* Note that we explicitly need to setup the values of tbl ++ because some compilers (e.g. OpenWatcom, IRIX) don't allow ++ to initialize a structure with automatic variables. */ ++ struct { const char *name; gcry_mpi_t *value; } tbl[] = { ++ { "e" }, ++ { "p" }, ++ { "q" }, ++ { NULL } ++ }; ++ int idx; ++ gcry_sexp_t oneparm; ++ ++ tbl[0].value = &e; ++ tbl[1].value = &p; ++ tbl[2].value = &q; ++ ++ for (idx=0; tbl[idx].name; idx++) ++ { ++ oneparm = sexp_find_token (testparms, tbl[idx].name, 0); ++ if (oneparm) ++ { ++ *tbl[idx].value = sexp_nth_mpi (oneparm, 1, ++ GCRYMPI_FMT_USG); ++ sexp_release (oneparm); ++ } ++ } ++ for (idx=0; tbl[idx].name; idx++) ++ if (!*tbl[idx].value) ++ break; ++ if (tbl[idx].name) ++ { ++ /* At least one parameter is missing. */ ++ for (idx=0; tbl[idx].name; idx++) ++ _gcry_mpi_release (*tbl[idx].value); ++ return GPG_ERR_MISSING_VALUE; ++ } ++ } ++ else ++ { ++ if (use_e < 65537) ++ use_e = 65537; /* This is the smallest value allowed by FIPS */ ++ ++ e = mpi_alloc( (32+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB ); ++ ++ use_e |= 1; /* make sure this is odd */ ++ mpi_set_ui (e, use_e); ++ ++ p = mpi_snew (pbits); ++ q = mpi_snew (pbits); ++ } ++ ++ n = mpi_new (nbits); ++ d = mpi_snew (nbits); ++ u = mpi_snew (nbits); ++ ++ /* prepare approximate minimum p and q */ ++ minp = mpi_new (pbits); ++ mpi_set_ui (minp, 0xB504F334); ++ mpi_lshift (minp, minp, pbits - 32); ++ ++ /* prepare minimum p and q difference */ ++ diff = mpi_new (pbits); ++ mindiff = mpi_new (pbits - 99); ++ mpi_set_ui (mindiff, 1); ++ mpi_lshift (mindiff, mindiff, pbits - 100); ++ ++ p1 = mpi_snew (pbits); ++ q1 = mpi_snew (pbits); ++ g = mpi_snew (pbits); ++ ++retry: ++ /* generate p and q */ ++ for (i = 0; i < 5 * pbits; i++) ++ { ++ ploop: ++ if (!testparms) ++ { ++ _gcry_mpi_randomize (p, pbits, random_level); ++ } ++ if (mpi_cmp (p, minp) < 0) ++ { ++ if (testparms) goto err; ++ goto ploop; ++ } ++ ++ mpi_sub_ui (p1, p, 1); ++ if (mpi_gcd (g, p1, e)) ++ { ++ if (_gcry_fips186_4_prime_check (p, pbits) != GPG_ERR_NO_ERROR) ++ { ++ /* not a prime */ ++ if (testparms) goto err; ++ } ++ else ++ break; ++ } ++ else if (testparms) goto err; ++ } ++ if (i >= 5 * pbits) ++ goto err; ++ ++ for (i = 0; i < 5 * pbits; i++) ++ { ++ qloop: ++ if (!testparms) ++ { ++ _gcry_mpi_randomize (q, pbits, random_level); ++ } ++ if (mpi_cmp (q, minp) < 0) ++ { ++ if (testparms) goto err; ++ goto qloop; ++ } ++ if (mpi_cmp (p, q) < 0) ++ { ++ pqswitch = 1; ++ mpi_sub (diff, q, p); ++ } ++ else ++ { ++ pqswitch = 0; ++ mpi_sub (diff, p, q); ++ } ++ if (mpi_cmp (diff, mindiff) < 0) ++ { ++ if (testparms) goto err; ++ goto qloop; ++ } ++ ++ mpi_sub_ui (q1, q, 1); ++ if (mpi_gcd (g, q1, e)) ++ { ++ if (_gcry_fips186_4_prime_check (q, pbits) != GPG_ERR_NO_ERROR) ++ { ++ /* not a prime */ ++ if (testparms) goto err; ++ } ++ else ++ break; ++ } ++ else if (testparms) goto err; ++ } ++ if (i >= 5 * pbits) ++ goto err; ++ ++ if (testparms) ++ { ++ mpi_clear (p); ++ mpi_clear (q); ++ } ++ else ++ { ++ gcry_mpi_t f; ++ ++ if (pqswitch) ++ { ++ gcry_mpi_t tmp; ++ ++ tmp = p; ++ p = q; ++ q = tmp; ++ } ++ ++ f = mpi_snew (nbits); ++ ++ /* calculate the modulus */ ++ mpi_mul(n, p, q); ++ ++ /* calculate the secret key d = e^1 mod phi */ ++ mpi_gcd (g, p1, q1); ++ mpi_fdiv_q (f, p1, g); ++ mpi_mul (f, f, q1); ++ ++ mpi_invm (d, e, f); ++ ++ _gcry_mpi_release (f); ++ ++ if (mpi_get_nbits (d) < pbits) goto retry; ++ ++ /* calculate the inverse of p and q (used for chinese remainder theorem)*/ ++ mpi_invm(u, p, q ); ++ } ++ ++ ec = 0; ++ ++ if( DBG_CIPHER ) ++ { ++ log_mpidump(" p= ", p ); ++ log_mpidump(" q= ", q ); ++ log_mpidump(" n= ", n ); ++ log_mpidump(" e= ", e ); ++ log_mpidump(" d= ", d ); ++ log_mpidump(" u= ", u ); ++ } ++ ++err: ++ ++ _gcry_mpi_release (p1); ++ _gcry_mpi_release (q1); ++ _gcry_mpi_release (g); ++ _gcry_mpi_release (minp); ++ _gcry_mpi_release (mindiff); ++ _gcry_mpi_release (diff); ++ ++ sk->n = n; ++ sk->e = e; ++ sk->p = p; ++ sk->q = q; ++ sk->d = d; ++ sk->u = u; ++ ++ /* Now we can test our keys. */ ++ if (ec || (!testparms && test_keys (sk, nbits - 64))) ++ { ++ _gcry_mpi_release (sk->n); sk->n = NULL; ++ _gcry_mpi_release (sk->e); sk->e = NULL; ++ _gcry_mpi_release (sk->p); sk->p = NULL; ++ _gcry_mpi_release (sk->q); sk->q = NULL; ++ _gcry_mpi_release (sk->d); sk->d = NULL; ++ _gcry_mpi_release (sk->u); sk->u = NULL; ++ if (!ec) ++ { ++ fips_signal_error ("self-test after key generation failed"); ++ return GPG_ERR_SELFTEST_FAILED; ++ } ++ } ++ ++ return ec; ++} ++ ++ + /* Helper for generate_x931. */ + static gcry_mpi_t + gen_x931_parm_xp (unsigned int nbits) +@@ -799,7 +1072,7 @@ rsa_generate (const gcry_sexp_t genparms + } + } + +- if (deriveparms || (flags & PUBKEY_FLAG_USE_X931) || fips_mode ()) ++ if (deriveparms || (flags & PUBKEY_FLAG_USE_X931)) + { + int swapped; + ec = generate_x931 (&sk, nbits, evalue, deriveparms, &swapped); +@@ -819,9 +1092,14 @@ rsa_generate (const gcry_sexp_t genparms + sexp_release (l1); + } + } ++ deriveparms = (genparms? ++ sexp_find_token (genparms, "test-parms", 0) : NULL); + /* Generate. */ +- ec = generate_std (&sk, nbits, evalue, +- !!(flags & PUBKEY_FLAG_TRANSIENT_KEY)); ++ if (deriveparms || fips_mode()) ++ ec = generate_fips (&sk, nbits, evalue, deriveparms, !!(flags & PUBKEY_FLAG_TRANSIENT_KEY)); ++ else ++ ec = generate_std (&sk, nbits, evalue, !!(flags & PUBKEY_FLAG_TRANSIENT_KEY)); ++ sexp_release (deriveparms); + } + + if (!ec) +diff -up libgcrypt-1.6.3/src/g10lib.h.fips-keygen libgcrypt-1.6.3/src/g10lib.h +--- libgcrypt-1.6.3/src/g10lib.h.fips-keygen 2015-02-23 11:55:58.000000000 +0100 ++++ libgcrypt-1.6.3/src/g10lib.h 2015-03-06 16:38:56.699052607 +0100 +@@ -259,6 +259,9 @@ gpg_err_code_t _gcry_generate_fips186_3_ + int *r_counter, + void **r_seed, size_t *r_seedlen, int *r_hashalgo); + ++gpg_err_code_t _gcry_fips186_4_prime_check ++ (const gcry_mpi_t x, unsigned int bits); ++ + + /* Replacements of missing functions (missing-string.c). */ + #ifndef HAVE_STPCPY +diff -up libgcrypt-1.6.3/tests/keygen.c.fips-keygen libgcrypt-1.6.3/tests/keygen.c +--- libgcrypt-1.6.3/tests/keygen.c.fips-keygen 2015-03-06 16:38:56.661052411 +0100 ++++ libgcrypt-1.6.3/tests/keygen.c 2015-03-06 16:38:56.699052607 +0100 +@@ -215,12 +215,12 @@ check_rsa_keys (void) + + + if (verbose) +- show ("creating 1024 bit RSA key with e=257\n"); ++ show ("creating 1024 bit RSA key with e=65539\n"); + rc = gcry_sexp_new (&keyparm, + "(genkey\n" + " (rsa\n" + " (nbits 4:1024)\n" +- " (rsa-use-e 3:257)\n" ++ " (rsa-use-e 5:65539)\n" + " ))", 0, 1); + if (rc) + die ("error creating S-expression: %s\n", gpg_strerror (rc)); +@@ -229,7 +229,7 @@ check_rsa_keys (void) + if (rc) + die ("error generating RSA key: %s\n", gpg_strerror (rc)); + +- check_generated_rsa_key (key, 257); ++ check_generated_rsa_key (key, 65539); + gcry_sexp_release (key); + + if (verbose) diff --git a/libgcrypt.spec b/libgcrypt.spec index 1a71b93..418dbc8 100644 --- a/libgcrypt.spec +++ b/libgcrypt.spec @@ -1,6 +1,6 @@ Name: libgcrypt -Version: 1.6.2 -Release: 4%{?dist} +Version: 1.6.3 +Release: 1%{?dist} URL: http://www.gnupg.org/ Source0: libgcrypt-%{version}-hobbled.tar.xz # The original libgcrypt sources now contain potentially patented ECC @@ -40,7 +40,7 @@ Patch18: libgcrypt-1.6.2-fips-ctor.patch # Make it possible to run the test suite in the FIPS mode Patch19: libgcrypt-1.6.2-fips-test.patch # Make the FIPS RSA keygen to be FIPS 186-4 compliant -Patch20: libgcrypt-1.6.2-rsa-fips-keygen.patch +Patch20: libgcrypt-1.6.3-rsa-fips-keygen.patch # update the selftests for new FIPS requirements Patch22: libgcrypt-1.6.2-fips-reqs.patch @@ -201,6 +201,9 @@ exit 0 %license COPYING %changelog +* Fri Mar 6 2015 Tomáš Mráz 1.6.3-1 +- new upstream version + * Wed Feb 25 2015 Tomáš Mráz 1.6.2-4 - do not initialize secure memory during the selftest (#1195850) diff --git a/sources b/sources index d296f4f..04e70c5 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -e682099d3bf9cd13802e5a5e67a66544 libgcrypt-1.6.2-hobbled.tar.xz +cbb7aa4b8c4c63f24e954fbf00e16335 libgcrypt-1.6.3-hobbled.tar.xz