From 1521b4e1a94b052010807f68b024bfc7af5961bc53aed5391c0363feba11c8dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ismail=20D=C3=B6nmez?= Date: Tue, 2 Sep 2014 17:36:56 +0000 Subject: [PATCH] Accepting request 247239 from home:vitezslav_cizek:branches:devel:libraries:c_c++ - 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 OBS-URL: https://build.opensuse.org/request/show/247239 OBS-URL: https://build.opensuse.org/package/show/devel:libraries:c_c++/libgcrypt?expand=0&rev=61 --- ...terministic-Random-Bit-Generator.patch.bz2 | 3 - cavs-test.sh | 61 + cavs_driver.pl | 3072 +++++++++++++++++ drbg_test.patch | 1303 +++++++ libgcrypt.changes | 15 + libgcrypt.spec | 31 +- ...A-Deterministic-Random-Bit-Generator.patch | 2406 +++++++++++++ ...ch => v9-0007-User-interface-to-DRBG.patch | 90 +- 8 files changed, 6947 insertions(+), 34 deletions(-) delete mode 100644 0001-SP800-90A-Deterministic-Random-Bit-Generator.patch.bz2 create mode 100644 cavs-test.sh create mode 100644 cavs_driver.pl create mode 100644 drbg_test.patch create mode 100644 v9-0001-SP800-90A-Deterministic-Random-Bit-Generator.patch rename 0007-User-interface-to-DRBG.patch => v9-0007-User-interface-to-DRBG.patch (72%) diff --git a/0001-SP800-90A-Deterministic-Random-Bit-Generator.patch.bz2 b/0001-SP800-90A-Deterministic-Random-Bit-Generator.patch.bz2 deleted file mode 100644 index 6bc7af4..0000000 --- a/0001-SP800-90A-Deterministic-Random-Bit-Generator.patch.bz2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bfa2d8bbd979682e3e33455481daeec820fd02b556bdfa8a69a890f20ab9cea1 -size 16119 diff --git a/cavs-test.sh b/cavs-test.sh new file mode 100644 index 0000000..c62bbf7 --- /dev/null +++ b/cavs-test.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# +# This is the driver script around the actual FIPS testing +# Written by: Stephan Müller +# (c) atsec information security corporation + +# The easiest way to perform the cipher compliance testing +# is the following: +# +# 1. patch/compile/copy the openssl binary with the patch if necessary +# (old versions hang when running the MC test if unpatched) +# +# 2. unpack the test vector ZIP file to a local dir +# +# 3. set PATH in a way that cavs_driver.pl is found +# +# 4. go to the local dir where you unzipped the test vector archive and execute +# $0 +# +# 5. send atsec the prepared CAVS_results-*.zip archive found in the same dir + +DATE=$(date +%Y%m%d) +ARCH=$(uname -m) +PATH=$PATH:$(pwd) + +# test interface to be used +# can be overridden by passing an argument to this script +# possible values are: +# openssl OpenSSL (default) +# libgcrypt Libgcrypt +# cryptoapi Kernel +INTERFACE="libgcrypt" + +if [ "$1" == "-I" -a -n "$2" ]; then + INTERFACE="$2" +fi + +for i in $(find ./ -name "*.req"); +do +( + cd $(dirname $i) || exit 1 + + # We have to see whether we check on DSA based on path name + echo $(dirname $i) | if [ ! $(grep -v DSA) ]; then + /usr/lib/libgcrypt/cavs_driver.pl -I $INTERFACE -D $(basename $i) + else + /usr/lib/libgcrypt/cavs_driver.pl -I $INTERFACE $(basename $i) + fi + + + # for CAVS, we have path/req/ + # and want to have the responses in path/resp/*.rsp + if [ $(basename $(dirname $i)) = "req" ]; then + mkdir ../resp > /dev/null 2>&1 + outfile="$(basename $i .req).rsp" + mv "$outfile" ../resp/ + fi +) & +done +wait +zip -r CAVS_results-$ARCH-$DATE.zip $(find ./ -name "*.rsp") diff --git a/cavs_driver.pl b/cavs_driver.pl new file mode 100644 index 0000000..482d15c --- /dev/null +++ b/cavs_driver.pl @@ -0,0 +1,3072 @@ +#!/usr/bin/env perl +# +# $Id: cavs_driver.pl 3235 2014-04-01 06:24:16Z smueller $ +# +# CAVS test driver (based on the OpenSSL driver) +# Written by: Stephan Müller +# Werner Koch (libgcrypt interface) +# Tomas Mraz (addition of DSA2) +# Copyright (c) atsec information security corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# NO WARRANTY +# +# BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +# FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +# OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +# PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +# OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +# TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +# PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +# REPAIR OR CORRECTION. +# +# IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +# WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +# REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +# INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +# OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +# TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +# YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +# PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGES. +# +# +# test execution instruction: +# 1. get the request files from the lab +# 2. call each request file from 1. with this program: +# $0 .rep +# 3. send the resulting file .rsp to the lab +# +# +# Test should be easily adoptable to other implementations +# See the first functions for this task +# +# Following tests are covered (others may also be covered +# but have not been tested) +# +# AES +# [CBC|CFB128|ECB|OFB]GFSbox[128|192|256] +# [CBC|CFB128|ECB|OFB]MCT[128|192|256] +# [CBC|CFB128|ECB|OFB]VarKey[128|192|256] +# [CBC|CFB128|ECB|OFB]KeySbox[128|192|256] +# [CBC|CFB128|ECB|OFB]MMT[128|192|256] +# [CBC|CFB128|ECB|OFB]VarTxt[128|192|256] +# +# RSA +# SigGen[15|RSA] +# SigVer15 +# (SigVerRSA is not applicable for OpenSSL as X9.31 padding +# is not done through openssl dgst) +# KeyGen RSA X9.31 +# +# SHA +# SHA[1|224|256|384|512]ShortMsg +# SHA[1|224|256|384|512]LongMsg +# SHA[1|224|256|384|512]Monte +# +# HMAC (SHA - caveat: we only support hash output equal to the block size of +# of the hash - we do not support truncation of the hash; to support +# that, we first need to decipher the HMAC.req file - see hmac_kat() ) +# HMAC +# +# TDES +# T[CBC|CFB??|ECB|OFB]Monte[1|2|3] +# T[CBC|CFB??|ECB|OFB]permop +# T[CBC|CFB??|ECB|OFB]MMT[1|2|3] +# T[CBC|CFB??|ECB|OFB]subtab +# T[CBC|CFB??|ECB|OFB]varkey +# T[CBC|CFB??|ECB|OFB]invperm +# T[CBC|CFB??|ECB|OFB]vartext +# WARNING: TDES in CFB and OFB mode problems see below +# +# ANSI X9.31 RNG +# ANSI931_AES128MCT +# ANSI931_AES128VST +# +# DSA2 +# PQGGen +# PQGVer +# KeyPair +# SigGen +# SigVer +# +# DRBG: +# CTR DRBG +# Hash DRBG +# HMAC DRBG +# with and w/o PR +# +# RC4 (atsec developed tests) +# RC4KeyBD +# RC4MCT +# RC4PltBD +# RC4REGT +# +# +# TDES MCT for CFB and OFB: +# ------------------------- +# The inner loop cannot be handled by this script. If you want to have tests +# for these cipher types, implement your own inner loop and add it to +# crypto_mct. +# +# the value $next_source in crypto_mct is NOT set by the standard implementation +# of this script. It would need to be set as follows for these two (code take +# from fipsdrv.c from libgcrypt - the value input at the end will contain the +# the value for $next_source: +# +# ... inner loop ... +# ... +# get_current_iv (hd, last_iv, blocklen); +# ... encrypt / decrypt (input is the data to be en/decrypted and output is the +# result of operation) ... +# if (encrypt_mode && (cipher_mode == GCRY_CIPHER_MODE_CFB)) +# memcpy (input, last_iv, blocklen); +# else if (cipher_mode == GCRY_CIPHER_MODE_OFB) +# memcpy (input, last_iv, blocklen); +# else if (!encrypt_mode && cipher_mode == GCRY_CIPHER_MODE_CFB) +# { +# /* Reconstruct the output vector. */ +# int i; +# for (i=0; i < blocklen; i++) +# input[i] ^= output[i]; +# } +# ... inner loop ends ... +# ==> now, the value of input is to be put into $next_source + +use strict; +use warnings; +use IPC::Open2; +use Getopt::Std; +use MIME::Base64; + +use Math::BigInt; + +# Contains the command line options +my %opt; + +################################################################# +##### Central interface functions to the external ciphers ####### +################################################################# +# Only these interface routines should be changed in case of +# porting to a new cipher library +# +# For porting to a new library, create implementation of these functions +# and then add pointers to the respective implementation of each +# function to the given variables. + +# common encryption/decryption routine +# $1 key in hex form (please note for 3DES: even when ede3 for three +# independent ciphers is given with the cipher specification, we hand in +# either one key for k1 = k2 = k3, two keys which are concatinated for +# k1 = k3, k2 independent, or three keys which are concatinated for +# k1, k2, k3 independent) +# $2 iv in hex form +# $3 cipher - the cipher string is defined as specified in the openssl +# enc(1ssl) specification for the option "-ciphername" +# (e.g. aes-128-cbc or des-ede3-cbc) +# $4 encrypt=1/decrypt=0 +# $5 de/encrypted data in hex form +# return en/decrypted data in hex form +my $encdec; + +# +# Derive an RSA key from the given X9.31 parameters. +# $1: modulus size +# $2: E in hex form +# $3: Xp1 in hex form +# $4: Xp2 in hex form +# $5: Xp in hex form +# $6: Xq1 in hex form +# $7: Xq2 in hex form +# $8: Xq in hex form +# return: string with the calculated values in hex format, where each value +# is separated from the previous with a \n in the following order: +# P\n +# Q\n +# N\n +# D\n +my $rsa_derive; + +# Sign a message with RSA +# $1: data to be signed in hex form +# $2: Hash algo +# $3: Key file in PEM format with the private key +# return: digest in hex format +my $rsa_sign; + +# Verify a message with RSA +# $1: data to be verified in hex form +# $2: hash algo +# $3: file holding the public RSA key in PEM format +# $4: file holding the signature in binary form +# return: 1 == verified / 0 == not verified +my $rsa_verify; + +# generate a new private RSA key with the following properties: +# exponent is 65537 +# PEM format +# $1 key size in bit +# $2 keyfile name +# return: nothing, but file created +my $gen_rsakey; + +# Creating a hash +# $1: Plaintext in hex form +# $2: hash type in the form documented in openssl's dgst(1ssl) - e.g. +# sha1, sha224, sha256, sha384, sha512 +# return: hash in hex form +my $hash; + +# supplying the call to the external cipher implementation +# that is being used to keep STDIN and STDOUT open +# to maintain the state of the block chaining +# $1: cipher +# $2: 1=encryption, 0=decryption +# $3: buffersize needed for openssl +# $4: encryption key in binary form +# $5: IV in binary form +# return: command line to execute the application +my $state_cipher; +# the only difference of the DES version is that it implements the inner loop +# of the TDES tests +my $state_cipher_des; + +# supplying the call to the external cipher implementation +# that is being used to keep STDIN and STDOUT open +# to maintain the state of the RNG with its seed +# +# input holds seed values +# $1: cipher key in hex format +# $2: DT value in hex format +# $3: V value in hex format +# +# return: command line to execute the application +# +# the application is expected to deliver random values on STDOUT - the script +# reads 128 bits repeatedly where the state of the RNG must be retained +# between the reads. The output of the RNG on STDOUT is assumed to be binary. +my $state_rng; + +# Generate an HMAC based on SHAx +# $1: Key to be used for the HMAC in hex format +# $2: length of the hash to be calculated in bits +# $3: Message for which the HMAC shall be calculated in hex format +# $4: hash type (1 - SHA1, 224 - SHA224, and so on) +# return: calculated HMAC in hex format +my $hmac; + +# +# Generate the P, Q, G, Seed, counter, h (value used to generate g) values +# for DSA +# $1: modulus size +# $2: q size +# $3: seed (might be empty string) +# return: string with the calculated values in hex format, where each value +# is separated from the previous with a \n in the following order: +# P\n +# Q\n +# G\n +# Seed\n +# counter\n +# h +my $dsa_pqggen; + +# Generate the G value from P and Q +# for DSA +# $1: modulus size +# $2: q size +# $3: P in hex form +# $4: Q in hex form +# return: string with the calculated values in hex format, where each value +# is separated from the previous with a \n in the following order: +# P\n +# Q\n +# G\n +my $dsa_ggen; + +# +# Generate an DSA public key from the provided parameters: +# $1: Name of file to create +# $2: P in hex form +# $3: Q in hex form +# $4: G in hex form +# $5: Y in hex form +my $dsa_genpubkey; + +# Verify a message with DSA +# $1: data to be verified in hex form +# $2: file holding the public DSA key in PEM format +# $3: R value of the signature +# $4: S value of the signature +# return: 1 == verified / 0 == not verified +my $dsa_verify; + +# generate a new DSA key with the following properties: +# PEM format +# $1: modulus size +# $2: q size +# $3 keyfile name +# return: file created with key, string with values of P, Q, G in hex format +my $gen_dsakey; + +# generate a new DSA private key XY parameters in domain: +# PEM format +# $1: P in hex form +# $2: Q in hex form +# $3: G in hex form +# return: string with values of X, Y in hex format +my $gen_dsakey_domain; + +# Sign a message with DSA +# $1: data to be signed in hex form +# $2: Key file in PEM format with the private key +# return: hash of digest information in hex format with Y, R, S as keys +my $dsa_sign; + +# interface with SP800-90A DRBG +# $1 cipher - the sign whether prediction resistance is required is visible on +# set additional entropy +# $2 expected length of output +# $3 entropy in hex +# $4 nonce in hex +# $5 personalization string in hex - if "z", string was empty +# $6 1st additional input in hex - if "z", string was empty +# $7 2nd additional input in hex - if "z", string was empty +# $8 1st additional entropy in hex - if "z", string was empty +# $9 2nd additional entropy in hex - if "z", string was empty +# return: random value in hex format +my $drbg; + +################################################################ +##### OpenSSL interface functions +################################################################ +sub openssl_encdec($$$$$) { + my $key=shift; + my $iv=shift; + my $cipher=shift; + my $enc = (shift) ? "-e" : "-d"; + my $data=shift; + + # We only invoke the driver with the IV parameter, if we have + # an IV, otherwise, we skip it + $iv = "-iv $iv" if ($iv); + + $data=hex2bin($data); + my $program="openssl enc -$cipher -nopad -nosalt -K $key $enc $iv"; + $program = "rc4 -k $key" if $opt{'R'}; #for ARCFOUR, no IV must be given + $data=pipe_through_program($data,$program); + return bin2hex($data); +} + +sub openssl_rsa_sign($$$) { + my $data = shift; + my $cipher = shift; + my $keyfile = shift; + + $data=hex2bin($data); + die "ARCFOUR not available for RSA" if $opt{'R'}; + $data=pipe_through_program($data, + "openssl dgst -$cipher -binary -sign $keyfile"); + return bin2hex($data); +} + +sub openssl_rsa_verify($$$$) { + my $data = shift; + my $cipher = shift; + my $keyfile = shift; + my $sigfile = shift; + + $data = hex2bin($data); + die "ARCFOUR not available for RSA" if $opt{'R'}; + $data = pipe_through_program($data, + "openssl dgst -$cipher -binary -verify $keyfile -signature $sigfile"); + + # Parse through the OpenSSL output information + return ($data =~ /OK/); +} + +sub openssl_gen_rsakey($$) { + my $keylen = shift; + my $file = shift; + + die "ARCFOUR not available for RSA" if $opt{'R'}; + # generating of a key with exponent 0x10001 + my @args = ("openssl", "genrsa", "-F4", "-out", "$file", "$keylen"); + system(@args) == 0 + or die "system @args failed: $?"; + die "system @args failed: file $file not created" if (! -f $file); +} + +sub openssl_hash($$) { + my $pt = shift; + my $cipher = shift; + + die "ARCFOUR not available for hashes" if $opt{'R'}; + my $hash = hex2bin($pt); + #bin2hex not needed as the '-hex' already converts it + return pipe_through_program($hash, "openssl dgst -$cipher -hex"); +} + +sub openssl_state_cipher($$$$$) { + my $cipher = shift; + my $encdec = shift; + my $bufsize = shift; + my $key = shift; + my $iv = shift; + + my $enc = $encdec ? "-e": "-d"; + + # We only invoke the driver with the IV parameter, if we have + # an IV, otherwise, we skip it + $iv = "-iv ".bin2hex($iv) if ($iv); + + my $out = "openssl enc -'$cipher' $enc -nopad -nosalt -bufsize $bufsize -K ".bin2hex($key)." $iv"; + #for ARCFOUR, no IV must be given + $out = "rc4 -k " . bin2hex($key) if $opt{'R'}; + return $out; +} + +###### End of OpenSSL interface implementation ############ + +########################################################### +###### libgcrypt implementation +########################################################### +sub libgcrypt_encdec($$$$$) { + my $key=shift; + my $iv=shift; + my $cipher=shift; + my $enc = (shift) ? "encrypt" : "decrypt"; + my $data=shift; + + # We only invoke the driver with the IV parameter, if we have + # an IV, otherwise, we skip it + $iv = "--iv $iv" if ($iv); + + my $program="fipsdrv --key $key $iv --algo $cipher $enc"; + + return pipe_through_program($data,$program); + +} + +sub libgcrypt_rsa_derive($$$$$$$$) { + my $n = shift; + my $e = shift; + my $xp1 = shift; + my $xp2 = shift; + my $xp = shift; + my $xq1 = shift; + my $xq2 = shift; + my $xq = shift; + my $sexp; + my @tmp; + + $n = sprintf ("%u", $n); + $e = sprintf ("%u", hex($e)); + $sexp = "(genkey(rsa(nbits " . sprintf ("%u:%s", length($n), $n) . ")" + . "(rsa-use-e " . sprintf ("%u:%s", length($e), $e) . ")" + . "(derive-parms" + . "(Xp1 #$xp1#)" + . "(Xp2 #$xp2#)" + . "(Xp #$xp#)" + . "(Xq1 #$xq1#)" + . "(Xq2 #$xq2#)" + . "(Xq #$xq#))))\n"; + + return pipe_through_program($sexp, "fipsdrv rsa-derive"); +} + + +sub libgcrypt_rsa_sign($$$) { + my $data = shift; + my $hashalgo = shift; + my $keyfile = shift; + + die "ARCFOUR not available for RSA" if $opt{'R'}; + + return pipe_through_program($data, + "fipsdrv --pkcs1 --algo $hashalgo --key $keyfile rsa-sign"); +} + +sub libgcrypt_rsa_verify($$$$) { + my $data = shift; + my $hashalgo = shift; + my $keyfile = shift; + my $sigfile = shift; + + die "ARCFOUR not available for RSA" if $opt{'R'}; + $data = pipe_through_program($data, + "fipsdrv --pkcs1 --algo $hashalgo --key $keyfile --signature $sigfile rsa-verify"); + + # Parse through the output information + return ($data =~ /GOOD signature/); +} + +sub libgcrypt_gen_rsakey($$) { + my $keylen = shift; + my $file = shift; + + die "ARCFOUR not available for RSA" if $opt{'R'}; + my @args = ("fipsdrv --keysize $keylen rsa-gen > $file"); + system(@args) == 0 + or die "system @args failed: $?"; + die "system @args failed: file $file not created" if (! -f $file); +} + +sub libgcrypt_hash($$) { + my $pt = shift; + my $hashalgo = shift; + + my $program = "fipsdrv --algo $hashalgo digest"; + die "ARCFOUR not available for hashes" if $opt{'R'}; + + return pipe_through_program($pt, $program); +} + +sub libgcrypt_state_cipher($$$$$) { + my $cipher = shift; + my $enc = (shift) ? "encrypt": "decrypt"; + my $bufsize = shift; + my $key = shift; + my $iv = shift; + + # We only invoke the driver with the IV parameter, if we have + # an IV, otherwise, we skip it + $iv = "--iv ".bin2hex($iv) if ($iv); + + my $program="fipsdrv --binary --key ".bin2hex($key)." $iv --algo '$cipher' --chunk '$bufsize' $enc"; + + return $program; +} + +sub libgcrypt_state_cipher_des($$$$$) { + my $cipher = shift; + my $enc = (shift) ? "encrypt": "decrypt"; + my $bufsize = shift; + my $key = shift; + my $iv = shift; + + # We only invoke the driver with the IV parameter, if we have + # an IV, otherwise, we skip it + $iv = "--iv ".bin2hex($iv) if ($iv); + + my $program="fipsdrv --algo '$cipher' --mct-server $enc"; + + return $program; +} + +sub libgcrypt_state_rng($$$) { + my $key = shift; + my $dt = shift; + my $v = shift; + + return "fipsdrv --binary --loop --key $key --iv $v --dt $dt random"; +} + +sub libgcrypt_hmac($$$$) { + my $key = shift; + my $maclen = shift; + my $msg = shift; + my $hashtype = shift; + + my $program = "fipsdrv --key $key --algo $hashtype hmac-sha"; + return pipe_through_program($msg, $program); +} + +sub libgcrypt_dsa_pqggen($$$) { + my $mod = shift; + my $qsize = shift; + my $seed = shift; + + my $program = "fipsdrv --keysize $mod --qsize $qsize dsa-pqg-gen"; + return pipe_through_program($seed, $program); +} + +sub libgcrypt_dsa_ggen($$$$) { + my $mod = shift; + my $qsize = shift; + my $p = shift; + my $q = shift; + my $domain = "(domain (p #$p#)(q #$q#))"; + + my $program = "fipsdrv --keysize $mod --qsize $qsize --key \'$domain\' dsa-g-gen"; + return pipe_through_program("", $program); +} + +sub libgcrypt_gen_dsakey($$$) { + my $mod = shift; + my $qsize = shift; + my $file = shift; + + my $program = "fipsdrv --keysize $mod --qsize $qsize --key $file dsa-gen"; + my $tmp; + my %ret; + + die "ARCFOUR not available for DSA" if $opt{'R'}; + + $tmp = pipe_through_program("", $program); + die "dsa key gen failed: file $file not created" if (! -f $file); + + @ret{'P', 'Q', 'G'} = split(/\n/, $tmp); + return %ret; +} + +sub libgcrypt_gen_dsakey_domain($$$) { + my $p = shift; + my $q = shift; + my $g = shift; + my $domain = "(domain (p #$p#)(q #$q#)(g #$g#))"; + + my $program = "fipsdrv --key '$domain' dsa-gen-key"; + + return pipe_through_program("", $program); +} + +sub libgcrypt_dsa_genpubkey($$$$$) { + my $filename = shift; + my $p = shift; + my $q = shift; + my $g = shift; + my $y = shift; + + my $sexp; + + $sexp = "(public-key(dsa(p #$p#)(q #$q#)(g #$g#)(y #$y#)))"; + + open(FH, ">", $filename) or die; + print FH $sexp; + close FH; +} + +sub libgcrypt_dsa_sign($$) { + my $data = shift; + my $keyfile = shift; + my $tmp; + my %ret; + + die "ARCFOUR not available for DSA" if $opt{'R'}; + + $tmp = pipe_through_program($data, "fipsdrv --key $keyfile dsa-sign"); + @ret{'Y', 'R', 'S'} = split(/\n/, $tmp); + return %ret; +} + +sub libgcrypt_dsa_verify($$$$) { + my $data = shift; + my $keyfile = shift; + my $r = shift; + my $s = shift; + + my $ret; + + die "ARCFOUR not available for DSA" if $opt{'R'}; + + my $sigfile = "$keyfile.sig"; + open(FH, ">$sigfile") or die "Cannot create file $sigfile: $?"; + print FH "(sig-val(dsa(r #$r#)(s #$s#)))"; + close FH; + + $ret = pipe_through_program($data, + "fipsdrv --key $keyfile --signature $sigfile dsa-verify"); + unlink ($sigfile); + # Parse through the output information + return ($ret =~ /GOOD signature/); +} + +sub libgcrypt_drbg($$$$$$$$$) { + my $cipher = shift; + my $drbg_expectedlen = shift; + my $drbg_entropy = shift; + my $drbg_nonce = shift; + my $drbg_pers = shift; + my $drbg_addtla = shift; + my $drbg_addtlb = shift; + my $drbg_entpra = shift; + my $drbg_entprb = shift; + my $out = ""; + my $parameter = ""; + my $flags = 0; + + $drbg_expectedlen = $drbg_expectedlen / 8; + + if ($cipher =~ /aes128/) { + $flags |= (1 << 0 | 1 << 13); + } + if ($cipher =~ /aes192/) { + $flags |= (1 << 0 | 1 << 14); + } + if ($cipher =~ /aes256/) { + $flags |= (1 << 0 | 1 << 15); + } + if ($cipher =~ /sha1/) { + $flags |= 1 << 4; + } + if ($cipher =~ /sha256/) { + $flags |= 1 << 6; + } + if ($cipher =~ /sha384/) { + $flags |= 1 << 7; + } + if ($cipher =~ /sha512/) { + $flags |= 1 << 8; + } + if ($cipher =~ /hmac/) { + $flags |= 1 << 12; + } + + if ($drbg_entpra ne "" && $drbg_entprb ne "") { + $flags |= 1 << 28; + } + + $parameter .= " -f $flags"; + # test drvier requires concatenated entropy/nonce + $drbg_entropy = $drbg_entropy . $drbg_nonce; + $parameter .= " -e $drbg_entropy"; + $parameter .= " -l $drbg_expectedlen"; + if ($drbg_pers ne "z") { $parameter .= " -p $drbg_pers"; } + if ($drbg_addtla ne "z") { $parameter .= " -c $drbg_addtla";} + if ($drbg_addtlb ne "z") { $parameter .= " -d $drbg_addtlb";} + if ($drbg_entpra ne "z" && $drbg_entpra ne "") { + $parameter .= " -y $drbg_entpra"; + } + if ($drbg_entprb ne "z" && $drbg_entprb ne "") { + $parameter .= " -z $drbg_entprb"; + } + + $out = pipe_through_program("", + "/usr/lib/libgcrypt/drbg_test $parameter 2>/dev/null"); + + return $out; +} + + +######### End of libgcrypt implementation ################ + +################################################################ +###### Kernel Crypto API interface functions +################################################################ + +#my $DIR = "/sys/kernel/debug/cryptoapi/"; +my $DIR = "/sys/kernel/debug/drbg-cavs/"; +my $CIPHER_AES = Math::BigInt->new("0x0000000000000001"); +my $CIPHER_TDES = Math::BigInt->new("0x0000000000000002"); + +my $CIPHER_SHA1 = Math::BigInt->new("0x0000000000010000"); +my $CIPHER_SHA224 = Math::BigInt->new("0x0000000000020000"); +my $CIPHER_SHA256 = Math::BigInt->new("0x0000000000040000"); +my $CIPHER_SHA384 = Math::BigInt->new("0x0000000000100000"); +my $CIPHER_SHA512 = Math::BigInt->new("0x0000000000200000"); + +my $CIPHER_X931RNG = Math::BigInt->new("0x0000000001000000"); + +my $TYPE_CTR = Math::BigInt->new("0x0010000000000000"); +my $TYPE_GENERIC = Math::BigInt->new("0x0020000000000000"); +my $TYPE_ASM = Math::BigInt->new("0x0040000000000000"); +my $TYPE_CBC = Math::BigInt->new("0x0100000000000000"); +my $TYPE_ECB = Math::BigInt->new("0x0200000000000000"); +my $TYPE_KEEP = Math::BigInt->new("0x0400000000000000"); +my $TYPE_HMAC = Math::BigInt->new("0x1000000000000000"); +my $TYPE_ENC = Math::BigInt->new("0x2000000000000000"); +my $TYPE_DEC = Math::BigInt->new("0x4000000000000000"); + +sub writedata($$) { + my $file=shift; + my $data=shift; + $file = $DIR . $file; + open(FH, ">$file") or die "Cannot open file $file"; + my $dlen = length($data); + my $len = syswrite(FH, $data, $dlen); + if($len != $dlen) { + die "Cannot write data of length $dlen"; + } + close(FH); +} + +sub readdata($$) { + my $file=shift; + my $bytes=shift; + my $out; + $file = $DIR . $file; + open(FH, "<$file") or die "Cannot open file $file"; + my $len = sysread(FH, $out, $bytes); + if(!defined($len)) { + $out=""; + } + return $out; +} + +sub cryptoapi_setupencdec($$$$$) { + my $key=shift; + my $iv=shift; + my $cipher=shift; + my $enc = shift; + my $keep = shift; + + # enc / dec yet unhandled - should not matter anyhow + if($cipher eq "des-ede3-cbc") { + $cipher = $CIPHER_TDES|$TYPE_CBC; + } elsif($cipher eq "des-ede3") { + $cipher = $CIPHER_TDES|$TYPE_ECB; + } elsif($cipher =~ /^aes-\d{3}-cbc$/) { + $cipher = $CIPHER_AES|$TYPE_CBC; + } elsif($cipher =~ /^aes-\d{3}-ecb$/) { + $cipher = $CIPHER_AES|$TYPE_ECB; + } else { + die "Unknown cipher $cipher for kernel crypto API"; + } + if($enc) { + $cipher = $cipher | $TYPE_ENC; + } else { + $cipher = $cipher | $TYPE_DEC; + } + if($keep) { + $cipher = $cipher | $TYPE_KEEP; + } + + # DIFFERENT IMPLEMENTATION enable generic implementation! + # $cipher = $cipher | $TYPE_GENERIC; + + # DIFFERENT IMPLEMENTATION enable asm implementation! + # $cipher = $cipher | $TYPE_ASM; + + $cipher = $cipher->as_hex; + + writedata("cipher", $cipher); + writedata("key", hex2bin($key)); + + # We only invoke the driver with the IV parameter, if we have + # an IV, otherwise, we skip it + if(defined($iv)) { + writedata("iv", hex2bin($iv)); + } +} + +sub cryptoapi_encdec($$$$$) { + my $key=shift; + my $iv=shift; + my $cipher=shift; + my $enc = shift; + my $data = shift; + cryptoapi_setupencdec($key, $iv, $cipher, $enc, 0); + writedata("data", hex2bin($data)); + my $out; + $out = readdata("data", 100000); + return bin2hex($out); +} + +sub cryptoapi_state_cipher($$$$$) { + my $cipher = shift; + my $enc = shift; + my $bufsize = shift; + my $key = bin2hex(shift); + my $iv = shift; + $iv = bin2hex($iv) if ($iv); + cryptoapi_setupencdec($key, $iv, $cipher, $enc, 1); + my $file = $DIR . "data"; + return "statewrapper.pl $file $bufsize"; +} + +sub cryptoapi_hash($$) { + my $pt = shift; + my $hashalgo = shift; + + my $out; + if($hashalgo eq "sha1") { + $hashalgo = $CIPHER_SHA1; + } elsif($hashalgo eq "sha224") { + $hashalgo = $CIPHER_SHA224; + } elsif($hashalgo eq "sha256") { + $hashalgo = $CIPHER_SHA256; + } elsif($hashalgo eq "sha384") { + $hashalgo = $CIPHER_SHA384; + } elsif($hashalgo eq "sha512") { + $hashalgo = $CIPHER_SHA512; + } else { + die "Unknown hashalgo $hashalgo for kernel crypto API"; + } + + # DIFFERENT IMPLEMENTATION enable generic implementation! + # $hashalgo = $hashalgo | $TYPE_GENERIC; + + $hashalgo = $hashalgo->as_hex; + writedata("cipher", $hashalgo); + writedata("data", hex2bin($pt)); + + die "ARCFOUR not available for hashes" if $opt{'R'}; + + $out = readdata("data", 100000); + return bin2hex($out); +} + +sub cryptoapi_hmac($$$$) { + my $key = shift; + my $maclen = shift; + my $msg = shift; + my $hashtype = shift; + + my $out; + if($hashtype eq "1") { + $hashtype = $CIPHER_SHA1 | $TYPE_HMAC; + } elsif($hashtype eq "224") { + $hashtype = $CIPHER_SHA224 | $TYPE_HMAC; + } elsif($hashtype eq "256") { + $hashtype = $CIPHER_SHA256 | $TYPE_HMAC; + } elsif($hashtype eq "384") { + $hashtype = $CIPHER_SHA384 | $TYPE_HMAC; + } elsif($hashtype eq "512") { + $hashtype = $CIPHER_SHA512 | $TYPE_HMAC; + } else { + die "Unknown hashalgo $hashtype for kernel crypto API"; + } + + # DIFFERENT IMPLEMENTATION enable generic implementation! + # $hashtype = $hashalgo | $TYPE_GENERIC; + + $hashtype = $hashtype->as_hex; + writedata("cipher", $hashtype); + writedata("key", hex2bin($key)); + writedata("data", hex2bin($msg)); + + $out = readdata("data", 100000); + return bin2hex($out); +} + +sub cryptoapi_state_rng($$$) { + my $key = shift; + my $dt = shift; + my $v = shift; + + my $seed = $v . $key . $dt; + $seed=hex2bin($seed); + + writedata("cipher", $CIPHER_X931RNG->as_hex); + writedata("key", $seed); + + my $file = $DIR . "data"; + return "statewrapper.pl $file"; +} + +sub cryptoapi_drbg($$$$$$$$$) { + my $cipher = shift; + my $drbg_expectedlen = shift; + my $drbg_entropy = shift; + my $drbg_nonce = shift; + my $drbg_pers = shift; + my $drbg_addtla = shift; + my $drbg_addtlb = shift; + my $drbg_entpra = shift; + my $drbg_entprb = shift; + my $out = ""; + + $drbg_expectedlen = $drbg_expectedlen / 8; + + if ($cipher =~ /hash\s+(\w+)/) { $cipher = $1; } + if ($cipher =~ /hmac\s+(\w+)/) { $cipher = "hmac($1)"; } + if ($cipher =~ /ctr\s+(\w+)/) { $cipher = "ctr($1)"; } + + if ($drbg_entpra ne "" && $drbg_entprb ne "") { + $cipher = "drbg(pr($cipher))"; + } else { + $cipher = "drbg(nopr($cipher))"; + } + + # test drvier requires concatenated entropy/nonce + $drbg_entropy = $drbg_entropy . $drbg_nonce; + writedata("name", $cipher); + writedata("entropy", hex2bin($drbg_entropy)); + if ($drbg_pers ne "z") { writedata("pers", hex2bin($drbg_pers)); } + if ($drbg_addtla ne "z") { writedata("addtla", hex2bin($drbg_addtla));} + if ($drbg_addtlb ne "z") { writedata("addtlb", hex2bin($drbg_addtlb));} + if ($drbg_entpra ne "z" && $drbg_entpra ne "") { + writedata("entpra", hex2bin($drbg_entpra)); + } + if ($drbg_entprb ne "z" && $drbg_entprb ne "") { + writedata("entprb", hex2bin($drbg_entprb)); + } + $out = readdata("data", $drbg_expectedlen); + $out = bin2hex($out); + return $out; +} + +################################################################ +###### Vendor1 interface functions +################################################################ + +sub vendor1_encdec($$$$$) { + my $key=shift; + my $iv=shift; + my $cipher=shift; + my $enc = (shift) ? "encrypt" : "decrypt"; + my $data=shift; + + $data=hex2bin($data); + my $program = "./aes $enc $key"; + $data=pipe_through_program($data,$program); + return bin2hex($data); +} + +sub vendor1_state_cipher($$$$$) { + my $cipher = shift; + my $encdec = shift; + my $bufsize = shift; + my $key = shift; + my $iv = shift; + + $key = bin2hex($key); + my $enc = $encdec ? "encrypt": "decrypt"; + my $out = "./aes $enc $key $bufsize"; + return $out; +} + +##### No other interface functions below this point ###### +########################################################## + +########################################################## +# General helper routines + +# Executing a program by feeding STDIN and retrieving +# STDOUT +# $1: data string to be piped to the app on STDIN +# rest: program and args +# returns: STDOUT of program as string +sub pipe_through_program($@) { + my $in = shift; + my @args = @_; + + my ($CO, $CI); + my $pid = open2($CO, $CI, @args); + + my $out = ""; + my $len = length($in); + my $first = 1; + while (1) { + my $rin = ""; + my $win = ""; + # Output of prog is FD that we read + vec($rin,fileno($CO),1) = 1; + # Input of prog is FD that we write + # check for $first is needed because we can have NULL input + # that is to be written to the app + if ( $len > 0 || $first) { + (vec($win,fileno($CI),1) = 1); + $first=0; + } + # Let us wait for 100ms + my $nfound = select(my $rout=$rin, my $wout=$win, undef, 0.1); + if ( $wout ) { + my $written = syswrite($CI, $in, $len); + die "broken pipe" if !defined $written; + $len -= $written; + substr($in, 0, $written) = ""; + if ($len <= 0) { + close $CI or die "broken pipe: $!"; + } + } + if ( $rout ) { + my $tmp_out = ""; + my $bytes_read = sysread($CO, $tmp_out, 4096); + $out .= $tmp_out; + last if ($bytes_read == 0); + } + } + close $CO or die "broken pipe: $!"; + waitpid $pid, 0; + + return $out; +} + +# +# convert ASCII hex to binary input +# $1 ASCII hex +# return binary representation +sub hex2bin($) { + my $in = shift; + my $len = length($in); + $len = 0 if ($in eq "00"); + return pack("H$len", "$in"); +} + +# +# convert binary input to ASCII hex +# $1 binary value +# return ASCII hex representation +sub bin2hex($) { + my $in = shift; + my $len = length($in)*2; + return unpack("H$len", "$in"); +} + +# $1: binary byte (character) +# returns: binary byte with odd parity using low bit as parity bit +sub odd_par($) { + my $in = ord(shift); + my $odd_count=0; + for(my $i=1; $i<8; $i++) { + $odd_count++ if ($in & (1<<$i)); + } + + my $out = $in; + if ($odd_count & 1) { # check if parity is already odd + $out &= ~1; # clear the low bit + } else { + $out |= 1; # set the low bit + } + + return chr($out); +} + +# DES keys uses only the 7 high bits of a byte, the 8th low bit +# is the parity bit +# as the new key is calculated from oldkey XOR cipher in the MCT test, +# the parity is not really checked and needs to be set to match +# expectation (OpenSSL does not really care, but the FIPS +# test result is expected that the key has the appropriate parity) +# $1: arbitrary binary string +# returns: string with odd parity set in low bit of each byte +sub fix_key_parity($) { + my $in = shift; + my $out = ""; + for (my $i = 0; $i < length($in); $i++) { + $out .= odd_par(substr($in, $i, 1)); + } + + return $out; +} + +#################################################### +# DER/PEM utility functions +# Cf. http://www.columbia.edu/~ariel/ssleay/layman.html + +# Convert unsigned integer to base256 bigint bytes +# $1 integer +# returns base256 octet string +sub int_base256_unsigned($) { + my $n = shift; + + my $out = chr($n & 255); + while ($n>>=8) { + $out = chr($n & 255) . $out; + } + + return $out; +} + +# Convert signed integer to base256 bigint bytes +# $1 integer +# returns base256 octet string +sub int_base256_signed($) { + my $n = shift; + my $negative = ($n < 0); + + if ($negative) { + $n = -$n-1; + } + + my $out = int_base256_unsigned($n); + + if (ord(substr($out, 0, 1)) & 128) { + # it's supposed to be positive but has sign bit set, + # add a leading zero + $out = chr(0) . $out; + } + + if ($negative) { + my $neg = chr(255) x length($out); + $out ^= $neg; + } + + return $out; +} + +# Length header for specified DER object length +# $1 length as integer +# return octet encoding for length +sub der_len($) { + my $len = shift; + + if ($len <= 127) { + return chr($len); + } else { + my $blen = int_base256_unsigned($len); + + return chr(128 | length($blen)) . $blen; + } +} + +# Prepend length header to object +# $1 object as octet sequence +# return length header for object followed by object as octets +sub der_len_obj($) { + my $x = shift; + + return der_len(length($x)) . $x; +} + +# DER sequence +# $* objects +# returns DER sequence consisting of the objects passed as arguments +sub der_seq { + my $seq = join("", @_); + return chr(0x30) . der_len_obj($seq); +} + +# DER bitstring +# $1 input octets (must be full octets, fractional octets not supported) +# returns input encapsulated as bitstring +sub der_bitstring($) { + my $x = shift; + + $x = chr(0) . $x; + + return chr(0x03) . der_len_obj($x); +} + +# base-128-encoded integer, used for object numbers. +# $1 integer +# returns octet sequence +sub der_base128($) { + my $n = shift; + + my $out = chr($n & 127); + + while ($n>>=7) { + $out = chr(128 | ($n & 127)) . $out; + } + + return $out; +} + +# Generating the PEM certificate string +# (base-64-encoded DER string) +# $1 DER string +# returns octet sequence +sub pem_cert($) { + my $n = shift; + + my $out = "-----BEGIN PUBLIC KEY-----\n"; + $out .= encode_base64($n); + $out .= "-----END PUBLIC KEY-----\n"; + + return $out; +} + +# DER object identifier +# $* sequence of id numbers +# returns octets +sub der_objectid { + my $v1 = shift; + my $v2 = shift; + + my $out = chr(40*$v1 + $v2) . join("", map { der_base128($_) } @_); + + return chr(0x06) . der_len_obj($out); +} + +# DER signed integer +# $1 number as octet string (base 256 representation, high byte first) +# returns number in DER integer encoding +sub der_bigint($) { + my $x = shift; + + return chr(0x02) . der_len_obj($x); +} + +# DER positive integer with leading zeroes stripped +# $1 number as octet string (base 256 representation, high byte first) +# returns number in DER integer encoding +sub der_pos_bigint($) { + my $x = shift; + + # strip leading zero digits + $x =~ s/^[\0]+//; + + # need to prepend a zero if high bit set, since it would otherwise be + # interpreted as a negative number. Also needed for number 0. + if (!length($x) || ord(substr($x, 0, 1)) >= 128) { + $x = chr(0) . $x; + } + + return der_bigint($x); +} + +# $1 number as signed integer +# returns number as signed DER integer encoding +sub der_int($) { + my $n = shift; + + return der_bigint(int_base256_signed($n)); +} + +# the NULL object constant +sub der_null() { + return chr(0x05) . chr(0x00); +} + +# Unit test helper +# $1 calculated result +# $2 expected result +# no return value, dies if results differ, showing caller's line number +sub der_test($$) { + my $actual = bin2hex(shift); + my $expected = shift; + + my @caller = caller; + $actual eq $expected or die "Error:line $caller[2]:assertion failed: " + ."$actual != $expected\n"; +} + +# Unit testing for the DER encoding functions +# Examples from http://www.columbia.edu/~ariel/ssleay/layman.html +# No input, no output. Dies if unit tests fail. +sub der_unit_test { + ## uncomment these if you want to test the test framework + #print STDERR "Unit test running\n"; + #der_test chr(0), "42"; + + der_test der_null, "0500"; + + # length bytes + der_test der_len(1), "01"; + der_test der_len(127), "7f"; + der_test der_len(128), "8180"; + der_test der_len(256), "820100"; + der_test der_len(65536), "83010000"; + + # bigint + der_test der_bigint(chr(0)), "020100"; + der_test der_bigint(chr(128)), "020180"; # -128 + der_test der_pos_bigint(chr(128)), "02020080"; # +128 + der_test der_pos_bigint(chr(0).chr(0).chr(1)), "020101"; + der_test der_pos_bigint(chr(0)), "020100"; + + # integers (tests base256 conversion) + der_test der_int( 0), "020100"; + der_test der_int( 127), "02017f"; + der_test der_int( 128), "02020080"; + der_test der_int( 256), "02020100"; + der_test der_int( -1), "0201ff"; + der_test der_int( -128), "020180"; + der_test der_int( -129), "0202ff7f"; + der_test der_int(-65536), "0203ff0000"; + der_test der_int(-65537), "0203feffff"; + + # object encoding, "RSA Security" + der_test der_base128(840), "8648"; + der_test der_objectid(1, 2, 840, 113549), "06062a864886f70d"; + + # Combinations + der_test der_bitstring("ABCD"), "03050041424344"; + der_test der_bitstring(der_null), "0303000500"; + der_test der_seq(der_int(0), der_null), "30050201000500"; + + # The big picture + der_test der_seq(der_seq(der_objectid(1, 2, 840, 113549), der_null), + der_bitstring(der_seq(der_pos_bigint(chr(5)), + der_pos_bigint(chr(3))))), + "3017300a06062a864886f70d05000309003006020105020103"; +} + +#################################################### +# OpenSSL missing functionality workarounds + +## Format of an RSA public key: +# 0:d=0 hl=3 l= 159 cons: SEQUENCE +# 3:d=1 hl=2 l= 13 cons: SEQUENCE +# 5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption +# 16:d=2 hl=2 l= 0 prim: NULL +# 18:d=1 hl=3 l= 141 prim: BIT STRING +# [ sequence: INTEGER (n), INTEGER (e) ] + +# generate RSA pub key in PEM format +# $1: filename where PEM key is to be stored +# $2: n of the RSA key in hex +# $3: e of the RSA key in hex +# return: nothing, but file created +sub gen_pubrsakey($$$) { + my $filename=shift; + my $n = shift; + my $e = shift; + + # make sure the DER encoder works ;-) + der_unit_test(); + + # generate DER encoding of the public key + + my $rsaEncryption = der_objectid(1, 2, 840, 113549, 1, 1, 1); + + my $der = der_seq(der_seq($rsaEncryption, der_null), + der_bitstring(der_seq(der_pos_bigint(hex2bin($n)), + der_pos_bigint(hex2bin($e))))); + + open(FH, ">", $filename) or die; + print FH pem_cert($der); + close FH; + +} + +# generate RSA pub key in PEM format +# +# This implementation uses "openssl asn1parse -genconf" which was added +# in openssl 0.9.8. It is not available in older openssl versions. +# +# $1: filename where PEM key is to be stored +# $2: n of the RSA key in hex +# $3: e of the RSA key in hex +# return: nothing, but file created +sub gen_pubrsakey_using_openssl($$$) { + my $filename=shift; + my $n = shift; + my $e = shift; + + my $asn1 = "asn1=SEQUENCE:pubkeyinfo + +[pubkeyinfo] +algorithm=SEQUENCE:rsa_alg +pubkey=BITWRAP,SEQUENCE:rsapubkey + +[rsa_alg] +algorithm=OID:rsaEncryption +parameter=NULL + +[rsapubkey] +n=INTEGER:0x$n + +e=INTEGER:0x$e"; + + open(FH, ">$filename.cnf") or die "Cannot create file $filename.cnf: $?"; + print FH $asn1; + close FH; + my @args = ("openssl", "asn1parse", "-genconf", "$filename.cnf", "-noout", "-out", "$filename.der"); + system(@args) == 0 or die "system @args failed: $?"; + @args = ("openssl", "rsa", "-inform", "DER", "-in", "$filename.der", + "-outform", "PEM", "-pubin", "-pubout", "-out", "$filename"); + system(@args) == 0 or die "system @args failed: $?"; + die "RSA PEM formatted key file $filename was not created" + if (! -f $filename); + + unlink("$filename.cnf"); + unlink("$filename.der"); +} + +############################################ +# Test cases + +# This is the Known Answer Test +# $1: the string that we have to put in front of the key +# when printing the key +# $2: crypto key1 in hex form +# $3: crypto key2 in hex form (TDES, undef otherwise) +# $4: crypto key3 in hex form (TDES, undef otherwise) +# $5: IV in hex form +# $6: Plaintext (enc=1) or Ciphertext (enc=0) in hex form +# $7: cipher +# $8: encrypt=1/decrypt=0 +# return: string formatted as expected by CAVS +sub kat($$$$$$$$) { + my $keytype = shift; + my $key1 = shift; + my $key2 = shift; + my $key3 = shift; + my $iv = shift; + my $pt = shift; + my $cipher = shift; + my $enc = shift; + + my $out = ""; + + $out .= "$keytype = $key1\n"; + + # this is the concardination of the keys for 3DES + if (defined($key2)) { + $out .= "KEY2 = $key2\n"; + $key1 = $key1 . $key2; + } + if (defined($key3)) { + $out .= "KEY3 = $key3\n"; + $key1= $key1 . $key3; + } + + $out .= "IV = $iv\n" if (defined($iv) && $iv ne ""); + if ($enc) { + $out .= "PLAINTEXT = $pt\n"; + $out .= "CIPHERTEXT = " . &$encdec($key1, $iv, $cipher, 1, $pt) . "\n"; + } else { + $out .= "CIPHERTEXT = $pt\n"; + $out .= "PLAINTEXT = " . &$encdec($key1, $iv, $cipher, 0, $pt) . "\n"; + } + + return $out; +} + +# This is the Known Answer Test for Hashes +# $1: Plaintext in hex form +# $2: hash +# $3: hash length (undef if not applicable) +# return: string formatted as expected by CAVS +sub hash_kat($$$) { + my $pt = shift; + my $cipher = shift; + my $len = shift; + + my $out = ""; + $out .= "Len = $len\n" if (defined($len)); + $out .= "Msg = $pt\n"; + + $pt = "" if(!$len); + $out .= "MD = " . &$hash($pt, $cipher) . "\n"; + return $out; +} + +# Known Answer Test for HMAC hash +# $1: key length in bytes +# $2: MAC length in bytes +# $3: key for HMAC in hex form +# $4: message to be hashed +# return: string formatted as expected by CAVS +sub hmac_kat($$$$) { + my $klen = shift; + my $tlen = shift; + my $key = shift; + my $msg = shift; + + # XXX this is a hack - we need to decipher the HMAC REQ files in a more + # sane way + # + # This is a conversion table from the expected hash output size + # to the assumed hash type - we only define here the block size of + # the underlying hashes and do not allow any truncation + my %hashtype = ( + 20 => 1, + 28 => 224, + 32 => 256, + 48 => 384, + 64 => 512 + ); + + die "Hash output size $tlen is not supported!" + if(!defined($hashtype{$tlen})); + + my $out = ""; + $out .= "Klen = $klen\n"; + $out .= "Tlen = $tlen\n"; + $out .= "Key = $key\n"; + $out .= "Msg = $msg\n"; + $out .= "Mac = " . lc(&$hmac($key, $tlen, $msg, $hashtype{$tlen})) . "\n"; + + return $out; +} + + +# Cipher Monte Carlo Testing +# $1: the string that we have to put in front of the key +# when printing the key +# $2: crypto key1 in hex form +# $3: crypto key2 in hex form (TDES, undef otherwise) +# $4: crypto key3 in hex form (TDES, undef otherwise) +# $5: IV in hex form +# $6: Plaintext (enc=1) or Ciphertext (enc=0) in hex form +# $7: cipher +# $8: encrypt=1/decrypt=0 +# return: string formatted as expected by CAVS +sub crypto_mct($$$$$$$$) { + my $keytype = shift; + my $key1 = hex2bin(shift); + my $key2 = shift; + my $key3 = shift; + my $iv = hex2bin(shift); + my $source_data = hex2bin(shift); + my $cipher = shift; + my $enc = shift; + + my $out = ""; + + $key2 = hex2bin($key2) if (defined($key2)); + $key3 = hex2bin($key3) if (defined($key3)); + my $bufsize = length($source_data); + + # for AES: outer loop 0-99, inner 0-999 based on FIPS compliance tests + # for RC4: outer loop 0-99, inner 0-999 based on atsec compliance tests + # for DES: outer loop 0-399, inner 0-9999 based on FIPS compliance tests + my $ciph = substr($cipher,0,3); + my $oloop=100; + my $iloop=1000; + if ($ciph =~ /des/) {$oloop=400;$iloop=10000;} + + for (my $i=0; $i<$oloop; ++$i) { + $out .= "COUNT = $i\n"; + if (defined($key2)) { + $out .= "$keytype = ". bin2hex($key1). "\n"; + $out .= "KEY2 = ". bin2hex($key2). "\n"; + $key1 = $key1 . $key2; + } else { + $out .= "$keytype = ". bin2hex($key1). "\n"; + } + if(defined($key3)) { + $out .= "KEY3 = ". bin2hex($key3). "\n"; + $key1 = $key1 . $key3; + } + my $keylen = length($key1); + + $out .= "IV = ". bin2hex($iv) . "\n" + if (defined($iv) && $iv ne ""); + + if ($enc) { + $out .= "PLAINTEXT = ". bin2hex($source_data). "\n"; + } else { + $out .= "CIPHERTEXT = ". bin2hex($source_data). "\n"; + } + my ($CO, $CI); + my $cipher_imp = &$state_cipher($cipher, $enc, $bufsize, $key1, $iv); + $cipher_imp = &$state_cipher_des($cipher, $enc, $bufsize, $key1, $iv) if($cipher =~ /des/ && defined($state_cipher_des)); + my $pid = open2($CO, $CI, $cipher_imp); + + my $calc_data = $iv; # CT[j] + my $old_calc_data; # CT[j-1] + my $old_old_calc_data; # CT[j-2] + my $next_source; + + # TDES inner loop implements logic within driver of libgcrypt + if ($cipher =~ /des/ && $opt{'I'} && $opt{'I'} eq 'libgcrypt' ) { + # Need to provide a dummy IV in case of ECB mode. + my $iv_arg = (defined($iv) && $iv ne "") + ? bin2hex($iv) + : "00"x(length($source_data)); + print $CI "1\n" + .$iloop."\n" + .bin2hex($key1)."\n" + .$iv_arg."\n" + .bin2hex($source_data)."\n\n" or die; + chomp(my $line = <$CO>); + $calc_data = hex2bin($line); + chomp($line = <$CO>); + $old_calc_data = hex2bin($line); + chomp($line = <$CO>); + $old_old_calc_data = hex2bin($line); + chomp($line = <$CO>); + $iv = hex2bin($line) if (defined($iv) && $iv ne ""); + chomp($line = <$CO>); + $next_source = hex2bin($line); + # Skip over empty line. + $line = <$CO>; + } else { + for (my $j = 0; $j < $iloop; ++$j) { + if ($cipher =~ /des-ede3-ofb/ || + (!$enc && $cipher =~ /des-ede3-cfb/)) { + die "Implementation lacks support for TDES OFB and TDES CFB in encryption mode - the problem is that we would need to extract the IV of the last round of encryption which would be the input for the next round - see comments in this script for implementation requirements"; + } + $old_old_calc_data = $old_calc_data; + $old_calc_data = $calc_data; + + #print STDERR "source_data=", bin2hex($source_data), "\n"; + syswrite $CI, $source_data or die $!; + my $len = sysread $CO, $calc_data, $bufsize; +#my $a = bin2hex($source_data); +#my $b = bin2hex($calc_data); +#warn "$a $b"; +#sleep 1; + + #print STDERR "len=$len, bufsize=$bufsize\n"; + die if $len ne $bufsize; + #print STDERR "calc_data=", bin2hex($calc_data), "\n"; + + if ( (!$enc && $ciph =~ /des/) || + $ciph =~ /rc4/ || + $cipher =~ /ecb/ ) { + #TDES in decryption mode, RC4 and ECB mode + #have a special rule + $source_data = $calc_data; + } else { + $source_data = $old_calc_data; + } +#my $c = bin2hex($source_data); +#my $d = bin2hex($calc_data); +#warn "$c $d"; + } + } + close $CO; + close $CI; + waitpid $pid, 0; + + if ($enc) { + $out .= "CIPHERTEXT = ". bin2hex($calc_data). "\n\n"; + } else { + $out .= "PLAINTEXT = ". bin2hex($calc_data). "\n\n"; + } + + if ( $ciph =~ /aes/ ) { + $key1 ^= substr($old_calc_data . $calc_data, -$keylen); + #print STDERR bin2hex($key1)."\n"; + } elsif ( $ciph =~ /des/ ) { + die "Wrong keylen $keylen" if ($keylen != 24); + + # $nkey needed as $key holds the concatenation of the + # old key atm + my $nkey = fix_key_parity(substr($key1,0,8) ^ $calc_data); + #print STDERR "KEY1 = ". bin2hex($nkey)."\n"; + if (substr($key1,0,8) ne substr($key1,8,8)) { + #print STDERR "KEY2 recalc: KEY1==KEY3, KEY2 indep. or all KEYs are indep.\n"; + $key2 = fix_key_parity((substr($key1,8,8) ^ $old_calc_data)); + } else { + #print STDERR "KEY2 recalc: KEY1==KEY2==KEY3\n"; + $key2 = fix_key_parity((substr($key1,8,8) ^ $calc_data)); + } + #print STDERR "KEY2 = ". bin2hex($key2)."\n"; + if ( substr($key1,0,8) eq substr($key1,16)) { + #print STDERR "KEY3 recalc: KEY1==KEY2==KEY3 or KEY1==KEY3, KEY2 indep.\n"; + $key3 = fix_key_parity((substr($key1,16) ^ $calc_data)); + } else { + #print STDERR "KEY3 recalc: all KEYs are independent\n"; + $key3 = fix_key_parity((substr($key1,16) ^ $old_old_calc_data)); + } + #print STDERR "KEY3 = ". bin2hex($key3)."\n"; + + # reset the first key - concardination happens at + # beginning of loop + $key1=$nkey; + } elsif ($ciph =~ /rc4/ ) { + $key1 ^= substr($calc_data, 0, 16); + #print STDERR bin2hex($key1)."\n"; + } else { + die "Test limitation: cipher '$cipher' not supported in Monte Carlo testing"; + } + + if ($cipher =~ /des-ede3-ofb/) { + $source_data = $source_data ^ $next_source; + } elsif (!$enc && $cipher =~ /des-ede3-cfb/) { + #TDES decryption CFB has a special rule + $source_data = $next_source; + } elsif ( $ciph =~ /rc4/ || $cipher eq "des-ede3" || $cipher =~ /ecb/) { + #No resetting of IV as the IV is all zero set initially (i.e. no IV) + $source_data = $calc_data; + } elsif (! $enc && $ciph =~ /des/ ) { + #TDES in decryption mode has a special rule + $iv = $old_calc_data; + $source_data = $calc_data; + } else { + $iv = $calc_data; + $source_data = $old_calc_data; + } + } + + return $out; +} + +# Hash Monte Carlo Testing +# $1: Plaintext in hex form +# $2: hash +# return: string formatted as expected by CAVS +sub hash_mct($$) { + my $pt = shift; + my $cipher = shift; + + my $out = ""; + + $out .= "Seed = $pt\n\n"; + + for (my $j=0; $j<100; ++$j) { + $out .= "COUNT = $j\n"; + my $md0=$pt; + my $md1=$pt; + my $md2=$pt; + for (my $i=0; $i<1000; ++$i) { + #print STDERR "outer loop $j; inner loop $i\n"; + my $mi= $md0 . $md1 . $md2; + $md0=$md1; + $md1=$md2; + $md2 = &$hash($mi, $cipher); + $md2 =~ s/\n//; + } + $out .= "MD = $md2\n\n"; + $pt=$md2; + } + + return $out; +} + +# RSA SigGen test +# $1: Message to be signed in hex form +# $2: Hash algorithm +# $3: file name with RSA key in PEM form +# return: string formatted as expected by CAVS +sub rsa_siggen($$$) { + my $data = shift; + my $cipher = shift; + my $keyfile = shift; + + my $out = ""; + + $out .= "SHAAlg = $cipher\n"; + $out .= "Msg = $data\n"; + $out .= "S = " . &$rsa_sign($data, lc($cipher), $keyfile) . "\n"; + + return $out; +} + +# RSA SigVer test +# $1: Message to be verified in hex form +# $2: Hash algoritm +# $3: Signature of message in hex form +# $4: n of the RSA key in hex in hex form +# $5: e of the RSA key in hex in hex form +# return: string formatted as expected by CAVS +sub rsa_sigver($$$$$) { + my $data = shift; + my $cipher = shift; + my $signature = shift; + my $n = shift; + my $e = shift; + + my $out = ""; + + $out .= "SHAAlg = $cipher\n"; + $out .= "e = $e\n"; + $out .= "Msg = $data\n"; + $out .= "S = $signature\n"; + + # XXX maybe a secure temp file name is better here + # but since it is not run on a security sensitive + # system, I hope that this is fine + my $keyfile = "rsa_sigver.tmp.$$"; + gen_pubrsakey($keyfile, $n, $e); + + my $sigfile = "$keyfile.sig"; + open(FH, ">$sigfile") or die "Cannot create file $sigfile: $?"; + print FH hex2bin($signature); + close FH; + + $out .= "Result = " . (&$rsa_verify($data, lc($cipher), $keyfile, $sigfile) ? "P\n" : "F\n"); + + unlink($keyfile); + unlink($sigfile); + + return $out; +} + +# RSA X9.31 key generation test +# $1 modulus size +# $2 e +# $3 xp1 +# $4 xp2 +# $5 Xp +# $6 xq1 +# $7 xq2 +# $8 Xq +# return: string formatted as expected by CAVS +sub rsa_keygen($$$$$$$$) { + my $modulus = shift; + my $e = shift; + my $xp1 = shift; + my $xp2 = shift; + my $Xp = shift; + my $xq1 = shift; + my $xq2 = shift; + my $Xq = shift; + + my $out = ""; + + my $ret = &$rsa_derive($modulus, $e, $xp1, $xp2, $Xp, $xq1, $xq2, $Xq); + + my ($P, $Q, $N, $D) = split(/\n/, $ret); + + $out .= "e = $e\n"; + $out .= "xp1 = $xp1\n"; + $out .= "xp2 = $xp2\n"; + $out .= "Xp = $Xp\n"; + $out .= "p = $P\n"; + $out .= "xq1 = $xq1\n"; + $out .= "xq2 = $xq2\n"; + $out .= "Xq = $Xq\n"; + $out .= "q = $Q\n"; + $out .= "n = $N\n"; + $out .= "d = $D\n\n"; + + return $out; + +} + +# X9.31 RNG test +# $1 key for the AES cipher +# $2 DT value +# $3 V value +# $4 type ("VST", "MCT") +# return: string formatted as expected by CAVS +sub rngx931($$$$) { + my $key=shift; + my $dt=shift; + my $v=shift; + my $type=shift; + + my $out = "Key = $key\n"; + $out .= "DT = $dt\n"; + $out .= "V = $v\n"; + + my $count = 1; + $count = 10000 if ($type eq "MCT"); + + my $rnd_val = ""; + + # we read 16 bytes from RNG + my $bufsize = 16; + + my ($CO, $CI); + my $rng_imp = &$state_rng($key, $dt, $v); + my $pid = open2($CO, $CI, $rng_imp); + for (my $i = 0; $i < $count; ++$i) { + my $len = sysread $CO, $rnd_val, $bufsize; + #print STDERR "len=$len, bufsize=$bufsize\n"; + die "len=$len != bufsize=$bufsize" if $len ne $bufsize; + #print STDERR "calc_data=", bin2hex($rnd_val), "\n"; + } + close $CO; + close $CI; + waitpid $pid, 0; + + $out .= "R = " . bin2hex($rnd_val) . "\n\n"; + + return $out; +} + +sub drbg_kat($$$$$$$$$) { + my $cipher = shift; + my $drbg_expectedlen = shift; + my $drbg_entropy = shift; + my $drbg_nonce = shift; + my $drbg_pers = shift; + my $drbg_addtla = shift; + my $drbg_addtlb = shift; + my $drbg_entpra = shift; + my $drbg_entprb = shift; + my $out = ""; + + my $ret = &$drbg($cipher, $drbg_expectedlen, $drbg_entropy, + $drbg_nonce, $drbg_pers, $drbg_addtla, + $drbg_addtlb, $drbg_entpra, $drbg_entprb); + $out = "ReturnedBits = " . $ret . "\n"; + return $out; +} + +# DSA PQGen test +# $1 modulus size +# $2 q size +# $3 number of rounds to perform the test +# return: string formatted as expected by CAVS +sub dsa_pqgen_driver($$$) { + my $mod = shift; + my $qsize = shift; + my $rounds = shift; + + my $out = ""; + for(my $i=0; $i<$rounds; $i++) { + my $ret = &$dsa_pqggen($mod, $qsize, ""); + my ($P, $Q, $G, $Seed, $c, $H) = split(/\n/, $ret); + die "Return value does not contain all expected values of P, Q, Seed, c for dsa_pqggen" + if (!defined($P) || !defined($Q) || + !defined($Seed) || !defined($c)); + + # now change the counter to decimal as CAVS wants decimal + # counter value although all other is HEX + $c = hex($c); + + $out .= "P = $P\n"; + $out .= "Q = $Q\n"; + $out .= "domain_parameter_seed = $Seed\n"; + $out .= "counter = $c\n\n"; + } + + return $out; +} + +# DSA GGen test +# $1 modulus size +# $2 q size +# $3 p in hex form +# $4 q in hex form +# return: string formatted as expected by CAVS +sub dsa_ggen_driver($$$$) { + my $mod = shift; + my $qsize = shift; + my $p = shift; + my $q = shift; + + my $out = ""; + my $ret = &$dsa_ggen($mod, $qsize, $p, $q); + my ($P, $Q, $G) = split(/\n/, $ret); + die "Return value does not contain all expected values of P, Q, G for dsa_ggen" + if (!defined($P) || !defined($Q) || !defined($G)); + + $out .= "G = $G\n\n"; + + return $out; +} + +# DSA PQVer test +# $1 modulus size +# $2 q size +# $3 p in hex form +# $4 q in hex form +# $5 seed in hex form +# $6 c decimal counter +# return: string formatted as expected by CAVS +sub dsa_pqver_driver($$$$$$) { + my $mod = shift; + my $qsize = shift; + my $p = shift; + my $q = shift; + my $seed = shift; + my $c = shift; + + my $out = ""; + my $ret = &$dsa_pqggen($mod, $qsize, $seed); + my ($P, $Q, $G, $seed2, $c2, $h2) = split(/\n/, $ret); + die "Return value does not contain all expected values of P, Q, G, seed, c for dsa_pqggen" + if (!defined($P) || !defined($Q) || !defined($G) || + !defined($seed2) || !defined($c2)); + + $c2 = hex($c2); + + $out .= "Seed = $seed\n"; + $out .= "c = $c\n"; + + if ($P eq $p && $Q eq $q && $seed eq lc $seed2 && $c eq $c2) { + $out .= "Result = P\n\n"; + } + else { + $out .= "Result = F\n\n"; + } + return $out; +} + +sub hexcomp($$) { + my $a = lc shift; + my $b = lc shift; + + if (length $a < length $b) { + my $c = $a; + $a = $b; + $b = $a; + } + while (length $b < length $a) { + $b = "00$b"; + } + + return $a eq $b; +} + +# DSA PQGVer test +# $1 modulus size +# $2 q size +# $3 p in hex form +# $4 q in hex form +# $5 g in hex form +# $6 seed in hex form +# $7 c decimal counter +# $8 h in hex form +# return: string formatted as expected by CAVS +sub dsa_pqgver_driver($$$$$$$$) { + my $mod = shift; + my $qsize = shift; + my $p = shift; + my $q = shift; + my $g = shift; + my $seed = shift; + my $c = shift; + my $h = shift; + + my $out = ""; + my $ret = &$dsa_pqggen($mod, $qsize, $seed); + my ($P, $Q, $G, $seed2, $c2, $h2) = split(/\n/, $ret); + die "Return value does not contain all expected values of P, Q, G, seed, c, H for dsa_pqggen" + if (!defined($P) || !defined($Q) || !defined($G) || + !defined($seed2) || !defined($c2) || !defined($h2)); + + + + $out .= "Seed = $seed\n"; + $out .= "c = $c\n"; + $out .= "H = $h\n"; + + $c2 = hex($c2); + + if (hexcomp($P, $p) && hexcomp($Q, $q) && hexcomp($G, $g) && hexcomp($seed, $seed2) && + $c == $c2 && hex($h) == hex($h2)) { + $out .= "Result = P\n\n"; + } + else { + $out .= "Result = F\n\n"; + } + + return $out; +} + +# DSA Keypair test +# $1 modulus size +# $2 q size +# $3 number of rounds to perform the test +# return: string formatted as expected by CAVS +sub dsa_keypair_driver($$$) { + my $mod = shift; + my $qsize = shift; + my $rounds = shift; + + my $out = ""; + my $tmpkeyfile = "dsa_siggen.tmp.$$"; + my %pqg = &$gen_dsakey($mod, $qsize, $tmpkeyfile); + $out .= "P = " . $pqg{'P'} . "\n"; + $out .= "Q = " . $pqg{'Q'} . "\n"; + $out .= "G = " . $pqg{'G'} . "\n\n"; + unlink($tmpkeyfile); + + for(my $i=0; $i<$rounds; $i++) { + my $ret = &$gen_dsakey_domain($pqg{'P'}, $pqg{'Q'}, $pqg{'G'}); + my ($X, $Y) = split(/\n/, $ret); + die "Return value does not contain all expected values of X, Y for gen_dsakey_domain" + if (!defined($X) || !defined($Y)); + + $out .= "X = $X\n"; + $out .= "Y = $Y\n\n"; + } + + return $out; +} + +# DSA SigGen test +# $1: Message to be signed in hex form +# $2: file name with DSA key in PEM form +# return: string formatted as expected by CAVS +sub dsa_siggen($$) { + my $data = shift; + my $keyfile = shift; + + my $out = ""; + + my %ret = &$dsa_sign($data, $keyfile); + + $out .= "Msg = $data\n"; + $out .= "Y = " . $ret{'Y'} . "\n"; + $out .= "R = " . $ret{'R'} . "\n"; + $out .= "S = " . $ret{'S'} . "\n"; + + return $out; +} + + +# DSA signature verification +# $1 modulus +# $2 P +# $3 Q +# $4 G +# $5 Y - public key +# $6 r +# $7 s +# $8 message to be verified +# return: string formatted as expected by CAVS +sub dsa_sigver($$$$$$$$) { + my $modulus = shift; + my $p = shift; + my $q = shift; + my $g = shift; + my $y = shift; + my $r = shift; + my $s = shift; + my $msg = shift; + + my $out = ""; + + #PQG are already printed - do not print them here + + $out .= "Msg = $msg\n"; + $out .= "Y = $y\n"; + $out .= "R = $r\n"; + $out .= "S = $s\n"; + + # XXX maybe a secure temp file name is better here + # but since it is not run on a security sensitive + # system, I hope that this is fine + my $keyfile = "dsa_sigver.tmp.$$"; + &$dsa_genpubkey($keyfile, $p, $q, $g, $y); + + $out .= "Result = " . (&$dsa_verify($msg, $keyfile, $r, $s) ? "P\n" : "F\n"); + + unlink($keyfile); + + return $out; +} + +############################################################## +# Parser of input file and generator of result file +# + +sub usage() { + + print STDERR "Usage: +$0 [-R] [-D] [-I name] + +-R execution of ARCFOUR instead of OpenSSL +-I NAME Use interface style NAME: + openssl OpenSSL (default) + libgcrypt Libgcrypt + cryptoapi Kernel +-D SigGen and SigVer are executed with DSA + Please note that the DSA CAVS vectors do not allow distinguishing + them from the RSA vectors. As the RSA test is the default, you have + to supply this option to apply the DSA logic"; +} + +# Parser of CAVS test vector file +# $1: Test vector file +# $2: Output file for test results +# return: nothing +sub parse($$) { + my $infile = shift; + my $outfile = shift; + + my $out = ""; + + # this is my cipher/hash type + my $cipher = ""; + + # Test type + # 1 - cipher known answer test + # 2 - cipher Monte Carlo test + # 3 - hash known answer test + # 4 - hash Monte Carlo test + # 5 - RSA signature generation + # 6 - RSA signature verification + my $tt = 0; + + # Variables for tests + my $keytype = ""; # we can have "KEY", "KEYs", "KEY1" + my $key1 = ""; + my $key2 = undef; #undef needed for allowing + my $key3 = undef; #the use of them as input variables + my $pt = ""; + my $enc = 1; + my $iv = ""; + my $len = undef; #see key2|3 + my $n = ""; + my $e = ""; + my $signature = ""; + my $rsa_keyfile = ""; + my $dsa_keyfile = ""; + my $dt = ""; + my $v = ""; + my $klen = ""; + my $tlen = ""; + my $modulus = ""; + my $qsize = ""; + my $capital_n = 0; + my $num = 0; + my $capital_p = ""; + my $capital_q = ""; + my $capital_g = ""; + my $capital_y = ""; + my $capital_r = ""; + my $capital_h = ""; + my $c = ""; + my $xp1 = ""; + my $xp2 = ""; + my $Xp = ""; + my $xq1 = ""; + my $xq2 = ""; + my $Xq = ""; + my $drbg_expectedlen = ""; + my $drbg_entropy = ""; + my $drbg_nonce = ""; + my $drbg_pers = ""; + my $drbg_addtla = ""; + my $drbg_addtlb = ""; + my $drbg_entpra = ""; + my $drbg_entprb = ""; + + my $mode = ""; + + open(IN, "<$infile"); + while() { + + my $line = $_; + chomp($line); + $line =~ s/\r//; + + my $keylen = ""; + + # Mode and type check + # consider the following parsed line + # '# AESVS MCT test data for CBC' + # '# TDES Multi block Message Test for CBC' + # '# INVERSE PERMUTATION - KAT for CBC' + # '# SUBSTITUTION TABLE - KAT for CBC' + # '# TDES Monte Carlo (Modes) Test for CBC' + # '# "SHA-1 Monte" information for "IBMRHEL5"' + # '# "SigVer PKCS#1 Ver 1.5" information for "IBMRHEL5"' + # '# "SigGen PKCS#1 Ver 1.5" information for "IBMRHEL5"' + # '#RC4VS MCT test data' + + # avoid false positives from user specified 'for "PRODUCT"' strings + my $tmpline = $line; + $tmpline =~ s/ for ".*"//; + + ##### Extract cipher + # XXX there may be more - to be added + if ($tmpline =~ /^#.*(CBC|ECB|OFB|CFB|SHA-|SigGen|SigVer|RC4VS|ANSI X9\.31|Hash sizes tested|PQGGen|KeyGen RSA|KeyPair|PQGVer|DRBG)/) { + if ($tmpline =~ /CBC/) { $mode="cbc"; } + elsif ($tmpline =~ /ECB/) { $mode="ecb"; } + elsif ($tmpline =~ /OFB/) { $mode="ofb"; } + elsif ($tmpline =~ /CFB/) { $mode="cfb"; } + #we do not need mode as the cipher is already clear + elsif ($tmpline =~ /SHA-1/) { $cipher="sha1"; } + elsif ($tmpline =~ /SHA-224/) { $cipher="sha224"; } + elsif ($tmpline =~ /SHA-256/) { $cipher="sha256"; } + elsif ($tmpline =~ /SHA-384/) { $cipher="sha384"; } + elsif ($tmpline =~ /SHA-512/) { $cipher="sha512"; } + #we do not need mode as the cipher is already clear + elsif ($tmpline =~ /RC4VS/) { $cipher="rc4"; } + elsif ($tmpline =~ /SigGen|SigVer/) { + die "Error: X9.31 is not supported" + if ($tmpline =~ /X9/); + $cipher="sha1"; #place holder - might be overwritten later + } + + if ($tmpline =~ /^#.*AESVS/) { + # AES cipher (part of it) + $cipher="aes"; + } + if ($tmpline =~ /^#.*(TDES|KAT)/) { + # TDES cipher (full definition) + # the FIPS-140 test generator tool does not produce + # machine readable output! + if ($mode eq "cbc") { $cipher="des-ede3-cbc"; } + if ($mode eq "ecb") { $cipher="des-ede3"; } + if ($mode eq "ofb") { $cipher="des-ede3-ofb"; } + if ($mode eq "cfb") { $cipher="des-ede3-cfb"; } + } + + # check for RNG + if ($tmpline =~ /ANSI X9\.31/) { + # change the tmpline to add the type of the + # test which is ONLY visible from the file + # name :-( + if ($infile =~ /MCT\.req/) { + $tmpline .= " MCT"; + } elsif ($infile =~ /VST\.req/) { + $tmpline .= " VST"; + } else { + die "Unexpected cipher type with $infile"; + } + } + + if ($tt == 0) { + ##### Identify the test type + if ($tmpline =~ /DRBG/) { + $tt = 18; + die "Interface function for SP800-90A DRBG testing not defined for tested library" + if (!defined($drbg)); + } elsif ($tmpline =~ /PQGVer/) { + $tt = 16; + die "Interface function for DSA PQGVer testing not defined for tested library" + if (!defined($dsa_pqggen)); + } elsif ($tmpline =~ /KeyPair/) { + $tt = 14; + die "Interface function dsa_keygen for DSA key generation not defined for tested library" + if (!defined($gen_dsakey_domain)); + } elsif ($tmpline =~ /KeyGen RSA \(X9\.31\)/) { + $tt = 13; + die "Interface function rsa_derive for RSA key generation not defined for tested library" + if (!defined($rsa_derive)); + } elsif ($tmpline =~ /SigVer/ && $opt{'D'} ) { + $tt = 12; + die "Interface function dsa_verify or dsa_genpubkey for DSA verification not defined for tested library" + if (!defined($dsa_verify) || !defined($dsa_genpubkey)); + } elsif ($tmpline =~ /SigGen/ && $opt{'D'}) { + $tt = 11; + die "Interface function dsa_sign or gen_dsakey for DSA sign not defined for tested library" + if (!defined($dsa_sign) || !defined($gen_dsakey)); + } elsif ($tmpline =~ /PQGGen/) { + $tt = 10; + die "Interface function for DSA PQGGen testing not defined for tested library" + if (!defined($dsa_pqggen) || !defined($dsa_ggen)); + } elsif ($tmpline =~ /Hash sizes tested/) { + $tt = 9; + die "Interface function hmac for HMAC testing not defined for tested library" + if (!defined($hmac)); + } elsif ($tmpline =~ /ANSI X9\.31/ && $tmpline =~ /MCT/) { + $tt = 8; + die "Interface function state_rng for RNG MCT not defined for tested library" + if (!defined($state_rng)); + } elsif ($tmpline =~ /ANSI X9\.31/ && $tmpline =~ /VST/) { + $tt = 7; + die "Interface function state_rng for RNG KAT not defined for tested library" + if (!defined($state_rng)); + } elsif ($tmpline =~ /SigVer/ ) { + $tt = 6; + die "Interface function rsa_verify or gen_rsakey for RSA verification not defined for tested library" + if (!defined($rsa_verify) || !defined($gen_rsakey)); + } elsif ($tmpline =~ /SigGen/ ) { + $tt = 5; + die "Interface function rsa_sign or gen_rsakey for RSA sign not defined for tested library" + if (!defined($rsa_sign) || !defined($gen_rsakey)); + } elsif ($tmpline =~ /Monte|MCT|Carlo/ && $cipher =~ /^sha/) { + $tt = 4; + die "Interface function hash for Hashing not defined for tested library" + if (!defined($hash)); + } elsif ($tmpline =~ /Monte|MCT|Carlo/) { + $tt = 2; + die "Interface function state_cipher for Stateful Cipher operation defined for tested library" + if (!defined($state_cipher) && !defined($state_cipher_des)); + } elsif ($cipher =~ /^sha/) { + $tt = 3; + die "Interface function hash for Hashing not defined for tested library" + if (!defined($hash)); + } else { + $tt = 1; + die "Interface function encdec for Encryption/Decryption not defined for tested library" + if (!defined($encdec)); + } + } + } + + # This is needed as ARCFOUR does not operate with an IV + $iv = "00000000000000000000000000000000" if ($cipher eq "rc4" + && $iv eq "" ); + + # we are now looking for the string + # '# Key Length : 256' + # found in AES + if ($tmpline =~ /^# Key Length.*?(128|192|256)/) { + if ($cipher eq "aes") { + $cipher="$cipher-$1-$mode"; + } else { + die "Error: Key length $1 given for cipher $cipher which is unexpected"; + } + } + + # Get the test data + if ($line =~ /^(KEY|KEY1|Key)\s*=\s*(.*)/) { # found in ciphers and RNG + die "KEY seen twice - input file crap" if ($key1 ne ""); + $keytype=$1; + $key1=$2; + $key1 =~ s/\s//g; #replace potential white spaces + } + elsif ($line =~ /^(KEYs)\s*=\s*(.*)/) { # found in ciphers and RNG + die "KEY seen twice - input file crap" if ($key1 ne ""); + $keytype=$1; + $key1=$2; + $key1 =~ s/\s//g; #replace potential white spaces + $key2 = $key1; + $key3 = $key1; + } + elsif ($line =~ /^KEY2\s*=\s*(.*)/) { # found in TDES + die "First key not set, but got already second key - input file crap" if ($key1 eq ""); + die "KEY2 seen twice - input file crap" if (defined($key2)); + $key2=$1; + $key2 =~ s/\s//g; #replace potential white spaces + } + elsif ($line =~ /^KEY3\s*=\s*(.*)/) { # found in TDES + die "Second key not set, but got already third key - input file crap" if ($key2 eq ""); + die "KEY3 seen twice - input file crap" if (defined($key3)); + $key3=$1; + $key3 =~ s/\s//g; #replace potential white spaces + } + elsif ($line =~ /^IV\s*=\s*(.*)/) { # found in ciphers + die "IV seen twice - input file crap" if ($iv ne ""); + $iv=$1; + $iv =~ s/\s//g; #replace potential white spaces + } + elsif ($line =~ /^PLAINTEXT\s*=\s*(.*)/) { # found in ciphers + if ( $1 !~ /\?/ ) { #only use it if there is valid hex data + die "PLAINTEXT/CIPHERTEXT seen twice - input file crap" if ($pt ne ""); + $pt=$1; + $pt =~ s/\s//g; #replace potential white spaces + $enc=1; + } + } + elsif ($line =~ /^CIPHERTEXT\s*=\s*(.*)/) { # found in ciphers + if ( $1 !~ /\?/ ) { #only use it if there is valid hex data + die "PLAINTEXT/CIPHERTEXT seen twice - input file crap" if ($pt ne ""); + $pt=$1; + $pt =~ s/\s//g; #replace potential white spaces + $enc=0; + } + } + elsif ($line =~ /^Len\s*=\s*(.*)/) { # found in hashs + $len=$1; + } + elsif ($line =~ /^(Msg|Seed)\s*=\s*(.*)/) { # found in hashs + die "Msg/Seed seen twice - input file crap" if ($pt ne ""); + $pt=$2; + } + elsif ($line =~ /^\[A.2.1\s.*\]$/) { # found in DSA2 PQGGen request + $out .= $line . "\n"; # print it + if ($tt == 10) { + # now generate G from PQ + $tt = 15; + } + } + elsif ($line =~ /^\[A.2.2\s.*\]$/) { # found in DSA2 PQGVer request + $out .= $line . "\n"; # print it + if ($tt == 16) { + # now verify PQG + $tt = 17; + } + } + elsif ($line =~ /^\[mod\s*=\s*L=([0-9]*),\s*N=([0-9]*).*\]$/) { # found in DSA2 requests + $modulus = $1; + $qsize = $2; + $out .= $line . "\n\n"; # print it + # clear eventual PQG + $capital_p = ""; + $capital_q = ""; + $capital_g = ""; + # generate the private key with given bit length now + # as we have the required key length in bit + if ($tt == 11) { + $dsa_keyfile = "dsa_siggen.tmp.$$"; + my %pqg = &$gen_dsakey($modulus, $qsize, $dsa_keyfile); + $out .= "P = " . $pqg{'P'} . "\n"; + $out .= "Q = " . $pqg{'Q'} . "\n"; + $out .= "G = " . $pqg{'G'} . "\n\n"; + } + } + elsif ($line =~ /^\[mod\s*=\s*(.*)\]$/) { # found in RSA requests + $modulus = $1; + $out .= $line . "\n\n"; # print it + # generate the private key with given bit length now + # as we have the required key length in bit + if ( $tt == 5 ) { + # XXX maybe a secure temp file name is better here + # but since it is not run on a security sensitive + # system, I hope that this is fine + $rsa_keyfile = "rsa_siggen.tmp.$$"; + &$gen_rsakey($modulus, $rsa_keyfile); + my $modulus = pipe_through_program("", "openssl rsa -pubout -modulus -in $rsa_keyfile"); + $modulus =~ s/Modulus=(.*?)\s(.|\s)*/$1/; + $out .= "n = $modulus\n"; + $out .= "\ne = 10001\n" + } + } + elsif ($line =~ /^SHAAlg\s*=\s*(.*)/) { #found in RSA requests + $cipher=$1; + } + elsif($line =~ /^n\s*=\s*(.*)/) { # found in RSA requests + $out .= $line . "\n"; + $n=$1; + } + elsif ($line =~ /^e\s*=\s*(.*)/) { # found in RSA requests + $e=$1; + } + elsif ($line =~ /^S\s*=\s*(.*)/) { # found in RSA requests + die "S seen twice - input file crap" if ($signature ne ""); + $signature=$1; + } + elsif ($line =~ /^DT\s*=\s*(.*)/) { # X9.31 RNG requests + die "DT seen twice - check input file" + if ($dt ne ""); + $dt=$1; + } + elsif ($line =~ /^V\s*=\s*(.*)/) { # X9.31 RNG requests + die "V seen twice - check input file" + if ($v ne ""); + $v=$1; + } + elsif ($line =~ /^Klen\s*=\s*(.*)/) { # HMAC requests + die "Klen seen twice - check input file" + if ($klen ne ""); + $klen=$1; + } + elsif ($line =~ /^Tlen\s*=\s*(.*)/) { # HMAC RNG requests + die "Tlen seen twice - check input file" + if ($tlen ne ""); + $tlen=$1; + } + elsif ($line =~ /^N\s*=\s*(.*)/) { #DSA KeyPair + die "N seen twice - check input file" + if ($capital_n); + $capital_n = $1; + } + elsif ($line =~ /^Num\s*=\s*(.*)/) { #DSA PQGGen + die "Num seen twice - check input file" + if ($num); + $num = $1; + } + elsif ($line =~ /^P\s*=\s*(.*)/) { #DSA SigVer + die "P seen twice - check input file" + if ($capital_p); + $capital_p = $1; + $out .= $line . "\n"; # print it + } + elsif ($line =~ /^Q\s*=\s*(.*)/) { #DSA SigVer + die "Q seen twice - check input file" + if ($capital_q); + $capital_q = $1; + $out .= $line . "\n"; # print it + } + elsif ($line =~ /^G\s*=\s*(.*)/) { #DSA SigVer + die "G seen twice - check input file" + if ($capital_g); + $capital_g = $1; + $out .= $line . "\n"; # print it + } + elsif ($line =~ /^Y\s*=\s*(.*)/) { #DSA SigVer + die "Y seen twice - check input file" + if ($capital_y); + $capital_y = $1; + } + elsif ($line =~ /^R\s*=\s*(.*)/) { #DSA SigVer + die "R seen twice - check input file" + if ($capital_r); + $capital_r = $1; + } + elsif ($line =~ /^H\s*=\s*(.*)/) { #DSA PQGVer + die "H seen twice - check input file" + if ($capital_h); + $capital_h = $1; + } + elsif ($line =~ /^c\s*=\s*(.*)/) { #DSA PQGVer + die "c seen twice - check input file" + if ($c); + $c = $1; + } + elsif ($line =~ /^xp1\s*=\s*(.*)/) { #RSA key gen + die "xp1 seen twice - check input file" + if ($xp1); + $xp1 = $1; + } + elsif ($line =~ /^xp2\s*=\s*(.*)/) { #RSA key gen + die "xp2 seen twice - check input file" + if ($xp2); + $xp2 = $1; + } + elsif ($line =~ /^Xp\s*=\s*(.*)/) { #RSA key gen + die "Xp seen twice - check input file" + if ($Xp); + $Xp = $1; + } + elsif ($line =~ /^xq1\s*=\s*(.*)/) { #RSA key gen + die "xq1 seen twice - check input file" + if ($xq1); + $xq1 = $1; + } + elsif ($line =~ /^xq2\s*=\s*(.*)/) { #RSA key gen + die "xq2 seen twice - check input file" + if ($xq2); + $xq2 = $1; + } + elsif ($line =~ /^Xq\s*=\s*(.*)/) { #RSA key gen + die "Xq seen twice - check input file" + if ($Xq); + $Xq = $1; + } + # DRBG types + elsif ($line =~ /^\[SHA-1\]/) { $cipher="sha1"; $out .= $line . "\n";} + elsif ($line =~ /^\[SHA-224\]/) { $cipher="sha224"; $out .= $line . "\n";} + elsif ($line =~ /^\[SHA-256\]/) { $cipher="sha256"; $out .= $line . "\n";} + elsif ($line =~ /^\[SHA-384\]/) { $cipher="sha384"; $out .= $line . "\n";} + elsif ($line =~ /^\[SHA-512\]/) { $cipher="sha512"; $out .= $line . "\n";} + elsif ($line =~ /^\[AES-128/) { $cipher="aes128"; $out .= $line . "\n";} + elsif ($line =~ /^\[AES-192/) { $cipher="aes192"; $out .= $line . "\n";} + elsif ($line =~ /^\[AES-256/) { $cipher="aes256"; $out .= $line . "\n";} + elsif ($line =~ /^\[ReturnedBitsLen\s*=\s*(.*)]/) { $drbg_expectedlen = $1; $out .= $line . "\n";} + elsif ($line =~ /^EntropyInput\s*=\s*(.*)/) { $drbg_entropy=$1; $out .= $line . "\n";} + elsif ($line =~ /^Nonce\s*=\s*(.*)/) { $drbg_nonce=$1; $out .= $line . "\n";} + elsif ($line =~ /^PersonalizationString\s*=\s*(.*)/) { + $drbg_pers=$1; + if ($drbg_pers eq "") { + $drbg_pers = "z"; + } + $out .= $line . "\n"; + } + elsif ($line =~ /^AdditionalInput\s*=\s*(.*)/) { + if ($drbg_addtla eq "") { + $drbg_addtla=$1; + if ($drbg_addtla eq "") { + $drbg_addtla = "z"; + } + } else { + $drbg_addtlb=$1; + if ($drbg_addtlb eq "") { + $drbg_addtlb = "z"; + } + } + $out .= $line . "\n"; + } + elsif ($line =~ /^EntropyInputPR\s*=\s*(.*)/) { + if ($drbg_entpra eq "") { + $drbg_entpra=$1; + if ($drbg_entpra eq "") { + $drbg_entpra = "z"; + } + } else { + $drbg_entprb=$1; + if ($drbg_entprb eq "") { + $drbg_entprb = "z"; + } + } + $out .= $line . "\n"; + } + else { + $out .= $line . "\n"; + } + + # call tests if all input data is there + if ($tt == 1) { + if ($key1 ne "" && $pt ne "" && $cipher ne "") { + $out .= kat($keytype, $key1, $key2, $key3, $iv, $pt, $cipher, $enc); + $keytype = ""; + $key1 = ""; + $key2 = undef; + $key3 = undef; + $iv = ""; + $pt = ""; + } + } + elsif ($tt == 2) { + if ($key1 ne "" && $pt ne "" && $cipher ne "") { + $out .= crypto_mct($keytype, $key1, $key2, $key3, $iv, $pt, $cipher, $enc); + $keytype = ""; + $key1 = ""; + $key2 = undef; + $key3 = undef; + $iv = ""; + $pt = ""; + } + } + elsif ($tt == 3) { + if ($pt ne "" && $cipher ne "") { + $out .= hash_kat($pt, $cipher, $len); + $pt = ""; + $len = undef; + } + } + elsif ($tt == 4) { + if ($pt ne "" && $cipher ne "") { + $out .= hash_mct($pt, $cipher); + $pt = ""; + } + } + elsif ($tt == 5) { + if ($pt ne "" && $cipher ne "" && $rsa_keyfile ne "") { + $out .= rsa_siggen($pt, $cipher, $rsa_keyfile); + $pt = ""; + } + } + elsif ($tt == 6) { + if ($pt ne "" && $cipher ne "" && $signature ne "" && $n ne "" && $e ne "") { + $out .= rsa_sigver($pt, $cipher, $signature, $n, $e); + $pt = ""; + $signature = ""; + } + } + elsif ($tt == 7 ) { + if ($key1 ne "" && $dt ne "" && $v ne "") { + $out .= rngx931($key1, $dt, $v, "VST"); + $key1 = ""; + $dt = ""; + $v = ""; + } + } + elsif ($tt == 8 ) { + if ($key1 ne "" && $dt ne "" && $v ne "") { + $out .= rngx931($key1, $dt, $v, "MCT"); + $key1 = ""; + $dt = ""; + $v = ""; + } + } + elsif ($tt == 9) { + if ($klen ne "" && $tlen ne "" && $key1 ne "" && $pt ne "") { + $out .= hmac_kat($klen, $tlen, $key1, $pt); + $key1 = ""; + $tlen = ""; + $klen = ""; + $pt = ""; + } + } + elsif ($tt == 10) { + if ($modulus ne "" && $qsize ne "" && $num > 0) { + $out .= dsa_pqgen_driver($modulus, $qsize, $num); + $num = 0; + } + } + elsif ($tt == 11) { + if ($pt ne "" && $dsa_keyfile ne "") { + $out .= dsa_siggen($pt, $dsa_keyfile); + $pt = ""; + } + } + elsif ($tt == 12) { + if ($modulus ne "" && + $capital_p ne "" && + $capital_q ne "" && + $capital_g ne "" && + $capital_y ne "" && + $capital_r ne "" && + $signature ne "" && + $pt ne "") { + $out .= dsa_sigver($modulus, + $capital_p, + $capital_q, + $capital_g, + $capital_y, + $capital_r, + $signature, + $pt); + + # We do not clear the domain values PQG and + # the modulus value as they + # are specified only once in a file + # and we do not need to print them as they + # are already printed above + $capital_y = ""; + $capital_r = ""; + $signature = ""; + $pt = ""; + } + } + elsif ($tt == 13) { + if($modulus ne "" && + $e ne "" && + $xp1 ne "" && + $xp2 ne "" && + $Xp ne "" && + $xq1 ne "" && + $xq2 ne "" && + $Xq ne "") { + $out .= rsa_keygen($modulus, + $e, + $xp1, + $xp2, + $Xp, + $xq1, + $xq2, + $Xq); + $e = ""; + $xp1 = ""; + $xp2 = ""; + $Xp = ""; + $xq1 = ""; + $xq2 = ""; + $Xq = ""; + } + } + elsif ($tt == 14) { + if ($modulus ne "" && + $qsize ne "" && + $capital_n > 0) { + $out .= dsa_keypair_driver($modulus, + $qsize, + $capital_n); + $capital_n = 0; + } + } + elsif ($tt == 15) { + if ($modulus ne "" && + $qsize ne "" && + $capital_p ne "" && + $capital_q ne "") { + $out .= dsa_ggen_driver($modulus, + $qsize, + $capital_p, + $capital_q); + $capital_p = ""; + $capital_q = ""; + $num--; + } + } + elsif ($tt == 16) { + if ($modulus ne "" && + $qsize ne "" && + $capital_p ne "" && + $capital_q ne "" && + $pt ne "" && + $c ne "") { + $out .= dsa_pqver_driver($modulus, + $qsize, + $capital_p, + $capital_q, + $pt, + $c); + $capital_p = ""; + $capital_q = ""; + $pt = ""; + $c = ""; + } + } + elsif ($tt == 17) { + if ($modulus ne "" && + $qsize ne "" && + $capital_p ne "" && + $capital_q ne "" && + $capital_g ne "" && + $pt ne "" && + $c ne "" && + $capital_h ne "") { + $out .= dsa_pqgver_driver($modulus, + $qsize, + $capital_p, + $capital_q, + $capital_g, + $pt, + $c, + $capital_h); + $capital_p = ""; + $capital_q = ""; + $capital_g = ""; + $pt = ""; + $c = ""; + $capital_h = ""; + } + } + elsif ($tt == 18) { + if ($cipher ne "" && + $drbg_expectedlen ne "" && + $drbg_entropy ne "" && + $drbg_nonce ne "" && + $drbg_pers ne "" && + $drbg_addtla ne "" && + $drbg_addtlb ne "") { + if ($drbg_entpra ne "" && $drbg_entprb eq "") { + next; + } + my $tmpcipher = $cipher; + if ($infile =~ /HMAC_DRBG\.req/) { + $tmpcipher = "hmac $tmpcipher"; + } elsif ($infile =~ /Hash_DRBG\.req/) { + $tmpcipher = "hash $tmpcipher"; + } elsif ($infile =~ /CTR_DRBG\.req/) { + $tmpcipher = "ctr $tmpcipher"; + } else { + die "unknown DRBG input file $infile"; + } + $out .= drbg_kat($tmpcipher, $drbg_expectedlen, + $drbg_entropy, $drbg_nonce, + $drbg_pers, $drbg_addtla, + $drbg_addtlb, $drbg_entpra, + $drbg_entprb); + $drbg_entropy = ""; + $drbg_nonce = ""; + $drbg_pers = ""; + $drbg_addtla = ""; + $drbg_addtlb = ""; + $drbg_entpra = ""; + $drbg_entprb = ""; + } + } + elsif ($tt > 0) { + die "Test case $tt not defined"; + } + } + + close IN; + $out =~ s/\n/\r\n/g; # make it a dos file + open(OUT, ">$outfile") or die "Cannot create output file $outfile: $?"; + print OUT $out; + close OUT; + +} + +# Signalhandler +sub cleanup() { + unlink("rsa_siggen.tmp.$$"); + unlink("rsa_sigver.tmp.$$"); + unlink("rsa_sigver.tmp.$$.sig"); + unlink("rsa_sigver.tmp.$$.der"); + unlink("rsa_sigver.tmp.$$.cnf"); + unlink("dsa_siggen.tmp.$$"); + unlink("dsa_sigver.tmp.$$"); + unlink("dsa_sigver.tmp.$$.sig"); + exit; +} + +############################################################ +# +# let us pretend to be C :-) +sub main() { + + usage() unless @ARGV; + + getopts("DRI:", \%opt) or die "bad option"; + + ##### Set library + + if ( ! defined $opt{'I'} || $opt{'I'} eq 'libgcrypt' ) { + print STDERR "Using libgcrypt interface functions\n"; + $encdec = \&libgcrypt_encdec; + $rsa_sign = \&libgcrypt_rsa_sign; + $rsa_verify = \&libgcrypt_rsa_verify; + $gen_rsakey = \&libgcrypt_gen_rsakey; + $rsa_derive = \&libgcrypt_rsa_derive; + $hash = \&libgcrypt_hash; + $state_cipher = \&libgcrypt_state_cipher; + $state_cipher_des = \&libgcrypt_state_cipher_des; + $state_rng = \&libgcrypt_state_rng; + $hmac = \&libgcrypt_hmac; + $dsa_pqggen = \&libgcrypt_dsa_pqggen; + $dsa_ggen = \&libgcrypt_dsa_ggen; + $gen_dsakey = \&libgcrypt_gen_dsakey; + $gen_dsakey_domain = \&libgcrypt_gen_dsakey_domain; + $dsa_sign = \&libgcrypt_dsa_sign; + $dsa_verify = \&libgcrypt_dsa_verify; + $dsa_genpubkey = \&libgcrypt_dsa_genpubkey; + $drbg = \&libgcrypt_drbg; + } elsif ( $opt{'I'} eq 'openssl' ) { + print STDERR "Using OpenSSL interface functions\n"; + $encdec = \&openssl_encdec; + $rsa_sign = \&openssl_rsa_sign; + $rsa_verify = \&openssl_rsa_verify; + $gen_rsakey = \&openssl_gen_rsakey; + $hash = \&openssl_hash; + $state_cipher = \&openssl_state_cipher; + } elsif ( $opt{'I'} eq 'cryptoapi' ) { + print STDERR "Using cryptoapi interface functions\n"; + $encdec = \&cryptoapi_encdec; + $hash = \&cryptoapi_hash; + $state_cipher = \&cryptoapi_state_cipher; + $hmac = \&cryptoapi_hmac; + $state_rng = \&cryptoapi_state_rng; + $drbg = \&cryptoapi_drbg; + } else { + die "Invalid interface option given"; + } + + my $infile=$ARGV[0]; + die "Error: Test vector file $infile not found" if (! -f $infile); + + my $outfile = $infile; + # let us add .rsp regardless whether we could strip .req + $outfile =~ s/\.req$//; + if ($opt{'R'}) { + $outfile .= ".rc4"; + } else { + $outfile .= ".rsp"; + } + if (-f $outfile) { + die "Output file $outfile could not be removed: $?" + unless unlink($outfile); + } + print STDERR "Performing tests from source file $infile with results stored in destination file $outfile\n"; + + #Signal handler + $SIG{HUP} = \&cleanup; + $SIG{INT} = \&cleanup; + $SIG{QUIT} = \&cleanup; + $SIG{TERM} = \&cleanup; + + # Do the job + parse($infile, $outfile); + + cleanup(); + +} + +########################################### +# Call it +main(); +1; diff --git a/drbg_test.patch b/drbg_test.patch new file mode 100644 index 0000000..db455ac --- /dev/null +++ b/drbg_test.patch @@ -0,0 +1,1303 @@ +Index: libgcrypt-1.6.1/tests/drbg_test.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ libgcrypt-1.6.1/tests/drbg_test.c 2014-09-02 16:49:42.279449470 +0200 +@@ -0,0 +1,1279 @@ ++/* DRBG test for libgcryt ++ Copyright (C) 2014 Stephan Mueller ++ ++ Compile: ++ gcc -g -I/home/sm/hacking/sources/libs/include -L/home/sm/hacking/sources/libs/lib -o drbg_test drbg_test.c -lgcrypt -lpthread ++ ++ Execute: ++ LD_LIBRARY_PATH=/home/sm/hacking/sources/libs/lib/ ./drbg_test ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++#include ++#include ++#include ++#include ++#include "gcrypt.h" ++ ++#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) ++ ++/* bin/hex conversion stolen from OpenSSL */ ++static int bin2hex(const unsigned char *in,int len,char *out) ++{ ++ int n1, n2; ++ unsigned char ch; ++ ++ for (n1=0,n2=0 ; n1 < len ; ++n1) ++ { ++ ch=in[n1] >> 4; ++ if (ch <= 0x09) ++ out[n2++]=ch+'0'; ++ else ++ out[n2++]=ch-10+'a'; ++ ch=in[n1] & 0x0f; ++ if(ch <= 0x09) ++ out[n2++]=ch+'0'; ++ else ++ out[n2++]=ch-10+'a'; ++ } ++ out[n2]='\0'; ++ return n2; ++} ++ ++int hex2bin(const char *in, unsigned char *out) ++{ ++ int n1, n2; ++ unsigned char ch; ++ ++ for (n1=0,n2=0 ; in[n1] && in[n1] != '\n' ; ) ++ { /* first byte */ ++ if ((in[n1] >= '0') && (in[n1] <= '9')) ++ ch = in[n1++] - '0'; ++ else if ((in[n1] >= 'A') && (in[n1] <= 'F')) ++ ch = in[n1++] - 'A' + 10; ++ else if ((in[n1] >= 'a') && (in[n1] <= 'f')) ++ ch = in[n1++] - 'a' + 10; ++ else ++ return -1; ++ if(!in[n1]) ++ { ++ out[n2++]=ch; ++ break; ++ } ++ out[n2] = ch << 4; ++ /* second byte */ ++ if ((in[n1] >= '0') && (in[n1] <= '9')) ++ ch = in[n1++] - '0'; ++ else if ((in[n1] >= 'A') && (in[n1] <= 'F')) ++ ch = in[n1++] - 'A' + 10; ++ else if ((in[n1] >= 'a') && (in[n1] <= 'f')) ++ ch = in[n1++] - 'a' + 10; ++ else ++ return -1; ++ out[n2++] |= ch; ++ } ++ return n2; ++} ++ ++/* 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 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 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 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, ++ }, ++}; ++ ++ ++/* ++ * CAVS Test driver ++ * ++ * @test: one test vector ++ * @pr: true/false for enabling or disabling prediction resistance ++ */ ++int drbg_cavs_test(struct drbg_test_vector *test, unsigned char *buf, ++ size_t buflen) ++{ ++ int ret = -1; ++ struct drbg_test_data test_data; ++ struct drbg_string addtl, pers, testentropy; ++ ++ test_data.testentropy = &testentropy; ++ drbg_string_fill(&testentropy, test->entropy, test->entropylen); ++ drbg_string_fill(&pers, test->pers, test->perslen); ++ ret = gcry_control(GCRYCTL_DRBG_REINIT, test->flags, &pers, &test_data); ++ if(ret) ++ { ++ printf("Test FAIL: re-init DRBG with test entropy\n"); ++ return ret; ++ } ++ ++ drbg_string_fill(&addtl, test->addtla, test->addtllen); ++ if(test->entpra) ++ drbg_string_fill(&testentropy, test->entpra, test->entprlen); ++ gcry_randomize_drbg_test(buf, buflen, GCRY_STRONG_RANDOM, &addtl, ++ &test_data); ++ ++ drbg_string_fill(&addtl, test->addtlb, test->addtllen); ++ if(test->entpra) ++ drbg_string_fill(&testentropy, test->entprb, test->entprlen); ++ ++ gcry_randomize_drbg_test(buf, buflen, GCRY_STRONG_RANDOM, &addtl, ++ &test_data); ++ ++ return ret; ++} ++ ++struct drbg_flags ++{ ++ u_int32_t flags; ++}; ++ ++void builtin_test(void) ++{ ++ /* this must be larger than 128 as otherwise there is a crash */ ++#define OUTLEN 150 ++ char rndbuf[OUTLEN]; ++ char out[200]; ++ 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); ++ gcry_randomize(&rndbuf, OUTLEN, GCRY_STRONG_RANDOM); ++ bin2hex(rndbuf, OUTLEN, out); ++ 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); ++ drbg_cavs_test(&drbg_test_nopr[i], rndbuf, drbg_test_nopr[i].expectedlen); ++ ret = memcmp(drbg_test_nopr[i].expected, rndbuf, drbg_test_nopr[i].expectedlen); ++ 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); ++ drbg_cavs_test(&drbg_test_pr[i], rndbuf, drbg_test_pr[i].expectedlen); ++ ret = memcmp(drbg_test_pr[i].expected, rndbuf, drbg_test_pr[i].expectedlen); ++ 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 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, 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); ++ 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, tmp); ++ *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; ++ long len = 0; ++ unsigned char *buf; ++ unsigned char *outbuf; ++ struct drbg_test_vector exttest; ++#define MAXDATA 256 ++ ++ memset(&exttest, 0, sizeof(struct 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': ++ len = atol(optarg); ++ break; ++ default: ++ usage(); ++ } ++ } ++ ++ if (0 >= len) ++ usage(); ++ ++ buf = malloc(len); ++ if(!buf) { ++ fprintf(stderr, "Cannot allocate %li bytes\n", len); ++ return -1; ++ } ++ outbuf = malloc(len * 2 + 1); ++ if(!outbuf) { ++ fprintf(stderr, "Cannot allocate %li bytes\n", (len*2+1)); ++ return -1; ++ } ++ memset(outbuf, 0, len * 2 + 1); ++ if (exttest.entropy) ++ drbg_cavs_test(&exttest, buf, len); ++ else ++ gcry_randomize(buf, len, GCRY_STRONG_RANDOM); ++ bin2hex(buf, len, outbuf); ++ ++ 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.6.1/Makefile.am +=================================================================== +--- libgcrypt-1.6.1.orig/Makefile.am 2014-01-12 12:19:50.000000000 +0100 ++++ libgcrypt-1.6.1/Makefile.am 2014-09-02 16:51:10.315504510 +0200 +@@ -36,6 +36,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, + # apply version number s to some files and create a VERSION file which diff --git a/libgcrypt.changes b/libgcrypt.changes index 571f1b2..6d58d08 100644 --- a/libgcrypt.changes +++ b/libgcrypt.changes @@ -1,3 +1,18 @@ +------------------------------------------------------------------- +Mon Sep 1 10:57:06 UTC 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 07:43:19 UTC 2014 - meissner@suse.com diff --git a/libgcrypt.spec b/libgcrypt.spec index acee48a..a8942c2 100644 --- a/libgcrypt.spec +++ b/libgcrypt.spec @@ -32,6 +32,9 @@ Source1: ftp://ftp.gnupg.org/gcrypt/libgcrypt/%{name}-%{version}.tar.bz2. Source2: baselibs.conf # http://www.gnupg.org/signature_key.en.html Source4: %{name}.keyring +# cavs test framework +Source5: cavs-test.sh +Source6: cavs_driver.pl Patch0: %{name}-ppc64.patch Patch1: %{name}-strict-aliasing.patch Patch3: %{name}-1.4.1-rijndael_no_strict_aliasing.patch @@ -49,15 +52,16 @@ Patch13: libgcrypt-1.6.1-fips-cavs.patch #PATCH-FIX-SUSE: bnc#724841, fix a random device opening routine Patch14: libgcrypt-1.6.1-fips-cfgrandom.patch # add support for SP800-90A DRBG (fate#316929, bnc#856312) -Patch21: 0001-SP800-90A-Deterministic-Random-Bit-Generator.patch.bz2 +Patch21: v9-0001-SP800-90A-Deterministic-Random-Bit-Generator.patch Patch22: 0002-Compile-DRBG.patch Patch23: 0003-Function-definitions-of-interfaces-for-random.c.patch Patch24: 0004-Invoke-DRBG-from-common-libgcrypt-RNG-code.patch Patch25: 0005-Function-definitions-for-gcry_control-callbacks.patch Patch26: 0006-DRBG-specific-gcry_control-requests.patch -Patch27: 0007-User-interface-to-DRBG.patch +Patch27: v9-0007-User-interface-to-DRBG.patch Patch28: libgcrypt-fix-rng.patch Patch29: libgcrypt-init-at-elf-load-fips.patch +Patch30: drbg_test.patch BuildRequires: automake >= 1.11 BuildRequires: libgpg-error-devel >= 1.11 BuildRequires: libtool @@ -65,8 +69,6 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-build %if 0%{?suse_version} > 1310 BuildRequires: fipscheck %endif -# not for base packages to avoid huge cycles -#BuildRequires: gpg-offline %description Libgcrypt is a general purpose library of cryptographic building @@ -111,6 +113,16 @@ 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 and GPL-2.0+ and LGPL-2.1+ 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 @@ -150,6 +162,7 @@ understanding of applied cryptography is required to use Libgcrypt. %patch27 -p1 %patch28 -p1 %patch29 -p1 +%patch30 -p1 %endif %patch13 -p1 %patch14 -p1 @@ -207,6 +220,12 @@ fipshmac src/.libs/libgcrypt.so.?? make DESTDIR=%{buildroot} install %{?_smp_mflags} rm %{buildroot}%{_libdir}/%{name}.la +# cavs +install -m 0755 -d %{buildroot}/%{_libexecdir}/%{name} +install -m 0755 %{SOURCE5} %{buildroot}/%{_libexecdir}/%{name} +install -m 0755 %{SOURCE6} %{buildroot}/%{_libexecdir}/%{name} +mv %{buildroot}%{_bindir}/fipsdrv %{buildroot}/%{_libexecdir}/%{name} +mv %{buildroot}%{_bindir}/drbg_test %{buildroot}/%{_libexecdir}/%{name} %post -n %{libsoname} -p /sbin/ldconfig @@ -255,4 +274,8 @@ rm %{buildroot}%{_libdir}/%{name}.la %{_bindir}/.hmac256.hmac %doc %{_mandir}/man1/hmac256.1* +%files cavs +%defattr(-,root,root) +%{_libexecdir}/%{name} + %changelog diff --git a/v9-0001-SP800-90A-Deterministic-Random-Bit-Generator.patch b/v9-0001-SP800-90A-Deterministic-Random-Bit-Generator.patch new file mode 100644 index 0000000..b9e54d8 --- /dev/null +++ b/v9-0001-SP800-90A-Deterministic-Random-Bit-Generator.patch @@ -0,0 +1,2406 @@ +From 6e04a47db68a0ae3947dbd5bfdb8c228ddb83c0e Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Mon, 1 Sep 2014 17:53:33 +0200 +Subject: [PATCH v9 1/7] SP800-90A Deterministic Random Bit Generator + +This is a clean-room implementation of the DRBG defined in SP800-90A. +All three viable DRBGs defined in the standard are implemented: + + * HMAC: This is the leanest DRBG and compiled per default + * Hash: The more complex DRBG can be enabled at compile time + * CTR: The most complex DRBG can also be enabled at compile time + +The DRBG implementation offers the following: + + * All three DRBG types are implemented with a derivation function. + * All DRBG types are available with and without prediction resistance. + * All SHA types of SHA-1, SHA-256, SHA-384, SHA-512 are available for + * the HMAC and Hash DRBGs. + * All AES types of AES-128, AES-192 and AES-256 are available for the + * CTR DRBG. + * A self test is implemented with drbg_healthcheck(). + * The FIPS 140-2 continuous self test is implemented. + * Additional cipher primitives, such as Serpent or Twofish, can be + * added to the DRBG without changing the implementation. The only + * change necessary is to the DRBG definition given in the cores[] + * array. + +Signed-off-by: Stephan Mueller +--- + random/drbg.c | 2364 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 2364 insertions(+) + create mode 100644 random/drbg.c + +diff --git a/random/drbg.c b/random/drbg.c +new file mode 100644 +index 0000000..8733f85 +--- /dev/null ++++ b/random/drbg.c +@@ -0,0 +1,2364 @@ ++/* ++ * DRBG: Deterministic Random Bits Generator ++ * Based on NIST Recommended DRBG from NIST SP800-90A with the following ++ * properties: ++ * * CTR DRBG with DF with AES-128, AES-192, AES-256 cores ++ * * Hash DRBG with DF with SHA-1, SHA-256, SHA-384, SHA-512 cores ++ * * HMAC DRBG with DF with SHA-1, SHA-256, SHA-384, SHA-512 cores ++ * * with and without prediction resistance ++ * ++ * Copyright Stephan Mueller , 2014 ++ * ++ * 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. ++ * ++ * ++ * gcry_control GCRYCTL_DRBG_REINIT ++ * ================================ ++ * This control request re-initializes the DRBG completely, i.e. the entire ++ * state of the DRBG is zeroized (with two exceptions listed in ++ * GCRYCTL_DRBG_SET_ENTROPY). ++ * ++ * The control request takes the following values which influences how the DRBG ++ * is re-initialized: ++ * * __u32 flags: This variable specifies the DRBG type to be used for the ++ * next initialization. If set to 0, the previous DRBG type is ++ * used for the initialization. The DRBG type is an OR of the ++ * mandatory flags of the requested DRBG strength and DRBG ++ * cipher type. Optionally, the prediction resistance flag ++ * can be ORed into the flags variable. For example: ++ * - CTR-DRBG with AES-128 without prediction resistance: ++ * DRBG_CTRAES128 ++ * - HMAC-DRBG with SHA-512 with prediction resistance: ++ * DRBG_HMACSHA512 | DRBG_PREDICTION_RESIST ++ * * struct drbg_string *pers: personalization string to be used for ++ * initialization. ++ * * struct drbg_test_data *test: TEST parameter only -- should be NULL in ++ * normal use -- parameter sets predefined ++ * "entropy" ++ * The variable of flags is independent from the pers/perslen variables. If ++ * flags is set to 0 and perslen is set to 0, the current DRBG type is ++ * completely reset without using a personalization string. ++ * ++ * DRBG Usage ++ * ========== ++ * The SP 800-90A DRBG allows the user to specify a personalization string ++ * for initialization as well as an additional information string for each ++ * random number request. The following code fragments show how a caller ++ * uses the kernel crypto API to use the full functionality of the DRBG. ++ * ++ * Usage without any additional data ++ * --------------------------------- ++ * gcry_randomize(outbuf, OUTLEN, GCRY_STRONG_RANDOM); ++ * ++ * ++ * Usage with personalization string during initialization ++ * ------------------------------------------------------- ++ * struct drbg_string pers; ++ * char personalization[11] = "some-string"; ++ * ++ * drbg_string_fill(&pers, personalization, strlen(personalization)); ++ * // The reset completely re-initializes the DRBG with the provided ++ * // personalization string without changing the DRBG type ++ * ret = gcry_control(GCRYCTL_DRBG_REINIT, 0, &pers, NULL); ++ * gcry_randomize(outbuf, OUTLEN, GCRY_STRONG_RANDOM); ++ * ++ * ++ * Usage with additional information string during random number request ++ * --------------------------------------------------------------------- ++ * struct drbg_string addtl; ++ * char addtl_string[11] = "some-string"; ++ * ++ * drbg_string_fill(&addtl, addtl_string, strlen(addtl_string)); ++ * // The following call is a wrapper to gcry_randomize() and returns ++ * // the same error codes. ++ * gcry_randomize_drbg(outbuf, OUTLEN, GCRY_STRONG_RANDOM, &addtl); ++ * ++ * ++ * Usage with personalization and additional information strings ++ * ------------------------------------------------------------- ++ * Just mix both scenarios above. ++ * ++ * ++ * Switch the DRBG type to some other type ++ * --------------------------------------- ++ * // Switch to CTR DRBG AES-128 without prediction resistance ++ * ret = gcry_control(GCRYCTL_DRBG_REINIT, DRBG_NOPR_CTRAES128, NULL, NULL); ++ * gcry_randomize(outbuf, OUTLEN, GCRY_STRONG_RANDOM); ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "g10lib.h" ++#include "random.h" ++#include "rand-internal.h" ++#include "../cipher/bithelp.h" ++ ++/****************************************************************** ++ * Common data structures ++ ******************************************************************/ ++ ++struct drbg_state; ++ ++struct drbg_core ++{ ++ u_int32_t flags; /* flags for the cipher */ ++ __u8 statelen; /* maximum state length */ ++ __u8 blocklen_bytes; /* block size of output in bytes */ ++ int backend_cipher; /* libgcrypt backend cipher */ ++}; ++ ++struct drbg_state_ops ++{ ++ gpg_err_code_t (*update) (struct drbg_state * drbg, ++ struct drbg_string * seed, int reseed); ++ gpg_err_code_t (*generate) (struct drbg_state * drbg, ++ unsigned char *buf, unsigned int buflen, ++ struct drbg_string * addtl); ++}; ++ ++struct drbg_state ++{ ++ unsigned char *V; /* internal state 10.1.1.1 1a) */ ++ unsigned char *C; /* hash: static value 10.1.1.1 1b) ++ * hmac / ctr: key */ ++ size_t reseed_ctr; /* Number of RNG requests since last reseed -- ++ * 10.1.1.1 1c) */ ++ unsigned char *scratchpad; /* some memory the DRBG can use for its ++ * operation -- allocated during init */ ++ int seeded:1; /* DRBG fully seeded? */ ++ int pr:1; /* Prediction resistance enabled? */ ++ int fips_primed:1; /* Continuous test primed? */ ++ unsigned char *prev; /* previous output value of drbg_blocklen for ++ * FIPS 140-2 continuous test */ ++ /* Taken from libgcrypt ANSI X9.31 DRNG: We need to keep track of the ++ * process which did the initialization so that we can detect a fork. ++ * The volatile modifier is required so that the compiler does not ++ * optimize it away in case the getpid function is badly attributed. */ ++ pid_t seed_init_pid; ++ const struct drbg_state_ops *d_ops; ++ const struct drbg_core *core; ++ struct drbg_test_data *test_data; ++}; ++ ++enum drbg_prefixes ++{ ++ DRBG_PREFIX0 = 0x00, ++ DRBG_PREFIX1, ++ DRBG_PREFIX2, ++ DRBG_PREFIX3 ++}; ++ ++#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) ++ ++/*************************************************************** ++ * Backend cipher definitions available to DRBG ++ ***************************************************************/ ++ ++static const struct drbg_core drbg_cores[] = { ++ { ++ /* Hash DRBGs */ ++ .flags = DRBG_HASHSHA1, ++ .statelen = 55, /* 440 bits */ ++ .blocklen_bytes = 20, ++ .backend_cipher = GCRY_MD_SHA1, ++ }, ++ { ++ .flags = DRBG_HASHSHA256, ++ .statelen = 55, /* 440 bits */ ++ .blocklen_bytes = 32, ++ .backend_cipher = GCRY_MD_SHA256, ++ }, ++ { ++ .flags = DRBG_HASHSHA384, ++ .statelen = 111, /* 888 bits */ ++ .blocklen_bytes = 48, ++ .backend_cipher = GCRY_MD_SHA384, ++ }, ++ { ++ .flags = DRBG_HASHSHA512, ++ .statelen = 111, /* 888 bits */ ++ .blocklen_bytes = 64, ++ .backend_cipher = GCRY_MD_SHA512, ++ }, ++ { ++ /* HMAC DRBGs */ ++ .flags = DRBG_HASHSHA1 | DRBG_HMAC, ++ .statelen = 20, /* block length of cipher */ ++ .blocklen_bytes = 20, ++ .backend_cipher = GCRY_MD_SHA1, ++ }, ++ { ++ .flags = DRBG_HASHSHA256 | DRBG_HMAC, ++ .statelen = 32, /* block length of cipher */ ++ .blocklen_bytes = 32, ++ .backend_cipher = GCRY_MD_SHA256, ++ }, ++ { ++ .flags = DRBG_HASHSHA384 | DRBG_HMAC, ++ .statelen = 48, /* block length of cipher */ ++ .blocklen_bytes = 48, ++ .backend_cipher = GCRY_MD_SHA384, ++ }, ++ { ++ .flags = DRBG_HASHSHA512 | DRBG_HMAC, ++ .statelen = 64, /* block length of cipher */ ++ .blocklen_bytes = 64, ++ .backend_cipher = GCRY_MD_SHA512, ++ }, ++ { ++ /* block ciphers */ ++ .flags = DRBG_CTRAES | DRBG_SYM128, ++ .statelen = 32, /* 256 bits as defined in 10.2.1 */ ++ .blocklen_bytes = 16, ++ .backend_cipher = GCRY_CIPHER_AES128, ++ }, ++ { ++ /* block ciphers */ ++ .flags = DRBG_CTRAES | DRBG_SYM192, ++ .statelen = 40, /* 320 bits as defined in 10.2.1 */ ++ .blocklen_bytes = 16, ++ .backend_cipher = GCRY_CIPHER_AES192, ++ }, ++ { ++ /* block ciphers */ ++ .flags = DRBG_CTRAES | DRBG_SYM256, ++ .statelen = 48, /* 384 bits as defined in 10.2.1 */ ++ .blocklen_bytes = 16, ++ .backend_cipher = GCRY_CIPHER_AES256, ++ }, ++}; ++ ++/****************************************************************** ++ ****************************************************************** ++ ****************************************************************** ++ * Generic DRBG code ++ ****************************************************************** ++ ****************************************************************** ++ ******************************************************************/ ++ ++/****************************************************************** ++ * Generic helper functions ++ ******************************************************************/ ++ ++#if 0 ++#define dbg(x) do { log_debug x; } while(0) ++#else ++#define dbg(x) ++#endif ++ ++int drbg_healthcheck (void); ++ ++static inline void * ++drbg_malloc (size_t len) ++{ ++ void *buf; ++ buf = xmalloc_secure (len); ++ if (buf) ++ memset (buf, 0, len); ++ return buf; ++} ++ ++static inline __u8 ++drbg_statelen (struct drbg_state *drbg) ++{ ++ if (drbg && drbg->core) ++ return drbg->core->statelen; ++ return 0; ++} ++ ++static inline __u8 ++drbg_blocklen (struct drbg_state *drbg) ++{ ++ if (drbg && drbg->core) ++ return drbg->core->blocklen_bytes; ++ return 0; ++} ++ ++static inline __u8 ++drbg_keylen (struct drbg_state *drbg) ++{ ++ if (drbg && drbg->core) ++ return (drbg->core->statelen - drbg->core->blocklen_bytes); ++ return 0; ++} ++ ++static inline size_t ++drbg_max_request_bytes (void) ++{ ++ /* SP800-90A requires the limit 2**19 bits, but we return bytes */ ++ return (1 << 16); ++} ++ ++static inline size_t ++drbg_max_addtl (void) ++{ ++ /* SP800-90A requires 2**35 bytes additional info str / pers str */ ++#ifdef __LP64__ ++ return (1UL<<35); ++#else ++ /* ++ * SP800-90A allows smaller maximum numbers to be returned -- we ++ * return SIZE_MAX - 1 to allow the verification of the enforcement ++ * of this value in drbg_healthcheck_sanity. ++ */ ++ return (SIZE_MAX - 1); ++#endif ++} ++ ++static inline size_t ++drbg_max_requests (void) ++{ ++ /* SP800-90A requires 2**48 maximum requests before reseeding */ ++#ifdef __LP64__ ++ return (1UL<<48); ++#else ++ return SIZE_MAX; ++#endif ++} ++ ++/* ++ * Return strength of DRBG according to SP800-90A section 8.4 ++ * ++ * flags: DRBG flags reference ++ * ++ * Return: normalized strength value or 32 as a default to counter ++ * programming errors ++ */ ++static inline unsigned short ++drbg_sec_strength (u_int32_t flags) ++{ ++ if ((flags & DRBG_HASHSHA1) || (flags & DRBG_SYM128)) ++ return 16; ++ else if (flags & DRBG_SYM192) ++ return 24; ++ else if ((flags & DRBG_SYM256) || (flags & DRBG_HASHSHA256) || ++ (flags & DRBG_HASHSHA384) || (flags & DRBG_HASHSHA512)) ++ return 32; ++ else ++ return 32; ++} ++ ++/* ++ * FIPS 140-2 continuous self test ++ * The test is performed on the result of one round of the output ++ * function. Thus, the function implicitly knows the size of the ++ * buffer. ++ * ++ * @drbg DRBG handle ++ * @buf output buffer of random data to be checked ++ * ++ * return: ++ * false on error ++ * true on success ++ */ ++static gpg_err_code_t ++drbg_fips_continuous_test (struct drbg_state *drbg, const unsigned char *buf) ++{ ++ gpg_err_code_t ret = 0; ++ /* skip test if we test the overall system */ ++ if (drbg->test_data) ++ return 1; ++ /* only perform test in FIPS mode */ ++ if (0 == fips_mode ()) ++ return 1; ++ if (!drbg->fips_primed) ++ { ++ /* Priming of FIPS test */ ++ memcpy (drbg->prev, buf, drbg_blocklen (drbg)); ++ drbg->fips_primed = 1; ++ /* return false due to priming, i.e. another round is needed */ ++ return 0; ++ } ++ ret = memcmp (drbg->prev, buf, drbg_blocklen (drbg)); ++ memcpy (drbg->prev, buf, drbg_blocklen (drbg)); ++ /* the test shall pass when the two compared values are not equal */ ++ return ret != 0; ++} ++ ++static inline void drbg_cpu_to_be32(uint32_t val, unsigned char *buf) ++{ ++ struct s { ++ uint32_t conv; ++ }; ++ struct s *conversion = (struct s *) buf; ++ ++ conversion->conv = be_bswap32(val); ++} ++ ++static void ++drbg_add_buf (unsigned char *dst, size_t dstlen, ++ unsigned char *add, size_t addlen) ++{ ++ /* implied: dstlen > addlen */ ++ unsigned char *dstptr, *addptr; ++ unsigned int remainder = 0; ++ size_t len = addlen; ++ ++ dstptr = dst + (dstlen - 1); ++ addptr = add + (addlen - 1); ++ while (len) ++ { ++ remainder += *dstptr + *addptr; ++ *dstptr = remainder & 0xff; ++ remainder >>= 8; ++ len--; ++ dstptr--; ++ addptr--; ++ } ++ len = dstlen - addlen; ++ while (len && remainder > 0) ++ { ++ remainder = *dstptr + 1; ++ *dstptr = remainder & 0xff; ++ remainder >>= 8; ++ len--; ++ dstptr--; ++ } ++} ++ ++/* Helper variables for read_cb(). ++ * ++ * The _gcry_rnd*_gather_random interface does not allow to provide a ++ * data pointer. Thus we need to use a global variable for ++ * communication. However, the then required locking is anyway a good ++ * idea because it does not make sense to have several readers of (say ++ * /dev/random). It is easier to serve them one after the other. */ ++static unsigned char *read_cb_buffer; /* The buffer. */ ++static size_t read_cb_size; /* Size of the buffer. */ ++static size_t read_cb_len; /* Used length. */ ++ ++/* Callback for generating seed from kernel device. */ ++static void ++drbg_read_cb (const void *buffer, size_t length, enum random_origins origin) ++{ ++ const unsigned char *p = buffer; ++ ++ (void) origin; ++ gcry_assert (read_cb_buffer); ++ ++ /* Note that we need to protect against gatherers returning more ++ * than the requested bytes (e.g. rndw32). */ ++ while (length-- && read_cb_len < read_cb_size) ++ read_cb_buffer[read_cb_len++] = *p++; ++} ++ ++static inline int ++drbg_get_entropy (struct drbg_state *drbg, unsigned char *buffer, size_t len) ++{ ++ int rc = 0; ++ ++ /* Perform testing as defined in 11.3.2 */ ++ if (drbg->test_data && drbg->test_data->fail_seed_source) ++ return -1; ++ ++ read_cb_buffer = buffer; ++ read_cb_size = len; ++ read_cb_len = 0; ++#if USE_RNDLINUX ++ rc = _gcry_rndlinux_gather_random (drbg_read_cb, 0, len, ++ GCRY_VERY_STRONG_RANDOM); ++#elif USE_RNDUNIX ++ rc = _gcry_rndunix_gather_random (read_cb, 0, length, ++ GCRY_VERY_STRONG_RANDOM); ++#elif USE_RNDW32 ++ do ++ { ++ rc = _gcry_rndw32_gather_random (read_cb, 0, length, ++ GCRY_VERY_STRONG_RANDOM); ++ } ++ while (rc >= 0 && read_cb_len < read_cb_size); ++#else ++ rc = -1; ++#endif ++ return rc; ++} ++ ++/****************************************************************** ++ * CTR DRBG callback functions ++ ******************************************************************/ ++ ++static gpg_err_code_t drbg_gcry_sym (struct drbg_state *drbg, ++ const unsigned char *key, ++ unsigned char *outval, ++ const struct drbg_string *buf); ++ ++/* BCC function for CTR DRBG as defined in 10.4.3 */ ++static gpg_err_code_t ++drbg_ctr_bcc (struct drbg_state *drbg, ++ unsigned char *out, const unsigned char *key, ++ struct drbg_string *in) ++{ ++ gpg_err_code_t ret = GPG_ERR_GENERAL; ++ struct drbg_string *curr = in; ++ size_t inpos = curr->len; ++ const unsigned char *pos = curr->buf; ++ struct drbg_string data; ++ ++ drbg_string_fill (&data, out, drbg_blocklen (drbg)); ++ ++ /* 10.4.3 step 1 */ ++ memset (out, 0, drbg_blocklen (drbg)); ++ ++ /* 10.4.3 step 2 / 4 */ ++ while (inpos) ++ { ++ short cnt = 0; ++ /* 10.4.3 step 4.1 */ ++ for (cnt = 0; cnt < drbg_blocklen (drbg); cnt++) ++ { ++ out[cnt] ^= *pos; ++ pos++; ++ inpos--; ++ /* the following branch implements the linked list ++ * iteration. If we are at the end of the current data ++ * set, we have to start using the next data set if ++ * available -- the inpos value always points to the ++ * current byte and will be zero if we have processed ++ * the last byte of the last linked list member */ ++ if (0 == inpos) ++ { ++ curr = curr->next; ++ if (NULL != curr) ++ { ++ pos = curr->buf; ++ inpos = curr->len; ++ } ++ else ++ { ++ inpos = 0; ++ break; ++ } ++ } ++ } ++ /* 10.4.3 step 4.2 */ ++ ret = drbg_gcry_sym (drbg, key, out, &data); ++ if (ret) ++ return ret; ++ /* 10.4.3 step 2 */ ++ } ++ return 0; ++} ++ ++ ++/* ++ * scratchpad usage: drbg_ctr_update is interlinked with drbg_ctr_df ++ * (and drbg_ctr_bcc, but this function does not need any temporary buffers), ++ * the scratchpad is used as follows: ++ * drbg_ctr_update: ++ * temp ++ * start: drbg->scratchpad ++ * length: drbg_statelen(drbg) + drbg_blocklen(drbg) ++ * note: the cipher writing into this variable works ++ * blocklen-wise. Now, when the statelen is not a multiple ++ * of blocklen, the generateion loop below "spills over" ++ * by at most blocklen. Thus, we need to give sufficient ++ * memory. ++ * df_data ++ * start: drbg->scratchpad + ++ * drbg_statelen(drbg) + drbg_blocklen(drbg) ++ * length: drbg_statelen(drbg) ++ * ++ * drbg_ctr_df: ++ * pad ++ * start: df_data + drbg_statelen(drbg) ++ * length: drbg_blocklen(drbg) ++ * iv ++ * start: pad + drbg_blocklen(drbg) ++ * length: drbg_blocklen(drbg) ++ * temp ++ * start: iv + drbg_blocklen(drbg) ++ * length: drbg_satelen(drbg) + drbg_blocklen(drbg) ++ * note: temp is the buffer that the BCC function operates ++ * on. BCC operates blockwise. drbg_statelen(drbg) ++ * is sufficient when the DRBG state length is a multiple ++ * of the block size. For AES192 (and maybe other ciphers) ++ * this is not correct and the length for temp is ++ * insufficient (yes, that also means for such ciphers, ++ * the final output of all BCC rounds are truncated). ++ * Therefore, add drbg_blocklen(drbg) to cover all ++ * possibilities. ++ */ ++ ++/* Derivation Function for CTR DRBG as defined in 10.4.2 */ ++static gpg_err_code_t ++drbg_ctr_df (struct drbg_state *drbg, unsigned char *df_data, ++ size_t bytes_to_return, struct drbg_string *addtl) ++{ ++ gpg_err_code_t ret = GPG_ERR_GENERAL; ++ unsigned char L_N[8]; ++ /* S3 is input */ ++ struct drbg_string S1, S2, S4, cipherin; ++ struct drbg_string *tempstr = addtl; ++ unsigned char *pad = df_data + drbg_statelen (drbg); ++ unsigned char *iv = pad + drbg_blocklen (drbg); ++ unsigned char *temp = iv + drbg_blocklen (drbg); ++ size_t padlen = 0; ++ unsigned int templen = 0; ++ /* 10.4.2 step 7 */ ++ unsigned int i = 0; ++ /* 10.4.2 step 8 */ ++ const unsigned char *K = (unsigned char *) ++ "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" ++ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"; ++ unsigned char *X; ++ size_t generated_len = 0; ++ size_t inputlen = 0; ++ ++ memset (pad, 0, drbg_blocklen (drbg)); ++ memset (iv, 0, drbg_blocklen (drbg)); ++ memset (temp, 0, drbg_statelen (drbg)); ++ ++ /* 10.4.2 step 1 is implicit as we work byte-wise */ ++ ++ /* 10.4.2 step 2 */ ++ if ((512 / 8) < bytes_to_return) ++ return GPG_ERR_INV_ARG; ++ ++ /* 10.4.2 step 2 -- calculate the entire length of all input data */ ++ for (; NULL != tempstr; tempstr = tempstr->next) ++ inputlen += tempstr->len; ++ drbg_cpu_to_be32 (inputlen, &L_N[0]); ++ ++ /* 10.4.2 step 3 */ ++ drbg_cpu_to_be32 (bytes_to_return, &L_N[4]); ++ ++ /* 10.4.2 step 5: length is size of L_N, input_string, one byte, padding */ ++ padlen = (inputlen + sizeof (L_N) + 1) % (drbg_blocklen (drbg)); ++ /* wrap the padlen appropriately */ ++ if (padlen) ++ padlen = drbg_blocklen (drbg) - padlen; ++ /* pad / padlen contains the 0x80 byte and the following zero bytes, so ++ * add one for byte for 0x80 */ ++ padlen++; ++ pad[0] = 0x80; ++ ++ /* 10.4.2 step 4 -- first fill the linked list and then order it */ ++ drbg_string_fill (&S1, iv, drbg_blocklen (drbg)); ++ drbg_string_fill (&S2, L_N, sizeof (L_N)); ++ drbg_string_fill (&S4, pad, padlen); ++ S1.next = &S2; ++ S2.next = addtl; ++ ++ /* Splice in addtl between S2 and S4 -- we place S4 at the end of the ++ * input data chain. As this code is only triggered when addtl is not ++ * NULL, no NULL checks are necessary.*/ ++ tempstr = addtl; ++ while (tempstr->next) ++ tempstr = tempstr->next; ++ tempstr->next = &S4; ++ ++ /* 10.4.2 step 9 */ ++ while (templen < (drbg_keylen (drbg) + (drbg_blocklen (drbg)))) ++ { ++ /* 10.4.2 step 9.1 - the padding is implicit as the buffer ++ * holds zeros after allocation -- even the increment of i ++ * is irrelevant as the increment remains within length of i */ ++ drbg_cpu_to_be32 (i, iv); ++ /* 10.4.2 step 9.2 -- BCC and concatenation with temp */ ++ ret = drbg_ctr_bcc (drbg, temp + templen, K, &S1); ++ if (ret) ++ goto out; ++ /* 10.4.2 step 9.3 */ ++ i++; ++ templen += drbg_blocklen (drbg); ++ } ++ ++ /* 10.4.2 step 11 */ ++ /* implicit key len with seedlen - blocklen according to table 3 */ ++ X = temp + (drbg_keylen (drbg)); ++ drbg_string_fill (&cipherin, X, drbg_blocklen (drbg)); ++ ++ /* 10.4.2 step 12: overwriting of outval */ ++ ++ /* 10.4.2 step 13 */ ++ while (generated_len < bytes_to_return) ++ { ++ short blocklen = 0; ++ /* 10.4.2 step 13.1 */ ++ /* the truncation of the key length is implicit as the key ++ * is only drbg_blocklen in size -- check for the implementation ++ * of the cipher function callback */ ++ ret = drbg_gcry_sym (drbg, temp, X, &cipherin); ++ if (ret) ++ goto out; ++ blocklen = (drbg_blocklen (drbg) < ++ (bytes_to_return - generated_len)) ? ++ drbg_blocklen (drbg) : (bytes_to_return - generated_len); ++ /* 10.4.2 step 13.2 and 14 */ ++ memcpy (df_data + generated_len, X, blocklen); ++ generated_len += blocklen; ++ } ++ ++ ret = 0; ++ ++out: ++ memset (iv, 0, drbg_blocklen (drbg)); ++ memset (temp, 0, drbg_statelen (drbg)); ++ memset (pad, 0, drbg_blocklen (drbg)); ++ return ret; ++} ++ ++/* ++ * update function of CTR DRBG as defined in 10.2.1.2 ++ * ++ * The reseed variable has an enhanced meaning compared to the update ++ * functions of the other DRBGs as follows: ++ * 0 => initial seed from initialization ++ * 1 => reseed via drbg_seed ++ * 2 => first invocation from drbg_ctr_update when addtl is present. In ++ * this case, the df_data scratchpad is not deleted so that it is ++ * available for another calls to prevent calling the DF function ++ * again. ++ * 3 => second invocation from drbg_ctr_update. When the update function ++ * was called with addtl, the df_data memory already contains the ++ * DFed addtl information and we do not need to call DF again. ++ */ ++static gpg_err_code_t ++drbg_ctr_update (struct drbg_state *drbg, ++ struct drbg_string *addtl, int reseed) ++{ ++ gpg_err_code_t ret = GPG_ERR_GENERAL; ++ /* 10.2.1.2 step 1 */ ++ unsigned char *temp = drbg->scratchpad; ++ unsigned char *df_data = drbg->scratchpad + drbg_statelen (drbg) + ++ drbg_blocklen (drbg); ++ unsigned char *temp_p, *df_data_p; /* pointer to iterate over buffers */ ++ unsigned int len = 0; ++ struct drbg_string cipherin; ++ unsigned char prefix = DRBG_PREFIX1; ++ ++ memset (temp, 0, drbg_statelen (drbg) + drbg_blocklen (drbg)); ++ if (3 > reseed) ++ memset (df_data, 0, drbg_statelen (drbg)); ++ ++ /* 10.2.1.3.2 step 2 and 10.2.1.4.2 step 2 */ ++ /* TODO use reseed variable to avoid re-doing DF operation */ ++ (void) reseed; ++ if (addtl && 0 < addtl->len) ++ { ++ ret = drbg_ctr_df (drbg, df_data, drbg_statelen (drbg), addtl); ++ if (ret) ++ goto out; ++ } ++ ++ drbg_string_fill (&cipherin, drbg->V, drbg_blocklen (drbg)); ++ /* 10.2.1.3.2 step 2 and 3 -- are already covered as we memset(0) ++ * all memory during initialization */ ++ while (len < (drbg_statelen (drbg))) ++ { ++ /* 10.2.1.2 step 2.1 */ ++ drbg_add_buf (drbg->V, drbg_blocklen (drbg), &prefix, 1); ++ /* 10.2.1.2 step 2.2 */ ++ /* using target of temp + len: 10.2.1.2 step 2.3 and 3 */ ++ ret = drbg_gcry_sym (drbg, drbg->C, temp + len, &cipherin); ++ if (ret) ++ goto out; ++ /* 10.2.1.2 step 2.3 and 3 */ ++ len += drbg_blocklen (drbg); ++ } ++ ++ /* 10.2.1.2 step 4 */ ++ temp_p = temp; ++ df_data_p = df_data; ++ for (len = 0; len < drbg_statelen (drbg); len++) ++ { ++ *temp_p ^= *df_data_p; ++ df_data_p++; ++ temp_p++; ++ } ++ ++ /* 10.2.1.2 step 5 */ ++ memcpy (drbg->C, temp, drbg_keylen (drbg)); ++ /* 10.2.1.2 step 6 */ ++ memcpy (drbg->V, temp + drbg_keylen (drbg), drbg_blocklen (drbg)); ++ ret = 0; ++ ++out: ++ memset (temp, 0, drbg_statelen (drbg) + drbg_blocklen (drbg)); ++ if (2 != reseed) ++ memset (df_data, 0, drbg_statelen (drbg)); ++ return ret; ++} ++ ++/* ++ * scratchpad use: drbg_ctr_update is called independently from ++ * drbg_ctr_extract_bytes. Therefore, the scratchpad is reused ++ */ ++/* Generate function of CTR DRBG as defined in 10.2.1.5.2 */ ++static gpg_err_code_t ++drbg_ctr_generate (struct drbg_state *drbg, ++ unsigned char *buf, unsigned int buflen, ++ struct drbg_string *addtl) ++{ ++ gpg_err_code_t ret = 0; ++ unsigned int len = 0; ++ struct drbg_string data; ++ unsigned char prefix = DRBG_PREFIX1; ++ ++ memset (drbg->scratchpad, 0, drbg_blocklen (drbg)); ++ ++ /* 10.2.1.5.2 step 2 */ ++ if (addtl && 0 < addtl->len) ++ { ++ addtl->next = NULL; ++ ret = drbg_ctr_update (drbg, addtl, 2); ++ if (ret) ++ return ret; ++ } ++ ++ /* 10.2.1.5.2 step 4.1 */ ++ drbg_add_buf (drbg->V, drbg_blocklen (drbg), &prefix, 1); ++ drbg_string_fill (&data, drbg->V, drbg_blocklen (drbg)); ++ while (len < buflen) ++ { ++ unsigned int outlen = 0; ++ /* 10.2.1.5.2 step 4.2 */ ++ ret = drbg_gcry_sym (drbg, drbg->C, drbg->scratchpad, &data); ++ if (ret) ++ goto out; ++ outlen = (drbg_blocklen (drbg) < (buflen - len)) ? ++ drbg_blocklen (drbg) : (buflen - len); ++ if (!drbg_fips_continuous_test (drbg, drbg->scratchpad)) ++ { ++ /* 10.2.1.5.2 step 6 */ ++ drbg_add_buf (drbg->V, drbg_blocklen (drbg), &prefix, 1); ++ continue; ++ } ++ /* 10.2.1.5.2 step 4.3 */ ++ memcpy (buf + len, drbg->scratchpad, outlen); ++ len += outlen; ++ /* 10.2.1.5.2 step 6 */ ++ if (len < buflen) ++ drbg_add_buf (drbg->V, drbg_blocklen (drbg), &prefix, 1); ++ } ++ ++ /* 10.2.1.5.2 step 6 */ ++ if (addtl) ++ addtl->next = NULL; ++ ret = drbg_ctr_update (drbg, addtl, 3); ++ ++out: ++ memset (drbg->scratchpad, 0, drbg_blocklen (drbg)); ++ return ret; ++} ++ ++static struct drbg_state_ops drbg_ctr_ops = { ++ .update = drbg_ctr_update, ++ .generate = drbg_ctr_generate, ++}; ++ ++/****************************************************************** ++ * HMAC DRBG callback functions ++ ******************************************************************/ ++ ++static gpg_err_code_t drbg_gcry_hmac (struct drbg_state *drbg, ++ const unsigned char *key, ++ unsigned char *outval, ++ const struct drbg_string *buf); ++ ++static gpg_err_code_t ++drbg_hmac_update (struct drbg_state *drbg, ++ struct drbg_string *seed, int reseed) ++{ ++ gpg_err_code_t ret = GPG_ERR_GENERAL; ++ int i = 0; ++ struct drbg_string seed1, seed2, cipherin; ++ ++ if (!reseed) ++ { ++ /* 10.1.2.3 step 2 already implicitly covered with ++ * the initial memset(0) of drbg->C */ ++ memset (drbg->C, 0, drbg_statelen (drbg)); ++ memset (drbg->V, 1, drbg_statelen (drbg)); ++ } ++ ++ /* build linked list which implements the concatenation and fill ++ * first part*/ ++ drbg_string_fill (&seed1, drbg->V, drbg_statelen (drbg)); ++ /* buffer will be filled in for loop below with one byte */ ++ drbg_string_fill (&seed2, NULL, 1); ++ seed1.next = &seed2; ++ /* seed may be NULL */ ++ seed2.next = seed; ++ ++ drbg_string_fill (&cipherin, drbg->V, drbg_statelen (drbg)); ++ /* we execute two rounds of V/K massaging */ ++ for (i = 2; 0 < i; i--) ++ { ++ /* first round uses 0x0, second 0x1 */ ++ unsigned char prefix = DRBG_PREFIX0; ++ if (1 == i) ++ prefix = DRBG_PREFIX1; ++ /* 10.1.2.2 step 1 and 4 -- concatenation and HMAC for key */ ++ seed2.buf = &prefix; ++ ret = drbg_gcry_hmac (drbg, drbg->C, drbg->C, &seed1); ++ if (ret) ++ return ret; ++ ++ /* 10.1.2.2 step 2 and 5 -- HMAC for V */ ++ ret = drbg_gcry_hmac (drbg, drbg->C, drbg->V, &cipherin); ++ if (ret) ++ return ret; ++ ++ /* 10.1.2.2 step 3 */ ++ if (!seed || 0 == seed->len) ++ return ret; ++ } ++ return 0; ++} ++ ++/* generate function of HMAC DRBG as defined in 10.1.2.5 */ ++static gpg_err_code_t ++drbg_hmac_generate (struct drbg_state *drbg, ++ unsigned char *buf, ++ unsigned int buflen, struct drbg_string *addtl) ++{ ++ gpg_err_code_t ret = 0; ++ unsigned int len = 0; ++ struct drbg_string data; ++ ++ /* 10.1.2.5 step 2 */ ++ if (addtl && 0 < addtl->len) ++ { ++ addtl->next = NULL; ++ ret = drbg_hmac_update (drbg, addtl, 1); ++ if (ret) ++ return ret; ++ } ++ ++ drbg_string_fill (&data, drbg->V, drbg_statelen (drbg)); ++ while (len < buflen) ++ { ++ unsigned int outlen = 0; ++ /* 10.1.2.5 step 4.1 */ ++ ret = drbg_gcry_hmac (drbg, drbg->C, drbg->V, &data); ++ if (ret) ++ return ret; ++ outlen = (drbg_blocklen (drbg) < (buflen - len)) ? ++ drbg_blocklen (drbg) : (buflen - len); ++ if (!drbg_fips_continuous_test (drbg, drbg->V)) ++ continue; ++ ++ /* 10.1.2.5 step 4.2 */ ++ memcpy (buf + len, drbg->V, outlen); ++ len += outlen; ++ } ++ ++ /* 10.1.2.5 step 6 */ ++ if (addtl) ++ addtl->next = NULL; ++ ret = drbg_hmac_update (drbg, addtl, 1); ++ ++ return ret; ++} ++ ++static struct drbg_state_ops drbg_hmac_ops = { ++ .update = drbg_hmac_update, ++ .generate = drbg_hmac_generate, ++}; ++ ++/****************************************************************** ++ * Hash DRBG callback functions ++ ******************************************************************/ ++ ++/* ++ * scratchpad usage: as drbg_hash_update and drbg_hash_df are used ++ * interlinked, the scratchpad is used as follows: ++ * drbg_hash_update ++ * start: drbg->scratchpad ++ * length: drbg_statelen(drbg) ++ * drbg_hash_df: ++ * start: drbg->scratchpad + drbg_statelen(drbg) ++ * length: drbg_blocklen(drbg) ++ */ ++/* Derivation Function for Hash DRBG as defined in 10.4.1 */ ++static gpg_err_code_t ++drbg_hash_df (struct drbg_state *drbg, ++ unsigned char *outval, size_t outlen, ++ struct drbg_string *entropy) ++{ ++ gpg_err_code_t ret = 0; ++ size_t len = 0; ++ unsigned char input[5]; ++ unsigned char *tmp = drbg->scratchpad + drbg_statelen (drbg); ++ struct drbg_string data1; ++ ++ memset (tmp, 0, drbg_blocklen (drbg)); ++ ++ /* 10.4.1 step 3 */ ++ input[0] = 1; ++ drbg_cpu_to_be32 ((outlen * 8), &input[1]); ++ ++ /* 10.4.1 step 4.1 -- concatenation of data for input into hash */ ++ drbg_string_fill (&data1, input, 5); ++ data1.next = entropy; ++ ++ /* 10.4.1 step 4 */ ++ while (len < outlen) ++ { ++ short blocklen = 0; ++ /* 10.4.1 step 4.1 */ ++ ret = drbg_gcry_hmac (drbg, NULL, tmp, &data1); ++ if (ret) ++ goto out; ++ /* 10.4.1 step 4.2 */ ++ input[0]++; ++ blocklen = (drbg_blocklen (drbg) < (outlen - len)) ? ++ drbg_blocklen (drbg) : (outlen - len); ++ memcpy (outval + len, tmp, blocklen); ++ len += blocklen; ++ } ++ ++out: ++ memset (tmp, 0, drbg_blocklen (drbg)); ++ return ret; ++} ++ ++/* update function for Hash DRBG as defined in 10.1.1.2 / 10.1.1.3 */ ++static gpg_err_code_t ++drbg_hash_update (struct drbg_state *drbg, struct drbg_string *seed, ++ int reseed) ++{ ++ gpg_err_code_t ret = 0; ++ struct drbg_string data1, data2; ++ unsigned char *V = drbg->scratchpad; ++ unsigned char prefix = DRBG_PREFIX1; ++ ++ memset (drbg->scratchpad, 0, drbg_statelen (drbg)); ++ if (!seed) ++ return GPG_ERR_INV_ARG; ++ ++ if (reseed) ++ { ++ /* 10.1.1.3 step 1: string length is concatenation of ++ * 1 byte, V and seed (which is concatenated entropy/addtl ++ * input) ++ */ ++ memcpy (V, drbg->V, drbg_statelen (drbg)); ++ drbg_string_fill (&data1, &prefix, 1); ++ drbg_string_fill (&data2, V, drbg_statelen (drbg)); ++ data1.next = &data2; ++ data2.next = seed; ++ } ++ else ++ { ++ drbg_string_fill (&data1, seed->buf, seed->len); ++ data1.next = seed->next; ++ } ++ ++ /* 10.1.1.2 / 10.1.1.3 step 2 and 3 */ ++ ret = drbg_hash_df (drbg, drbg->V, drbg_statelen (drbg), &data1); ++ if (ret) ++ goto out; ++ ++ /* 10.1.1.2 / 10.1.1.3 step 4 -- concatenation */ ++ prefix = DRBG_PREFIX0; ++ drbg_string_fill (&data1, &prefix, 1); ++ drbg_string_fill (&data2, drbg->V, drbg_statelen (drbg)); ++ data1.next = &data2; ++ /* 10.1.1.2 / 10.1.1.3 step 4 -- df operation */ ++ ret = drbg_hash_df (drbg, drbg->C, drbg_statelen (drbg), &data1); ++ ++out: ++ memset (drbg->scratchpad, 0, drbg_statelen (drbg)); ++ return ret; ++} ++ ++/* processing of additional information string for Hash DRBG */ ++static gpg_err_code_t ++drbg_hash_process_addtl (struct drbg_state *drbg, struct drbg_string *addtl) ++{ ++ gpg_err_code_t ret = 0; ++ struct drbg_string data1, data2; ++ struct drbg_string *data3; ++ unsigned char prefix = DRBG_PREFIX2; ++ ++ /* this is value w as per documentation */ ++ memset (drbg->scratchpad, 0, drbg_blocklen (drbg)); ++ ++ /* 10.1.1.4 step 2 */ ++ if (!addtl || 0 == addtl->len) ++ return 0; ++ ++ /* 10.1.1.4 step 2a -- concatenation */ ++ drbg_string_fill (&data1, &prefix, 1); ++ drbg_string_fill (&data2, drbg->V, drbg_statelen (drbg)); ++ data3 = addtl; ++ data1.next = &data2; ++ data2.next = data3; ++ data3->next = NULL; ++ /* 10.1.1.4 step 2a -- cipher invocation */ ++ ret = drbg_gcry_hmac (drbg, NULL, drbg->scratchpad, &data1); ++ if (ret) ++ goto out; ++ ++ /* 10.1.1.4 step 2b */ ++ drbg_add_buf (drbg->V, drbg_statelen (drbg), ++ drbg->scratchpad, drbg_blocklen (drbg)); ++ ++out: ++ memset (drbg->scratchpad, 0, drbg_blocklen (drbg)); ++ return ret; ++} ++ ++/* ++ * Hashgen defined in 10.1.1.4 ++ */ ++static gpg_err_code_t ++drbg_hash_hashgen (struct drbg_state *drbg, ++ unsigned char *buf, unsigned int buflen) ++{ ++ gpg_err_code_t ret = 0; ++ unsigned int len = 0; ++ unsigned char *src = drbg->scratchpad; ++ unsigned char *dst = drbg->scratchpad + drbg_statelen (drbg); ++ struct drbg_string data; ++ unsigned char prefix = DRBG_PREFIX1; ++ ++ /* use the scratchpad as a lookaside buffer */ ++ memset (src, 0, drbg_statelen (drbg)); ++ memset (dst, 0, drbg_blocklen (drbg)); ++ ++ /* 10.1.1.4 step hashgen 2 */ ++ memcpy (src, drbg->V, drbg_statelen (drbg)); ++ ++ drbg_string_fill (&data, src, drbg_statelen (drbg)); ++ while (len < buflen) ++ { ++ unsigned int outlen = 0; ++ /* 10.1.1.4 step hashgen 4.1 */ ++ ret = drbg_gcry_hmac (drbg, NULL, dst, &data); ++ if (ret) ++ goto out; ++ outlen = (drbg_blocklen (drbg) < (buflen - len)) ? ++ drbg_blocklen (drbg) : (buflen - len); ++ if (!drbg_fips_continuous_test (drbg, dst)) ++ { ++ drbg_add_buf (src, drbg_statelen (drbg), &prefix, 1); ++ continue; ++ } ++ /* 10.1.1.4 step hashgen 4.2 */ ++ memcpy (buf + len, dst, outlen); ++ len += outlen; ++ /* 10.1.1.4 hashgen step 4.3 */ ++ if (len < buflen) ++ drbg_add_buf (src, drbg_statelen (drbg), &prefix, 1); ++ } ++ ++out: ++ memset (drbg->scratchpad, 0, (drbg_statelen (drbg) + drbg_blocklen (drbg))); ++ return ret; ++} ++ ++/* generate function for Hash DRBG as defined in 10.1.1.4 */ ++static gpg_err_code_t ++drbg_hash_generate (struct drbg_state *drbg, ++ unsigned char *buf, unsigned int buflen, ++ struct drbg_string *addtl) ++{ ++ gpg_err_code_t ret = 0; ++ unsigned char prefix = DRBG_PREFIX3; ++ struct drbg_string data1, data2; ++ union ++ { ++ unsigned char req[8]; ++ uint64_t req_int; ++ } u; ++ ++ /* ++ * scratchpad usage: drbg_hash_process_addtl uses the scratchpad, but ++ * fully completes before returning. Thus, we can reuse the scratchpad ++ */ ++ /* 10.1.1.4 step 2 */ ++ ret = drbg_hash_process_addtl (drbg, addtl); ++ if (ret) ++ return ret; ++ /* 10.1.1.4 step 3 -- invocation of the Hashgen function defined in ++ * 10.1.1.4 */ ++ ret = drbg_hash_hashgen (drbg, buf, buflen); ++ if (ret) ++ return ret; ++ ++ /* this is the value H as documented in 10.1.1.4 */ ++ memset (drbg->scratchpad, 0, drbg_blocklen (drbg)); ++ /* 10.1.1.4 step 4 */ ++ drbg_string_fill (&data1, &prefix, 1); ++ drbg_string_fill (&data2, drbg->V, drbg_statelen (drbg)); ++ data1.next = &data2; ++ ret = drbg_gcry_hmac (drbg, NULL, drbg->scratchpad, &data1); ++ if (ret) ++ goto out; ++ ++ /* 10.1.1.4 step 5 */ ++ drbg_add_buf (drbg->V, drbg_statelen (drbg), ++ drbg->scratchpad, drbg_blocklen (drbg)); ++ drbg_add_buf (drbg->V, drbg_statelen (drbg), drbg->C, drbg_statelen (drbg)); ++ u.req_int = be_bswap64(drbg->reseed_ctr); ++ drbg_add_buf (drbg->V, drbg_statelen (drbg), u.req, sizeof (u.req)); ++ ++out: ++ memset (drbg->scratchpad, 0, drbg_blocklen (drbg)); ++ return ret; ++} ++ ++/* ++ * scratchpad usage: as update and generate are used isolated, both ++ * can use the scratchpad ++ */ ++static struct drbg_state_ops drbg_hash_ops = { ++ .update = drbg_hash_update, ++ .generate = drbg_hash_generate, ++}; ++ ++/****************************************************************** ++ * Functions common for DRBG implementations ++ ******************************************************************/ ++ ++/* ++ * Seeding or reseeding of the DRBG ++ * ++ * @drbg: DRBG state struct ++ * @pers: personalization / additional information buffer ++ * @reseed: 0 for initial seed process, 1 for reseeding ++ * ++ * return: ++ * 0 on success ++ * error value otherwise ++ */ ++static gpg_err_code_t ++drbg_seed (struct drbg_state *drbg, struct drbg_string *pers, int reseed) ++{ ++ gpg_err_code_t ret = 0; ++ unsigned char *entropy = NULL; ++ size_t entropylen = 0; ++ struct drbg_string data1; ++ ++ /* 9.1 / 9.2 / 9.3.1 step 3 */ ++ if (pers && pers->len > (drbg_max_addtl ())) ++ { ++ dbg (("DRBG: personalization string too long %lu\n", pers->len)); ++ return GPG_ERR_INV_ARG; ++ } ++ if (drbg->test_data && drbg->test_data->testentropy) ++ { ++ drbg_string_fill (&data1, drbg->test_data->testentropy->buf, ++ drbg->test_data->testentropy->len); ++ dbg (("DRBG: using test entropy\n")); ++ } ++ else ++ { ++ /* Gather entropy equal to the security strength of the DRBG. ++ * With a derivation function, a nonce is required in addition ++ * to the entropy. A nonce must be at least 1/2 of the security ++ * strength of the DRBG in size. Thus, entropy * nonce is 3/2 ++ * of the strength. The consideration of a nonce is only ++ * applicable during initial seeding. */ ++ entropylen = drbg_sec_strength (drbg->core->flags); ++ if (!entropylen) ++ return GPG_ERR_GENERAL; ++ if (0 == reseed) ++ /* make sure we round up strength/2 in ++ * case it is not divisible by 2 */ ++ entropylen = ((entropylen + 1) / 2) * 3; ++ dbg (("DRBG: (re)seeding with %lu bytes of entropy\n", entropylen)); ++ entropy = drbg_malloc (entropylen); ++ if (!entropy) ++ return GPG_ERR_ENOMEM; ++ ret = drbg_get_entropy (drbg, entropy, entropylen); ++ if (ret) ++ goto out; ++ drbg_string_fill (&data1, entropy, entropylen); ++ } ++ ++ /* concatenation of entropy with personalization str / addtl input) ++ * the variable pers is directly handed by the caller, check its ++ * contents whether it is appropriate */ ++ if (pers && pers->buf && 0 < pers->len && NULL == pers->next) ++ { ++ data1.next = pers; ++ dbg (("DRBG: using personalization string\n")); ++ } ++ ++ ret = drbg->d_ops->update (drbg, &data1, reseed); ++ dbg (("DRBG: state updated with seed\n")); ++ if (ret) ++ goto out; ++ drbg->seeded = 1; ++ /* 10.1.1.2 / 10.1.1.3 step 5 */ ++ drbg->reseed_ctr = 1; ++ ++out: ++ if (entropy) ++ xfree (entropy); ++ return ret; ++} ++ ++/************************************************************************* ++ * exported interfaces ++ *************************************************************************/ ++ ++/* ++ * DRBG generate function as required by SP800-90A - this function ++ * generates random numbers ++ * ++ * @drbg DRBG state handle ++ * @buf Buffer where to store the random numbers -- the buffer must already ++ * be pre-allocated by caller ++ * @buflen Length of output buffer - this value defines the number of random ++ * bytes pulled from DRBG ++ * @addtl Additional input that is mixed into state, may be NULL -- note ++ * the entropy is pulled by the DRBG internally unconditionally ++ * as defined in SP800-90A. The additional input is mixed into ++ * the state in addition to the pulled entropy. ++ * ++ * return: generated number of bytes ++ */ ++static gpg_err_code_t ++drbg_generate (struct drbg_state *drbg, ++ unsigned char *buf, unsigned int buflen, ++ struct drbg_string *addtl) ++{ ++ gpg_err_code_t ret = GPG_ERR_INV_ARG; ++ ++ if (0 == buflen || !buf) ++ { ++ dbg (("DRBG: no buffer provided\n")); ++ return ret; ++ } ++ if (addtl && NULL == addtl->buf && 0 < addtl->len) ++ { ++ dbg (("DRBG: wrong format of additional information\n")); ++ return ret; ++ } ++ ++ /* 9.3.1 step 2 */ ++ if (buflen > (drbg_max_request_bytes ())) ++ { ++ dbg (("DRBG: requested random numbers too large %u\n", buflen)); ++ return ret; ++ } ++ /* 9.3.1 step 3 is implicit with the chosen DRBG */ ++ /* 9.3.1 step 4 */ ++ if (addtl && addtl->len > (drbg_max_addtl ())) ++ { ++ dbg (("DRBG: additional information string too long %lu\n", ++ addtl->len)); ++ return ret; ++ } ++ /* 9.3.1 step 5 is implicit with the chosen DRBG */ ++ /* 9.3.1 step 6 and 9 supplemented by 9.3.2 step c -- the spec is a ++ * bit convoluted here, we make it simpler */ ++ if ((drbg_max_requests ()) < drbg->reseed_ctr) ++ drbg->seeded = 0; ++ ++ if (drbg->pr || !drbg->seeded) ++ { ++ dbg (("DRBG: reseeding before generation (prediction resistance: %s, state %s)\n", drbg->pr ? "true" : "false", drbg->seeded ? "seeded" : "unseeded")); ++ /* 9.3.1 steps 7.1 through 7.3 */ ++ ret = drbg_seed (drbg, addtl, 1); ++ if (ret) ++ return ret; ++ /* 9.3.1 step 7.4 */ ++ addtl = NULL; ++ } ++ ++ if (addtl && addtl->buf) ++ { ++ dbg (("DRBG: using additional information string\n")); ++ } ++ ++ /* 9.3.1 step 8 and 10 */ ++ ret = drbg->d_ops->generate (drbg, buf, buflen, addtl); ++ ++ /* 10.1.1.4 step 6, 10.1.2.5 step 7, 10.2.1.5.2 step 7 */ ++ drbg->reseed_ctr++; ++ if (ret) ++ return ret; ++ ++ /* 11.3.3 -- re-perform self tests after some generated random ++ * numbers, the chosen value after which self test is performed ++ * is arbitrary, but it should be reasonable */ ++ /* Here we do not perform the self tests because of the following ++ * reasons: it is mathematically impossible that the initial self tests ++ * were successfully and the following are not. If the initial would ++ * pass and the following would not, the system integrity is violated. ++ * In this case, the entire system operation is questionable and it ++ * is unlikely that the integrity violation only affects to the ++ * correct operation of the DRBG. ++ */ ++#if 0 ++ if (drbg->reseed_ctr && !(drbg->reseed_ctr % 4096)) ++ { ++ dbg (("DRBG: start to perform self test\n")); ++ ret = drbg_healthcheck (); ++ if (ret) ++ { ++ log_fatal (("DRBG: self test failed\n")); ++ return ret; ++ } ++ else ++ { ++ dbg (("DRBG: self test successful\n")); ++ } ++ } ++#endif ++ ++ return ret; ++} ++ ++/* ++ * Wrapper around drbg_generate which can pull arbitrary long strings ++ * from the DRBG without hitting the maximum request limitation. ++ * ++ * Parameters: see drbg_generate ++ * Return codes: see drbg_generate -- if one drbg_generate request fails, ++ * the entire drbg_generate_long request fails ++ */ ++static gpg_err_code_t ++drbg_generate_long (struct drbg_state *drbg, ++ unsigned char *buf, unsigned int buflen, ++ struct drbg_string *addtl) ++{ ++ gpg_err_code_t ret = 0; ++ unsigned int slice = 0; ++ unsigned char *buf_p = buf; ++ unsigned len = 0; ++ do ++ { ++ unsigned int chunk = 0; ++ slice = ((buflen - len) / drbg_max_request_bytes ()); ++ chunk = slice ? drbg_max_request_bytes () : (buflen - len); ++ ret = drbg_generate (drbg, buf_p, chunk, addtl); ++ if (ret) ++ return ret; ++ buf_p += chunk; ++ len += chunk; ++ } ++ while (slice > 0 && (len < buflen)); ++ return ret; ++} ++ ++/* ++ * DRBG uninstantiate function as required by SP800-90A - this function ++ * frees all buffers and the DRBG handle ++ * ++ * @drbg DRBG state handle ++ * ++ * return ++ * 0 on success ++ */ ++static gpg_err_code_t ++drbg_uninstantiate (struct drbg_state *drbg) ++{ ++ if (!drbg) ++ return GPG_ERR_INV_ARG; ++ if (drbg->V) ++ xfree (drbg->V); ++ drbg->V = NULL; ++ if (drbg->C) ++ xfree (drbg->C); ++ drbg->C = NULL; ++ drbg->reseed_ctr = 0; ++ if (drbg->scratchpad) ++ xfree (drbg->scratchpad); ++ drbg->scratchpad = NULL; ++ drbg->seeded = 0; ++ drbg->pr = 0; ++ drbg->fips_primed = 0; ++ if (drbg->prev) ++ xfree (drbg->prev); ++ drbg->prev = NULL; ++ drbg->seed_init_pid = 0; ++ return 0; ++} ++ ++/* ++ * DRBG instantiation function as required by SP800-90A - this function ++ * sets up the DRBG handle, performs the initial seeding and all sanity ++ * checks required by SP800-90A ++ * ++ * @drbg memory of state -- if NULL, new memory is allocated ++ * @pers Personalization string that is mixed into state, may be NULL -- note ++ * the entropy is pulled by the DRBG internally unconditionally ++ * as defined in SP800-90A. The additional input is mixed into ++ * the state in addition to the pulled entropy. ++ * @coreref reference to core ++ * @flags Flags defining the requested DRBG type and cipher type. The flags ++ * are defined in drbg.h and may be XORed. Beware, if you XOR multiple ++ * cipher types together, the code picks the core on a first come first ++ * serve basis as it iterates through the available cipher cores and ++ * uses the one with the first match. The minimum required flags are: ++ * cipher type flag ++ * ++ * return ++ * 0 on success ++ * error value otherwise ++ */ ++static gpg_err_code_t ++drbg_instantiate (struct drbg_state *drbg, struct drbg_string *pers, ++ int coreref, int pr) ++{ ++ gpg_err_code_t ret = GPG_ERR_ENOMEM; ++ unsigned int sb_size = 0; ++ ++ if (!drbg) ++ return GPG_ERR_INV_ARG; ++ ++ dbg (("DRBG: Initializing DRBG core %d with prediction resistance %s\n", ++ coreref, pr ? "enabled" : "disabled")); ++ drbg->core = &drbg_cores[coreref]; ++ drbg->pr = pr; ++ drbg->seeded = 0; ++ if (drbg->core->flags & DRBG_HMAC) ++ drbg->d_ops = &drbg_hmac_ops; ++ else if (drbg->core->flags & DRBG_HASH_MASK) ++ drbg->d_ops = &drbg_hash_ops; ++ else if (drbg->core->flags & DRBG_CTR_MASK) ++ drbg->d_ops = &drbg_ctr_ops; ++ else ++ return GPG_ERR_GENERAL; ++ /* 9.1 step 1 is implicit with the selected DRBG type -- see ++ * drbg_sec_strength() */ ++ ++ /* 9.1 step 2 is implicit as caller can select prediction resistance ++ * and the flag is copied into drbg->flags -- ++ * all DRBG types support prediction resistance */ ++ ++ /* 9.1 step 4 is implicit in drbg_sec_strength */ ++ ++ /* no allocation of drbg as this is done by the kernel crypto API */ ++ drbg->V = drbg_malloc (drbg_statelen (drbg)); ++ if (!drbg->V) ++ goto err; ++ drbg->C = drbg_malloc (drbg_statelen (drbg)); ++ if (!drbg->C) ++ goto err; ++ drbg->prev = drbg_malloc (drbg_blocklen (drbg)); ++ if (!drbg->prev) ++ goto err; ++ drbg->fips_primed = 0; ++ /* scratchpad is only generated for CTR and Hash */ ++ if (drbg->core->flags & DRBG_HMAC) ++ sb_size = 0; ++ else if (drbg->core->flags & DRBG_CTR_MASK) ++ sb_size = drbg_statelen (drbg) + drbg_blocklen (drbg) + /* temp */ ++ drbg_statelen (drbg) + /* df_data */ ++ drbg_blocklen (drbg) + /* pad */ ++ drbg_blocklen (drbg) + /* iv */ ++ drbg_statelen (drbg) + drbg_blocklen(drbg); /* temp */ ++ else ++ sb_size = drbg_statelen (drbg) + drbg_blocklen (drbg); ++ ++ if (0 < sb_size) ++ { ++ drbg->scratchpad = drbg_malloc (sb_size); ++ if (!drbg->scratchpad) ++ goto err; ++ } ++ dbg (("DRBG: state allocated with scratchpad size %u bytes\n", sb_size)); ++ ++ /* 9.1 step 6 through 11 */ ++ ret = drbg_seed (drbg, pers, 0); ++ if (ret) ++ goto err; ++ ++ dbg (("DRBG: core %d %s prediction resistance successfully initialized\n", ++ coreref, pr ? "with" : "without")); ++ return 0; ++ ++err: ++ drbg_uninstantiate (drbg); ++ return ret; ++} ++ ++/* ++ * DRBG reseed function as required by SP800-90A ++ * ++ * @drbg DRBG state handle ++ * @addtl Additional input that is mixed into state, may be NULL -- note ++ * the entropy is pulled by the DRBG internally unconditionally ++ * as defined in SP800-90A. The additional input is mixed into ++ * the state in addition to the pulled entropy. ++ * ++ * return ++ * 0 on success ++ * error value otherwise ++ */ ++static gpg_err_code_t ++drbg_reseed (struct drbg_state *drbg, struct drbg_string *addtl) ++{ ++ gpg_err_code_t ret = 0; ++ ret = drbg_seed (drbg, addtl, 1); ++ return ret; ++} ++ ++/****************************************************************** ++ * ***************************************************************** ++ ****************************************************************** ++ * libgcrypt integration code ++ ****************************************************************** ++ ****************************************************************** ++ ******************************************************************/ ++ ++/*************************************************************** ++ * libgcrypt backend functions to the RNG API code ++ ***************************************************************/ ++ ++/* global state variable holding the current instance of the DRBG -- the ++ * default DRBG type is defined in _gcry_drbg_init */ ++static struct drbg_state *gcry_drbg = NULL; ++GPGRT_LOCK_DEFINE (drbg_gcry_lock); ++ ++static inline void ++drbg_lock (void) ++{ ++ gpg_err_code_t rc; ++ rc = gpgrt_lock_lock (&drbg_gcry_lock); ++ if (rc) ++ log_fatal ("failed to acquire the RNG lock: %s\n", gpg_strerror (rc)); ++} ++ ++static inline void ++drbg_unlock (void) ++{ ++ gpg_err_code_t rc; ++ rc = gpgrt_lock_unlock (&drbg_gcry_lock); ++ if (rc) ++ log_fatal ("failed to release the RNG lock: %s\n", gpg_strerror (rc)); ++} ++ ++/****** helper functions where lock must be held by caller *****/ ++ ++/* Check whether given flags are known to point to an applicable DRBG */ ++static gpg_err_code_t ++drbg_algo_available (u_int32_t flags, int *coreref) ++{ ++ int i = 0; ++ for (i = 0; ARRAY_SIZE (drbg_cores) > i; i++) ++ { ++ if ((drbg_cores[i].flags & DRBG_CIPHER_MASK) == ++ (flags & DRBG_CIPHER_MASK)) ++ { ++ *coreref = i; ++ return 0; ++ } ++ } ++ return GPG_ERR_GENERAL; ++} ++ ++static gpg_err_code_t ++_gcry_drbg_init_internal (int full, u_int32_t flags, struct drbg_string *pers) ++{ ++ gpg_err_code_t ret = 0; ++ static u_int32_t oldflags = 0; ++ int coreref = 0; ++ int pr = 0; ++ /* TODO what shall we do with the full variable? */ ++ (void) full; ++ ++ /* If a caller provides 0 as flags, use the flags of the previous ++ * initialization, otherwise use the current flags and remember them ++ * for the next invocation ++ */ ++ if (0 == flags) ++ flags = oldflags; ++ else ++ oldflags = flags; ++ ++ ret = drbg_algo_available (flags, &coreref); ++ if (ret) ++ return ret; ++ ++ if (NULL != gcry_drbg) ++ { ++ drbg_uninstantiate (gcry_drbg); ++ } ++ else ++ { ++ gcry_drbg = drbg_malloc (sizeof (struct drbg_state)); ++ if (!gcry_drbg) ++ return GPG_ERR_ENOMEM; ++ } ++ if (flags & DRBG_PREDICTION_RESIST) ++ pr = 1; ++ ret = drbg_instantiate (gcry_drbg, pers, coreref, pr); ++ if (ret) ++ fips_signal_error ("DRBG cannot be initialized"); ++ else ++ gcry_drbg->seed_init_pid = getpid (); ++ return ret; ++} ++ ++/************* calls available to common RNG code **************/ ++ ++/* ++ * Initialize one DRBG invoked by the libgcrypt API ++ * ++ * Function uses the kernel crypto API cra_name to look up ++ * the flags to instantiate the DRBG ++ */ ++void ++_gcry_drbg_init (int full) ++{ ++ /* default DRBG */ ++ u_int32_t flags = DRBG_NOPR_HMACSHA256; ++ drbg_lock (); ++ _gcry_drbg_init_internal (full, flags, NULL); ++ drbg_unlock (); ++} ++ ++/* ++ * Backend handler function for GCRYCTL_DRBG_REINIT ++ * ++ * Select a different DRBG type and initialize it. ++ * Function checks whether requested DRBG type exists and returns an error in ++ * case it does not. In case of an error, the previous instantiated DRBG is ++ * left untouched and alive. Thus, in case of an error, a DRBG is always ++ * available, even if it is not the chosen one. ++ * ++ * Re-initialization will be performed in any case regardless whether flags ++ * or personalization string are set. ++ * ++ * If flags == 0, do not change current DRBG ++ * If parsonalization string is NULL or its length is 0, re-initialize without ++ * personalization string ++ * ++ * If test_data is provided, the "entropy" is provided instead of using ++ * the noise source. ++ */ ++gpg_err_code_t ++_gcry_drbg_reinit (u_int32_t flags, struct drbg_string *pers, ++ struct drbg_test_data *test_data) ++{ ++ gpg_err_code_t ret = GPG_ERR_GENERAL; ++ dbg (("DRBG: reinitialize internal DRBG state with flags %u\n", flags)); ++ drbg_lock (); ++ gcry_drbg->test_data = test_data; ++ ret = _gcry_drbg_init_internal (1, flags, pers); ++ drbg_unlock (); ++ return ret; ++} ++ ++/* Try to close the FDs of the random gather module. This is ++ * currently only implemented for rndlinux. */ ++void ++_gcry_drbg_close_fds (void) ++{ ++#if USE_RNDLINUX ++ drbg_lock (); ++ _gcry_rndlinux_gather_random (NULL, 0, 0, 0); ++ drbg_unlock (); ++#endif ++} ++ ++/* Print some statistics about the RNG. */ ++void ++_gcry_drbg_dump_stats (void) ++{ ++ /* Not yet implemented. */ ++ /* Maybe dumping of reseed counter? */ ++} ++ ++/* This function returns true if no real RNG is available or the ++ * quality of the RNG has been degraded for test purposes. */ ++int ++_gcry_drbg_is_faked (void) ++{ ++ return 0; /* Faked random is not allowed. */ ++} ++ ++/* Add BUFLEN bytes from BUF to the internal random pool. QUALITY ++ * should be in the range of 0..100 to indicate the goodness of the ++ * entropy added, or -1 for goodness not known. */ ++gcry_error_t ++_gcry_drng_add_bytes (const void *buf, size_t buflen, int quality) ++{ ++ gpg_err_code_t ret = 0; ++ struct drbg_string seed; ++ (void) quality; ++ if (NULL == gcry_drbg) ++ return GPG_ERR_GENERAL; ++ drbg_string_fill (&seed, (unsigned char *) buf, buflen); ++ drbg_lock (); ++ ret = drbg_reseed (gcry_drbg, &seed); ++ drbg_unlock (); ++ return ret; ++} ++ ++/* This function is to be used for all types of random numbers, including ++ * nonces ++ */ ++void ++_gcry_drbg_randomize (void *buffer, size_t length, ++ enum gcry_random_level level) ++{ ++ (void) level; ++ drbg_lock (); ++ if (NULL == gcry_drbg) ++ { ++ fips_signal_error ("DRBG is not initialized"); ++ goto bailout; ++ } ++ ++ /* As reseeding changes the entire state of the DRBG, including any ++ * key, either a re-init or a reseed is sufficient for a fork */ ++ if (gcry_drbg->seed_init_pid != getpid ()) ++ { ++ /* We are in a child of us. Perform a reseeding. */ ++ if (drbg_reseed (gcry_drbg, NULL)) ++ { ++ fips_signal_error ("reseeding upon fork failed"); ++ log_fatal ("severe error getting random\n"); ++ goto bailout; ++ } ++ } ++ /* potential integer overflow is covered by drbg_generate which ++ * ensures that length cannot overflow an unsigned int */ ++ if (0 < length) ++ { ++ if (!buffer) ++ goto bailout; ++ if (drbg_generate_long (gcry_drbg, buffer, (unsigned int) length, NULL)) ++ log_fatal ("No random numbers generated\n"); ++ } ++ else ++ { ++ struct drbg_gen *data = (struct drbg_gen *) buffer; ++ /* catch NULL pointer */ ++ if (!data || !data->outbuf) ++ { ++ fips_signal_error ("No output buffer provided"); ++ goto bailout; ++ } ++ gcry_drbg->test_data = data->test_data; ++ if (drbg_generate_long (gcry_drbg, data->outbuf, data->outlen, ++ data->addtl)) ++ log_fatal ("No random numbers generated\n"); ++ } ++bailout: ++ drbg_unlock (); ++ return; ++ ++} ++ ++/*************************************************************** ++ * Self-test code ++ ***************************************************************/ ++ ++/* ++ * Test vectors from ++ * http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip ++ */ ++ ++struct drbg_test_vector ++{ ++ u_int32_t flags; ++ unsigned char *entropy; ++ size_t entropylen; ++ unsigned char *entpra; ++ unsigned char *entprb; ++ size_t entprlen; ++ unsigned char *addtla; ++ unsigned char *addtlb; ++ size_t addtllen; ++ unsigned char *pers; ++ size_t perslen; ++ unsigned char *expected; ++ size_t expectedlen; ++}; ++ ++struct drbg_test_vector drbg_test_pr[] = { ++ { ++ .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_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_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 drbg_test_vector drbg_test_nopr[] = { ++ { ++ .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_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_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, ++ }, ++}; ++ ++ ++/* ++ * Tests implement the CAVS test approach as documented in ++ * http://csrc.nist.gov/groups/STM/cavp/documents/drbg/DRBGVS.pdf ++ */ ++ ++/* ++ * CAVS test ++ */ ++static gpg_err_code_t ++drbg_healthcheck_one (struct drbg_test_vector *test) ++{ ++ gpg_err_code_t ret = GPG_ERR_ENOMEM; ++ struct drbg_state *drbg = NULL; ++ struct drbg_test_data test_data; ++ struct drbg_string addtl, pers, testentropy; ++ int coreref = 0; ++ int pr = 0; ++ unsigned char *buf = drbg_malloc (test->expectedlen); ++ ++ if (!buf) ++ return GPG_ERR_ENOMEM; ++ ret = drbg_algo_available (test->flags, &coreref); ++ if (ret) ++ goto outbuf; ++ ++ drbg = drbg_malloc (sizeof (struct drbg_state)); ++ if (!drbg) ++ goto outbuf; ++ ++ if (test->flags & DRBG_PREDICTION_RESIST) ++ pr = 1; ++ ++ test_data.testentropy = &testentropy; ++ drbg_string_fill (&testentropy, test->entropy, test->entropylen); ++ drbg->test_data = &test_data; ++ drbg_string_fill (&pers, test->pers, test->perslen); ++ ret = drbg_instantiate (drbg, &pers, coreref, pr); ++ if (ret) ++ goto outbuf; ++ ++ drbg_string_fill (&addtl, test->addtla, test->addtllen); ++ if (test->entpra) ++ { ++ drbg_string_fill (&testentropy, test->entpra, test->entprlen); ++ drbg->test_data = &test_data; ++ } ++ drbg_generate_long (drbg, buf, test->expectedlen, &addtl); ++ ++ drbg_string_fill (&addtl, test->addtlb, test->addtllen); ++ if (test->entprb) ++ { ++ drbg_string_fill (&testentropy, test->entprb, test->entprlen); ++ drbg->test_data = &test_data; ++ } ++ drbg_generate_long (drbg, buf, test->expectedlen, &addtl); ++ ++ ret = memcmp (test->expected, buf, test->expectedlen); ++ ++ drbg_uninstantiate (drbg); ++outbuf: ++ xfree (buf); ++ if (drbg) ++ xfree (drbg); ++ return ret; ++} ++ ++/* ++ * Tests as defined in 11.3.2 in addition to the cipher tests: testing ++ * of the error handling. ++ * ++ * Note, testing the reseed counter is not done as an automatic reseeding ++ * is performed in drbg_generate when the reseed counter is too large. ++ */ ++static gpg_err_code_t ++drbg_healthcheck_sanity (struct drbg_test_vector *test) ++{ ++ unsigned int len = 0; ++ struct drbg_state *drbg = NULL; ++ gpg_err_code_t ret = GPG_ERR_GENERAL; ++ gpg_err_code_t tmpret = GPG_ERR_GENERAL; ++ struct drbg_test_data test_data; ++ struct drbg_string addtl, testentropy; ++ int coreref = 0; ++ unsigned char *buf = NULL; ++ size_t max_addtllen, max_request_bytes; ++ ++ /* only perform test in FIPS mode */ ++ if (0 == fips_mode ()) ++ return 0; ++ ++ buf = drbg_malloc (test->expectedlen); ++ if (!buf) ++ return GPG_ERR_ENOMEM; ++ tmpret = drbg_algo_available (test->flags, &coreref); ++ if (tmpret) ++ goto outbuf; ++ drbg = drbg_malloc (sizeof (struct drbg_state)); ++ if (!drbg) ++ goto outbuf; ++ ++ /* if the following tests fail, it is likely that there is a buffer ++ * overflow and we get a SIGSEV */ ++ ret = drbg_instantiate (drbg, NULL, coreref, 1); ++ if (ret) ++ goto outbuf; ++ max_addtllen = drbg_max_addtl (); ++ max_request_bytes = drbg_max_request_bytes (); ++ /* overflow addtllen with additonal info string */ ++ drbg_string_fill (&addtl, test->addtla, (max_addtllen + 1)); ++ len = drbg_generate (drbg, buf, test->expectedlen, &addtl); ++ if (len) ++ goto outdrbg; ++ ++ /* overflow max_bits */ ++ len = drbg_generate (drbg, buf, (max_request_bytes + 1), NULL); ++ if (len) ++ goto outdrbg; ++ drbg_uninstantiate (drbg); ++ ++ /* test failing entropy source as defined in 11.3.2 */ ++ test_data.testentropy = NULL; ++ test_data.fail_seed_source = 1; ++ drbg->test_data = &test_data; ++ tmpret = drbg_instantiate (drbg, NULL, coreref, 0); ++ if (!tmpret) ++ goto outdrbg; ++ test_data.fail_seed_source = 0; ++ ++ test_data.testentropy = &testentropy; ++ drbg_string_fill (&testentropy, test->entropy, test->entropylen); ++ /* overflow max addtllen with personalization string */ ++ tmpret = drbg_instantiate (drbg, &addtl, coreref, 0); ++ if (!tmpret) ++ goto outdrbg; ++ ++ /* test uninstantated DRBG */ ++ len = drbg_generate (drbg, buf, (max_request_bytes + 1), NULL); ++ if (len) ++ goto outbuf; ++ ++ dbg (("DRBG: Sanity tests for failure code paths successfully completed\n")); ++ ret = 0; ++ ++outdrbg: ++ drbg_uninstantiate (drbg); ++outbuf: ++ xfree (buf); ++ if (drbg) ++ xfree (drbg); ++ return ret; ++} ++ ++/* ++ * DRBG Healthcheck function as required in SP800-90A ++ * ++ * return: ++ * 0 on success (all tests pass) ++ * >0 on error (return code indicate the number of failures) ++ */ ++int ++drbg_healthcheck (void) ++{ ++ int ret = 0; ++ ret += drbg_healthcheck_one (&drbg_test_nopr[0]); ++ ret += drbg_healthcheck_one (&drbg_test_nopr[1]); ++ ret += drbg_healthcheck_one (&drbg_test_nopr[2]); ++ ret += drbg_healthcheck_one (&drbg_test_pr[0]); ++ ret += drbg_healthcheck_one (&drbg_test_pr[1]); ++ ret += drbg_healthcheck_one (&drbg_test_pr[2]); ++ ret += drbg_healthcheck_sanity (&drbg_test_nopr[0]); ++ return ret; ++} ++ ++/* Run the self-tests. */ ++gcry_error_t ++_gcry_drbg_selftest (selftest_report_func_t report) ++{ ++ gcry_err_code_t ec; ++ const char *errtxt = NULL; ++ drbg_lock (); ++ if (0 != drbg_healthcheck ()) ++ errtxt = "RNG output does not match known value"; ++ drbg_unlock (); ++ if (report && errtxt) ++ report ("random", 0, "KAT", errtxt); ++ ec = errtxt ? GPG_ERR_SELFTEST_FAILED : 0; ++ return gpg_error (ec); ++} ++ ++/*************************************************************** ++ * Cipher invocations requested by DRBG ++ ***************************************************************/ ++ ++static gpg_err_code_t ++drbg_gcry_hmac (struct drbg_state *drbg, const unsigned char *key, ++ unsigned char *outval, const struct drbg_string *buf) ++{ ++ gpg_error_t err; ++ gcry_md_hd_t hd; ++ ++ if (key) ++ { ++ err = _gcry_md_open (&hd, drbg->core->backend_cipher, GCRY_MD_FLAG_HMAC); ++ if (err) ++ return err; ++ err = _gcry_md_setkey (hd, key, drbg_statelen (drbg)); ++ if (err) ++ return err; ++ } ++ else ++ { ++ err = _gcry_md_open (&hd, drbg->core->backend_cipher, 0); ++ if (err) ++ return err; ++ } ++ for (; NULL != buf; buf = buf->next) ++ _gcry_md_write (hd, buf->buf, buf->len); ++ _gcry_md_final (hd); ++ memcpy (outval, _gcry_md_read (hd, drbg->core->backend_cipher), ++ drbg_blocklen (drbg)); ++ _gcry_md_close (hd); ++ return 0; ++} ++ ++static gpg_err_code_t ++drbg_gcry_sym (struct drbg_state *drbg, const unsigned char *key, ++ unsigned char *outval, const struct drbg_string *buf) ++{ ++ gpg_error_t err; ++ gcry_cipher_hd_t hd; ++ ++ err = ++ _gcry_cipher_open (&hd, drbg->core->backend_cipher, GCRY_CIPHER_MODE_ECB, ++ 0); ++ if (err) ++ return err; ++ if (drbg_blocklen (drbg) != ++ _gcry_cipher_get_algo_blklen (drbg->core->backend_cipher)) ++ return -GPG_ERR_NO_ERROR; ++ if (drbg_blocklen (drbg) < buf->len) ++ return -GPG_ERR_NO_ERROR; ++ err = _gcry_cipher_setkey (hd, key, drbg_keylen (drbg)); ++ if (err) ++ return err; ++ /* in is only component */ ++ _gcry_cipher_encrypt (hd, outval, drbg_blocklen (drbg), buf->buf, buf->len); ++ _gcry_cipher_close (hd); ++ return 0; ++} +-- +1.9.3 + diff --git a/0007-User-interface-to-DRBG.patch b/v9-0007-User-interface-to-DRBG.patch similarity index 72% rename from 0007-User-interface-to-DRBG.patch rename to v9-0007-User-interface-to-DRBG.patch index d89b353..fedee59 100644 --- a/0007-User-interface-to-DRBG.patch +++ b/v9-0007-User-interface-to-DRBG.patch @@ -1,15 +1,58 @@ -Changes v4: +From 581c850aa7ac63086a489480efa4cc0bf8cfd510 Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Thu, 21 Aug 2014 21:26:27 +0200 +Subject: [PATCH v9 7/7] User interface to DRBG - * add explicit type casting from void to unsigned char as reported - in https://bugzilla.novell.com/show_bug.cgi?id=877233 +DRBG Usage +========== +The SP 800-90A DRBG allows the user to specify a personalization string +for initialization as well as an additional information string for each +random number request. The following code fragments show how a caller +uses the kernel crypto API to use the full functionality of the DRBG. -Signed-off-by: Stephan Mueller +Usage without any additional data +--------------------------------- +gcry_randomize(outbuf, OUTLEN, GCRY_STRONG_RANDOM); + +Usage with personalization string during initialization +------------------------------------------------------- +struct drbg_string pers; + +drbg_string_fill(&pers, "string", strlen("string")); +// The reset completely re-initializes the DRBG with the provided +// personalization string without changing the DRBG type +ret = gcry_control(GCRYCTL_DRBG_REINIT, 0, &pers, NULL); +gcry_randomize(outbuf, OUTLEN, GCRY_STRONG_RANDOM); + +Usage with additional information string during random number request +--------------------------------------------------------------------- +struct drbg_string addtl; + +drbg_string_fill(&addtl, "string", strlen("string")); +// The following call is a wrapper to gcry_randomize() and returns +// the same error codes. +gcry_randomize_drbg(outbuf, OUTLEN, GCRY_STRONG_RANDOM, &addtl); + +Usage with personalization and additional information strings +------------------------------------------------------------- +Just mix both scenarios above. + +Switch the DRBG type to some other type +--------------------------------------- +// Switch to CTR DRBG AES-128 without prediction resistance +ret = gcry_control(GCRYCTL_DRBG_REINIT, DRBG_NOPR_CTRAES128, NULL, NULL); +gcry_randomize(outbuf, OUTLEN, GCRY_STRONG_RANDOM); + +Signed-off-by: Stephan Mueller --- -diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in -index c84a3f7..569d7a0 100644 ---- a/src/gcrypt.h.in -+++ b/src/gcrypt.h.in -@@ -193,7 +193,7 @@ gcry_error_t gcry_err_make_from_errno (gcry_err_source_t source, int err); + src/gcrypt.h.in | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 144 insertions(+), 13 deletions(-) + +Index: libgcrypt-1.6.1/src/gcrypt.h.in +=================================================================== +--- libgcrypt-1.6.1.orig/src/gcrypt.h.in 2014-01-29 10:49:05.000000000 +0100 ++++ libgcrypt-1.6.1/src/gcrypt.h.in 2014-09-02 13:45:42.439648231 +0200 +@@ -193,7 +193,7 @@ gcry_error_t gcry_err_make_from_errno (g /* Return an error value with the system error ERR. */ gcry_err_code_t gcry_error_from_errno (int err); @@ -36,24 +79,17 @@ index c84a3f7..569d7a0 100644 /* Check that the library fulfills the version requirement. */ const char *gcry_check_version (const char *req_version); -@@ -329,13 +329,14 @@ enum gcry_ctl_cmds +@@ -329,7 +329,8 @@ enum gcry_ctl_cmds GCRYCTL_SET_CCM_LENGTHS = 69, GCRYCTL_CLOSE_RANDOM_DEVICE = 70, GCRYCTL_INACTIVATE_FIPS_FLAG = 71, - GCRYCTL_REACTIVATE_FIPS_FLAG = 72 + GCRYCTL_REACTIVATE_FIPS_FLAG = 72, -+ GCRYCTL_DRBG_REINIT = 73, ++ GCRYCTL_DRBG_REINIT = 74, }; /* Perform various operations defined by CMD. */ - gcry_error_t gcry_control (enum gcry_ctl_cmds CMD, ...); - -- -+ - /* S-expression management. */ - - /* The object to represent an S-expression as used with the public key -@@ -477,7 +478,7 @@ gpg_error_t gcry_sexp_extract_param (gcry_sexp_t sexp, +@@ -477,7 +478,7 @@ gpg_error_t gcry_sexp_extract_param (gcr const char *list, ...) _GCRY_GCC_ATTR_SENTINEL(0); @@ -71,7 +107,7 @@ index c84a3f7..569d7a0 100644 /************************************ * * * Symmetric Cipher Functions * -@@ -1015,7 +1016,7 @@ size_t gcry_cipher_get_algo_blklen (int algo); +@@ -1015,7 +1016,7 @@ size_t gcry_cipher_get_algo_blklen (int #define gcry_cipher_test_algo(a) \ gcry_cipher_algo_info( (a), GCRYCTL_TEST_ALGO, NULL, NULL ) @@ -80,7 +116,7 @@ index c84a3f7..569d7a0 100644 /************************************ * * * Asymmetric Cipher Functions * -@@ -1114,7 +1115,7 @@ gcry_sexp_t gcry_pk_get_param (int algo, const char *name); +@@ -1114,7 +1115,7 @@ gcry_sexp_t gcry_pk_get_param (int algo, gcry_error_t gcry_pubkey_get_sexp (gcry_sexp_t *r_sexp, int mode, gcry_ctx_t ctx); @@ -89,7 +125,7 @@ index c84a3f7..569d7a0 100644 /************************************ * * -@@ -1291,7 +1292,7 @@ void gcry_md_debug (gcry_md_hd_t hd, const char *suffix); +@@ -1291,7 +1292,7 @@ void gcry_md_debug (gcry_md_hd_t hd, con #define gcry_md_get_asnoid(a,b,n) \ gcry_md_algo_info((a), GCRYCTL_GET_ASNOID, (b), (n)) @@ -98,7 +134,7 @@ index c84a3f7..569d7a0 100644 /********************************************** * * -@@ -1411,7 +1412,7 @@ int gcry_mac_map_name (const char *name) _GCRY_GCC_ATTR_PURE; +@@ -1407,7 +1408,7 @@ int gcry_mac_map_name (const char *name) #define gcry_mac_test_algo(a) \ gcry_mac_algo_info( (a), GCRYCTL_TEST_ALGO, NULL, NULL ) @@ -107,7 +143,7 @@ index c84a3f7..569d7a0 100644 /****************************** * * * Key Derivation Functions * -@@ -1439,7 +1440,7 @@ gpg_error_t gcry_kdf_derive (const void *passphrase, size_t passphraselen, +@@ -1435,7 +1436,7 @@ gpg_error_t gcry_kdf_derive (const void @@ -116,7 +152,7 @@ index c84a3f7..569d7a0 100644 /************************************ * * * Random Generating Functions * -@@ -1508,7 +1509,7 @@ void gcry_create_nonce (void *buffer, size_t length); +@@ -1504,7 +1505,7 @@ void gcry_create_nonce (void *buffer, si @@ -125,7 +161,7 @@ index c84a3f7..569d7a0 100644 /*******************************/ /* */ /* Prime Number Functions */ -@@ -1567,7 +1568,7 @@ void gcry_prime_release_factors (gcry_mpi_t *factors); +@@ -1563,7 +1564,7 @@ void gcry_prime_release_factors (gcry_mp gcry_error_t gcry_prime_check (gcry_mpi_t x, unsigned int flags); @@ -134,7 +170,7 @@ index c84a3f7..569d7a0 100644 /************************************ * * * Miscellaneous Stuff * -@@ -1672,6 +1673,136 @@ int gcry_is_secure (const void *a) _GCRY_GCC_ATTR_PURE; +@@ -1668,6 +1669,136 @@ int gcry_is_secure (const void *a) _GCRY /* Return true if Libgcrypt is in FIPS mode. */ #define gcry_fips_mode_active() !!gcry_control (GCRYCTL_FIPS_MODE_P, 0)