3073 lines
81 KiB
Perl
3073 lines
81 KiB
Perl
|
#!/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 <sm@atsec.com>
|
||
|
# Werner Koch <wk@g10code.com> (libgcrypt interface)
|
||
|
# Tomas Mraz <tmraz@redhat.com> (addition of DSA2)
|
||
|
# Copyright (c) atsec information security corporation
|
||
|
#
|
||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
# of this software and associated documentation files (the "Software"), to deal
|
||
|
# in the Software without restriction, including without limitation the rights
|
||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
# copies of the Software, and to permit persons to whom the Software is
|
||
|
# furnished to do so, subject to the following conditions:
|
||
|
#
|
||
|
# The above copyright notice and this permission notice shall be included in
|
||
|
# all copies or substantial portions of the Software.
|
||
|
#
|
||
|
# NO WARRANTY
|
||
|
#
|
||
|
# BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||
|
# FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||
|
# OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||
|
# PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||
|
# OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||
|
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||
|
# TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||
|
# PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||
|
# REPAIR OR CORRECTION.
|
||
|
#
|
||
|
# IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||
|
# WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||
|
# REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||
|
# INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||
|
# OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||
|
# TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||
|
# YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||
|
# PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||
|
# POSSIBILITY OF SUCH DAMAGES.
|
||
|
#
|
||
|
#
|
||
|
# test execution instruction:
|
||
|
# 1. get the request files from the lab
|
||
|
# 2. call each request file from 1. with this program:
|
||
|
# $0 <FILE>.rep
|
||
|
# 3. send the resulting file <FILE>.rsp to the lab
|
||
|
#
|
||
|
#
|
||
|
# Test should be easily adoptable to other implementations
|
||
|
# See the first functions for this task
|
||
|
#
|
||
|
# Following tests are covered (others may also be covered
|
||
|
# but have not been tested)
|
||
|
#
|
||
|
# AES
|
||
|
# [CBC|CFB128|ECB|OFB]GFSbox[128|192|256]
|
||
|
# [CBC|CFB128|ECB|OFB]MCT[128|192|256]
|
||
|
# [CBC|CFB128|ECB|OFB]VarKey[128|192|256]
|
||
|
# [CBC|CFB128|ECB|OFB]KeySbox[128|192|256]
|
||
|
# [CBC|CFB128|ECB|OFB]MMT[128|192|256]
|
||
|
# [CBC|CFB128|ECB|OFB]VarTxt[128|192|256]
|
||
|
#
|
||
|
# RSA
|
||
|
# SigGen[15|RSA]
|
||
|
# SigVer15
|
||
|
# (SigVerRSA is not applicable for OpenSSL as X9.31 padding
|
||
|
# is not done through openssl dgst)
|
||
|
# KeyGen RSA X9.31
|
||
|
#
|
||
|
# SHA
|
||
|
# SHA[1|224|256|384|512]ShortMsg
|
||
|
# SHA[1|224|256|384|512]LongMsg
|
||
|
# SHA[1|224|256|384|512]Monte
|
||
|
#
|
||
|
# HMAC (SHA - caveat: we only support hash output equal to the block size of
|
||
|
# of the hash - we do not support truncation of the hash; to support
|
||
|
# that, we first need to decipher the HMAC.req file - see hmac_kat() )
|
||
|
# HMAC
|
||
|
#
|
||
|
# TDES
|
||
|
# T[CBC|CFB??|ECB|OFB]Monte[1|2|3]
|
||
|
# T[CBC|CFB??|ECB|OFB]permop
|
||
|
# T[CBC|CFB??|ECB|OFB]MMT[1|2|3]
|
||
|
# T[CBC|CFB??|ECB|OFB]subtab
|
||
|
# T[CBC|CFB??|ECB|OFB]varkey
|
||
|
# T[CBC|CFB??|ECB|OFB]invperm
|
||
|
# T[CBC|CFB??|ECB|OFB]vartext
|
||
|
# WARNING: TDES in CFB and OFB mode problems see below
|
||
|
#
|
||
|
# ANSI X9.31 RNG
|
||
|
# ANSI931_AES128MCT
|
||
|
# ANSI931_AES128VST
|
||
|
#
|
||
|
# DSA2
|
||
|
# PQGGen
|
||
|
# PQGVer
|
||
|
# KeyPair
|
||
|
# SigGen
|
||
|
# SigVer
|
||
|
#
|
||
|
# DRBG:
|
||
|
# CTR DRBG
|
||
|
# Hash DRBG
|
||
|
# HMAC DRBG
|
||
|
# with and w/o PR
|
||
|
#
|
||
|
# RC4 (atsec developed tests)
|
||
|
# RC4KeyBD
|
||
|
# RC4MCT
|
||
|
# RC4PltBD
|
||
|
# RC4REGT
|
||
|
#
|
||
|
#
|
||
|
# TDES MCT for CFB and OFB:
|
||
|
# -------------------------
|
||
|
# The inner loop cannot be handled by this script. If you want to have tests
|
||
|
# for these cipher types, implement your own inner loop and add it to
|
||
|
# crypto_mct.
|
||
|
#
|
||
|
# the value $next_source in crypto_mct is NOT set by the standard implementation
|
||
|
# of this script. It would need to be set as follows for these two (code take
|
||
|
# from fipsdrv.c from libgcrypt - the value input at the end will contain the
|
||
|
# the value for $next_source:
|
||
|
#
|
||
|
# ... inner loop ...
|
||
|
# ...
|
||
|
# get_current_iv (hd, last_iv, blocklen);
|
||
|
# ... encrypt / decrypt (input is the data to be en/decrypted and output is the
|
||
|
# result of operation) ...
|
||
|
# if (encrypt_mode && (cipher_mode == GCRY_CIPHER_MODE_CFB))
|
||
|
# memcpy (input, last_iv, blocklen);
|
||
|
# else if (cipher_mode == GCRY_CIPHER_MODE_OFB)
|
||
|
# memcpy (input, last_iv, blocklen);
|
||
|
# else if (!encrypt_mode && cipher_mode == GCRY_CIPHER_MODE_CFB)
|
||
|
# {
|
||
|
# /* Reconstruct the output vector. */
|
||
|
# int i;
|
||
|
# for (i=0; i < blocklen; i++)
|
||
|
# input[i] ^= output[i];
|
||
|
# }
|
||
|
# ... inner loop ends ...
|
||
|
# ==> now, the value of input is to be put into $next_source
|
||
|
|
||
|
use strict;
|
||
|
use warnings;
|
||
|
use IPC::Open2;
|
||
|
use Getopt::Std;
|
||
|
use MIME::Base64;
|
||
|
|
||
|
use Math::BigInt;
|
||
|
|
||
|
# Contains the command line options
|
||
|
my %opt;
|
||
|
|
||
|
#################################################################
|
||
|
##### Central interface functions to the external ciphers #######
|
||
|
#################################################################
|
||
|
# Only these interface routines should be changed in case of
|
||
|
# porting to a new cipher library
|
||
|
#
|
||
|
# For porting to a new library, create implementation of these functions
|
||
|
# and then add pointers to the respective implementation of each
|
||
|
# function to the given variables.
|
||
|
|
||
|
# common encryption/decryption routine
|
||
|
# $1 key in hex form (please note for 3DES: even when ede3 for three
|
||
|
# independent ciphers is given with the cipher specification, we hand in
|
||
|
# either one key for k1 = k2 = k3, two keys which are concatinated for
|
||
|
# k1 = k3, k2 independent, or three keys which are concatinated for
|
||
|
# k1, k2, k3 independent)
|
||
|
# $2 iv in hex form
|
||
|
# $3 cipher - the cipher string is defined as specified in the openssl
|
||
|
# enc(1ssl) specification for the option "-ciphername"
|
||
|
# (e.g. aes-128-cbc or des-ede3-cbc)
|
||
|
# $4 encrypt=1/decrypt=0
|
||
|
# $5 de/encrypted data in hex form
|
||
|
# return en/decrypted data in hex form
|
||
|
my $encdec;
|
||
|
|
||
|
#
|
||
|
# Derive an RSA key from the given X9.31 parameters.
|
||
|
# $1: modulus size
|
||
|
# $2: E in hex form
|
||
|
# $3: Xp1 in hex form
|
||
|
# $4: Xp2 in hex form
|
||
|
# $5: Xp in hex form
|
||
|
# $6: Xq1 in hex form
|
||
|
# $7: Xq2 in hex form
|
||
|
# $8: Xq in hex form
|
||
|
# return: string with the calculated values in hex format, where each value
|
||
|
# is separated from the previous with a \n in the following order:
|
||
|
# P\n
|
||
|
# Q\n
|
||
|
# N\n
|
||
|
# D\n
|
||
|
my $rsa_derive;
|
||
|
|
||
|
# Sign a message with RSA
|
||
|
# $1: data to be signed in hex form
|
||
|
# $2: Hash algo
|
||
|
# $3: Key file in PEM format with the private key
|
||
|
# return: digest in hex format
|
||
|
my $rsa_sign;
|
||
|
|
||
|
# Verify a message with RSA
|
||
|
# $1: data to be verified in hex form
|
||
|
# $2: hash algo
|
||
|
# $3: file holding the public RSA key in PEM format
|
||
|
# $4: file holding the signature in binary form
|
||
|
# return: 1 == verified / 0 == not verified
|
||
|
my $rsa_verify;
|
||
|
|
||
|
# generate a new private RSA key with the following properties:
|
||
|
# exponent is 65537
|
||
|
# PEM format
|
||
|
# $1 key size in bit
|
||
|
# $2 keyfile name
|
||
|
# return: nothing, but file created
|
||
|
my $gen_rsakey;
|
||
|
|
||
|
# Creating a hash
|
||
|
# $1: Plaintext in hex form
|
||
|
# $2: hash type in the form documented in openssl's dgst(1ssl) - e.g.
|
||
|
# sha1, sha224, sha256, sha384, sha512
|
||
|
# return: hash in hex form
|
||
|
my $hash;
|
||
|
|
||
|
# supplying the call to the external cipher implementation
|
||
|
# that is being used to keep STDIN and STDOUT open
|
||
|
# to maintain the state of the block chaining
|
||
|
# $1: cipher
|
||
|
# $2: 1=encryption, 0=decryption
|
||
|
# $3: buffersize needed for openssl
|
||
|
# $4: encryption key in binary form
|
||
|
# $5: IV in binary form
|
||
|
# return: command line to execute the application
|
||
|
my $state_cipher;
|
||
|
# the only difference of the DES version is that it implements the inner loop
|
||
|
# of the TDES tests
|
||
|
my $state_cipher_des;
|
||
|
|
||
|
# supplying the call to the external cipher implementation
|
||
|
# that is being used to keep STDIN and STDOUT open
|
||
|
# to maintain the state of the RNG with its seed
|
||
|
#
|
||
|
# input holds seed values
|
||
|
# $1: cipher key in hex format
|
||
|
# $2: DT value in hex format
|
||
|
# $3: V value in hex format
|
||
|
#
|
||
|
# return: command line to execute the application
|
||
|
#
|
||
|
# the application is expected to deliver random values on STDOUT - the script
|
||
|
# reads 128 bits repeatedly where the state of the RNG must be retained
|
||
|
# between the reads. The output of the RNG on STDOUT is assumed to be binary.
|
||
|
my $state_rng;
|
||
|
|
||
|
# Generate an HMAC based on SHAx
|
||
|
# $1: Key to be used for the HMAC in hex format
|
||
|
# $2: length of the hash to be calculated in bits
|
||
|
# $3: Message for which the HMAC shall be calculated in hex format
|
||
|
# $4: hash type (1 - SHA1, 224 - SHA224, and so on)
|
||
|
# return: calculated HMAC in hex format
|
||
|
my $hmac;
|
||
|
|
||
|
#
|
||
|
# Generate the P, Q, G, Seed, counter, h (value used to generate g) values
|
||
|
# for DSA
|
||
|
# $1: modulus size
|
||
|
# $2: q size
|
||
|
# $3: seed (might be empty string)
|
||
|
# return: string with the calculated values in hex format, where each value
|
||
|
# is separated from the previous with a \n in the following order:
|
||
|
# P\n
|
||
|
# Q\n
|
||
|
# G\n
|
||
|
# Seed\n
|
||
|
# counter\n
|
||
|
# h
|
||
|
my $dsa_pqggen;
|
||
|
|
||
|
# Generate the G value from P and Q
|
||
|
# for DSA
|
||
|
# $1: modulus size
|
||
|
# $2: q size
|
||
|
# $3: P in hex form
|
||
|
# $4: Q in hex form
|
||
|
# return: string with the calculated values in hex format, where each value
|
||
|
# is separated from the previous with a \n in the following order:
|
||
|
# P\n
|
||
|
# Q\n
|
||
|
# G\n
|
||
|
my $dsa_ggen;
|
||
|
|
||
|
#
|
||
|
# Generate an DSA public key from the provided parameters:
|
||
|
# $1: Name of file to create
|
||
|
# $2: P in hex form
|
||
|
# $3: Q in hex form
|
||
|
# $4: G in hex form
|
||
|
# $5: Y in hex form
|
||
|
my $dsa_genpubkey;
|
||
|
|
||
|
# Verify a message with DSA
|
||
|
# $1: data to be verified in hex form
|
||
|
# $2: file holding the public DSA key in PEM format
|
||
|
# $3: R value of the signature
|
||
|
# $4: S value of the signature
|
||
|
# return: 1 == verified / 0 == not verified
|
||
|
my $dsa_verify;
|
||
|
|
||
|
# generate a new DSA key with the following properties:
|
||
|
# PEM format
|
||
|
# $1: modulus size
|
||
|
# $2: q size
|
||
|
# $3 keyfile name
|
||
|
# return: file created with key, string with values of P, Q, G in hex format
|
||
|
my $gen_dsakey;
|
||
|
|
||
|
# generate a new DSA private key XY parameters in domain:
|
||
|
# PEM format
|
||
|
# $1: P in hex form
|
||
|
# $2: Q in hex form
|
||
|
# $3: G in hex form
|
||
|
# return: string with values of X, Y in hex format
|
||
|
my $gen_dsakey_domain;
|
||
|
|
||
|
# Sign a message with DSA
|
||
|
# $1: data to be signed in hex form
|
||
|
# $2: Key file in PEM format with the private key
|
||
|
# return: hash of digest information in hex format with Y, R, S as keys
|
||
|
my $dsa_sign;
|
||
|
|
||
|
# interface with SP800-90A DRBG
|
||
|
# $1 cipher - the sign whether prediction resistance is required is visible on
|
||
|
# set additional entropy
|
||
|
# $2 expected length of output
|
||
|
# $3 entropy in hex
|
||
|
# $4 nonce in hex
|
||
|
# $5 personalization string in hex - if "z", string was empty
|
||
|
# $6 1st additional input in hex - if "z", string was empty
|
||
|
# $7 2nd additional input in hex - if "z", string was empty
|
||
|
# $8 1st additional entropy in hex - if "z", string was empty
|
||
|
# $9 2nd additional entropy in hex - if "z", string was empty
|
||
|
# return: random value in hex format
|
||
|
my $drbg;
|
||
|
|
||
|
################################################################
|
||
|
##### OpenSSL interface functions
|
||
|
################################################################
|
||
|
sub openssl_encdec($$$$$) {
|
||
|
my $key=shift;
|
||
|
my $iv=shift;
|
||
|
my $cipher=shift;
|
||
|
my $enc = (shift) ? "-e" : "-d";
|
||
|
my $data=shift;
|
||
|
|
||
|
# We only invoke the driver with the IV parameter, if we have
|
||
|
# an IV, otherwise, we skip it
|
||
|
$iv = "-iv $iv" if ($iv);
|
||
|
|
||
|
$data=hex2bin($data);
|
||
|
my $program="openssl enc -$cipher -nopad -nosalt -K $key $enc $iv";
|
||
|
$program = "rc4 -k $key" if $opt{'R'}; #for ARCFOUR, no IV must be given
|
||
|
$data=pipe_through_program($data,$program);
|
||
|
return bin2hex($data);
|
||
|
}
|
||
|
|
||
|
sub openssl_rsa_sign($$$) {
|
||
|
my $data = shift;
|
||
|
my $cipher = shift;
|
||
|
my $keyfile = shift;
|
||
|
|
||
|
$data=hex2bin($data);
|
||
|
die "ARCFOUR not available for RSA" if $opt{'R'};
|
||
|
$data=pipe_through_program($data,
|
||
|
"openssl dgst -$cipher -binary -sign $keyfile");
|
||
|
return bin2hex($data);
|
||
|
}
|
||
|
|
||
|
sub openssl_rsa_verify($$$$) {
|
||
|
my $data = shift;
|
||
|
my $cipher = shift;
|
||
|
my $keyfile = shift;
|
||
|
my $sigfile = shift;
|
||
|
|
||
|
$data = hex2bin($data);
|
||
|
die "ARCFOUR not available for RSA" if $opt{'R'};
|
||
|
$data = pipe_through_program($data,
|
||
|
"openssl dgst -$cipher -binary -verify $keyfile -signature $sigfile");
|
||
|
|
||
|
# Parse through the OpenSSL output information
|
||
|
return ($data =~ /OK/);
|
||
|
}
|
||
|
|
||
|
sub openssl_gen_rsakey($$) {
|
||
|
my $keylen = shift;
|
||
|
my $file = shift;
|
||
|
|
||
|
die "ARCFOUR not available for RSA" if $opt{'R'};
|
||
|
# generating of a key with exponent 0x10001
|
||
|
my @args = ("openssl", "genrsa", "-F4", "-out", "$file", "$keylen");
|
||
|
system(@args) == 0
|
||
|
or die "system @args failed: $?";
|
||
|
die "system @args failed: file $file not created" if (! -f $file);
|
||
|
}
|
||
|
|
||
|
sub openssl_hash($$) {
|
||
|
my $pt = shift;
|
||
|
my $cipher = shift;
|
||
|
|
||
|
die "ARCFOUR not available for hashes" if $opt{'R'};
|
||
|
my $hash = hex2bin($pt);
|
||
|
#bin2hex not needed as the '-hex' already converts it
|
||
|
return pipe_through_program($hash, "openssl dgst -$cipher -hex");
|
||
|
}
|
||
|
|
||
|
sub openssl_state_cipher($$$$$) {
|
||
|
my $cipher = shift;
|
||
|
my $encdec = shift;
|
||
|
my $bufsize = shift;
|
||
|
my $key = shift;
|
||
|
my $iv = shift;
|
||
|
|
||
|
my $enc = $encdec ? "-e": "-d";
|
||
|
|
||
|
# We only invoke the driver with the IV parameter, if we have
|
||
|
# an IV, otherwise, we skip it
|
||
|
$iv = "-iv ".bin2hex($iv) if ($iv);
|
||
|
|
||
|
my $out = "openssl enc -'$cipher' $enc -nopad -nosalt -bufsize $bufsize -K ".bin2hex($key)." $iv";
|
||
|
#for ARCFOUR, no IV must be given
|
||
|
$out = "rc4 -k " . bin2hex($key) if $opt{'R'};
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
###### End of OpenSSL interface implementation ############
|
||
|
|
||
|
###########################################################
|
||
|
###### libgcrypt implementation
|
||
|
###########################################################
|
||
|
sub libgcrypt_encdec($$$$$) {
|
||
|
my $key=shift;
|
||
|
my $iv=shift;
|
||
|
my $cipher=shift;
|
||
|
my $enc = (shift) ? "encrypt" : "decrypt";
|
||
|
my $data=shift;
|
||
|
|
||
|
# We only invoke the driver with the IV parameter, if we have
|
||
|
# an IV, otherwise, we skip it
|
||
|
$iv = "--iv $iv" if ($iv);
|
||
|
|
||
|
my $program="fipsdrv --key $key $iv --algo $cipher $enc";
|
||
|
|
||
|
return pipe_through_program($data,$program);
|
||
|
|
||
|
}
|
||
|
|
||
|
sub libgcrypt_rsa_derive($$$$$$$$) {
|
||
|
my $n = shift;
|
||
|
my $e = shift;
|
||
|
my $xp1 = shift;
|
||
|
my $xp2 = shift;
|
||
|
my $xp = shift;
|
||
|
my $xq1 = shift;
|
||
|
my $xq2 = shift;
|
||
|
my $xq = shift;
|
||
|
my $sexp;
|
||
|
my @tmp;
|
||
|
|
||
|
$n = sprintf ("%u", $n);
|
||
|
$e = sprintf ("%u", hex($e));
|
||
|
$sexp = "(genkey(rsa(nbits " . sprintf ("%u:%s", length($n), $n) . ")"
|
||
|
. "(rsa-use-e " . sprintf ("%u:%s", length($e), $e) . ")"
|
||
|
. "(derive-parms"
|
||
|
. "(Xp1 #$xp1#)"
|
||
|
. "(Xp2 #$xp2#)"
|
||
|
. "(Xp #$xp#)"
|
||
|
. "(Xq1 #$xq1#)"
|
||
|
. "(Xq2 #$xq2#)"
|
||
|
. "(Xq #$xq#))))\n";
|
||
|
|
||
|
return pipe_through_program($sexp, "fipsdrv rsa-derive");
|
||
|
}
|
||
|
|
||
|
|
||
|
sub libgcrypt_rsa_sign($$$) {
|
||
|
my $data = shift;
|
||
|
my $hashalgo = shift;
|
||
|
my $keyfile = shift;
|
||
|
|
||
|
die "ARCFOUR not available for RSA" if $opt{'R'};
|
||
|
|
||
|
return pipe_through_program($data,
|
||
|
"fipsdrv --pkcs1 --algo $hashalgo --key $keyfile rsa-sign");
|
||
|
}
|
||
|
|
||
|
sub libgcrypt_rsa_verify($$$$) {
|
||
|
my $data = shift;
|
||
|
my $hashalgo = shift;
|
||
|
my $keyfile = shift;
|
||
|
my $sigfile = shift;
|
||
|
|
||
|
die "ARCFOUR not available for RSA" if $opt{'R'};
|
||
|
$data = pipe_through_program($data,
|
||
|
"fipsdrv --pkcs1 --algo $hashalgo --key $keyfile --signature $sigfile rsa-verify");
|
||
|
|
||
|
# Parse through the output information
|
||
|
return ($data =~ /GOOD signature/);
|
||
|
}
|
||
|
|
||
|
sub libgcrypt_gen_rsakey($$) {
|
||
|
my $keylen = shift;
|
||
|
my $file = shift;
|
||
|
|
||
|
die "ARCFOUR not available for RSA" if $opt{'R'};
|
||
|
my @args = ("fipsdrv --keysize $keylen rsa-gen > $file");
|
||
|
system(@args) == 0
|
||
|
or die "system @args failed: $?";
|
||
|
die "system @args failed: file $file not created" if (! -f $file);
|
||
|
}
|
||
|
|
||
|
sub libgcrypt_hash($$) {
|
||
|
my $pt = shift;
|
||
|
my $hashalgo = shift;
|
||
|
|
||
|
my $program = "fipsdrv --algo $hashalgo digest";
|
||
|
die "ARCFOUR not available for hashes" if $opt{'R'};
|
||
|
|
||
|
return pipe_through_program($pt, $program);
|
||
|
}
|
||
|
|
||
|
sub libgcrypt_state_cipher($$$$$) {
|
||
|
my $cipher = shift;
|
||
|
my $enc = (shift) ? "encrypt": "decrypt";
|
||
|
my $bufsize = shift;
|
||
|
my $key = shift;
|
||
|
my $iv = shift;
|
||
|
|
||
|
# We only invoke the driver with the IV parameter, if we have
|
||
|
# an IV, otherwise, we skip it
|
||
|
$iv = "--iv ".bin2hex($iv) if ($iv);
|
||
|
|
||
|
my $program="fipsdrv --binary --key ".bin2hex($key)." $iv --algo '$cipher' --chunk '$bufsize' $enc";
|
||
|
|
||
|
return $program;
|
||
|
}
|
||
|
|
||
|
sub libgcrypt_state_cipher_des($$$$$) {
|
||
|
my $cipher = shift;
|
||
|
my $enc = (shift) ? "encrypt": "decrypt";
|
||
|
my $bufsize = shift;
|
||
|
my $key = shift;
|
||
|
my $iv = shift;
|
||
|
|
||
|
# We only invoke the driver with the IV parameter, if we have
|
||
|
# an IV, otherwise, we skip it
|
||
|
$iv = "--iv ".bin2hex($iv) if ($iv);
|
||
|
|
||
|
my $program="fipsdrv --algo '$cipher' --mct-server $enc";
|
||
|
|
||
|
return $program;
|
||
|
}
|
||
|
|
||
|
sub libgcrypt_state_rng($$$) {
|
||
|
my $key = shift;
|
||
|
my $dt = shift;
|
||
|
my $v = shift;
|
||
|
|
||
|
return "fipsdrv --binary --loop --key $key --iv $v --dt $dt random";
|
||
|
}
|
||
|
|
||
|
sub libgcrypt_hmac($$$$) {
|
||
|
my $key = shift;
|
||
|
my $maclen = shift;
|
||
|
my $msg = shift;
|
||
|
my $hashtype = shift;
|
||
|
|
||
|
my $program = "fipsdrv --key $key --algo $hashtype hmac-sha";
|
||
|
return pipe_through_program($msg, $program);
|
||
|
}
|
||
|
|
||
|
sub libgcrypt_dsa_pqggen($$$) {
|
||
|
my $mod = shift;
|
||
|
my $qsize = shift;
|
||
|
my $seed = shift;
|
||
|
|
||
|
my $program = "fipsdrv --keysize $mod --qsize $qsize dsa-pqg-gen";
|
||
|
return pipe_through_program($seed, $program);
|
||
|
}
|
||
|
|
||
|
sub libgcrypt_dsa_ggen($$$$) {
|
||
|
my $mod = shift;
|
||
|
my $qsize = shift;
|
||
|
my $p = shift;
|
||
|
my $q = shift;
|
||
|
my $domain = "(domain (p #$p#)(q #$q#))";
|
||
|
|
||
|
my $program = "fipsdrv --keysize $mod --qsize $qsize --key \'$domain\' dsa-g-gen";
|
||
|
return pipe_through_program("", $program);
|
||
|
}
|
||
|
|
||
|
sub libgcrypt_gen_dsakey($$$) {
|
||
|
my $mod = shift;
|
||
|
my $qsize = shift;
|
||
|
my $file = shift;
|
||
|
|
||
|
my $program = "fipsdrv --keysize $mod --qsize $qsize --key $file dsa-gen";
|
||
|
my $tmp;
|
||
|
my %ret;
|
||
|
|
||
|
die "ARCFOUR not available for DSA" if $opt{'R'};
|
||
|
|
||
|
$tmp = pipe_through_program("", $program);
|
||
|
die "dsa key gen failed: file $file not created" if (! -f $file);
|
||
|
|
||
|
@ret{'P', 'Q', 'G'} = split(/\n/, $tmp);
|
||
|
return %ret;
|
||
|
}
|
||
|
|
||
|
sub libgcrypt_gen_dsakey_domain($$$) {
|
||
|
my $p = shift;
|
||
|
my $q = shift;
|
||
|
my $g = shift;
|
||
|
my $domain = "(domain (p #$p#)(q #$q#)(g #$g#))";
|
||
|
|
||
|
my $program = "fipsdrv --key '$domain' dsa-gen-key";
|
||
|
|
||
|
return pipe_through_program("", $program);
|
||
|
}
|
||
|
|
||
|
sub libgcrypt_dsa_genpubkey($$$$$) {
|
||
|
my $filename = shift;
|
||
|
my $p = shift;
|
||
|
my $q = shift;
|
||
|
my $g = shift;
|
||
|
my $y = shift;
|
||
|
|
||
|
my $sexp;
|
||
|
|
||
|
$sexp = "(public-key(dsa(p #$p#)(q #$q#)(g #$g#)(y #$y#)))";
|
||
|
|
||
|
open(FH, ">", $filename) or die;
|
||
|
print FH $sexp;
|
||
|
close FH;
|
||
|
}
|
||
|
|
||
|
sub libgcrypt_dsa_sign($$) {
|
||
|
my $data = shift;
|
||
|
my $keyfile = shift;
|
||
|
my $tmp;
|
||
|
my %ret;
|
||
|
|
||
|
die "ARCFOUR not available for DSA" if $opt{'R'};
|
||
|
|
||
|
$tmp = pipe_through_program($data, "fipsdrv --key $keyfile dsa-sign");
|
||
|
@ret{'Y', 'R', 'S'} = split(/\n/, $tmp);
|
||
|
return %ret;
|
||
|
}
|
||
|
|
||
|
sub libgcrypt_dsa_verify($$$$) {
|
||
|
my $data = shift;
|
||
|
my $keyfile = shift;
|
||
|
my $r = shift;
|
||
|
my $s = shift;
|
||
|
|
||
|
my $ret;
|
||
|
|
||
|
die "ARCFOUR not available for DSA" if $opt{'R'};
|
||
|
|
||
|
my $sigfile = "$keyfile.sig";
|
||
|
open(FH, ">$sigfile") or die "Cannot create file $sigfile: $?";
|
||
|
print FH "(sig-val(dsa(r #$r#)(s #$s#)))";
|
||
|
close FH;
|
||
|
|
||
|
$ret = pipe_through_program($data,
|
||
|
"fipsdrv --key $keyfile --signature $sigfile dsa-verify");
|
||
|
unlink ($sigfile);
|
||
|
# Parse through the output information
|
||
|
return ($ret =~ /GOOD signature/);
|
||
|
}
|
||
|
|
||
|
sub libgcrypt_drbg($$$$$$$$$) {
|
||
|
my $cipher = shift;
|
||
|
my $drbg_expectedlen = shift;
|
||
|
my $drbg_entropy = shift;
|
||
|
my $drbg_nonce = shift;
|
||
|
my $drbg_pers = shift;
|
||
|
my $drbg_addtla = shift;
|
||
|
my $drbg_addtlb = shift;
|
||
|
my $drbg_entpra = shift;
|
||
|
my $drbg_entprb = shift;
|
||
|
my $out = "";
|
||
|
my $parameter = "";
|
||
|
my $flags = 0;
|
||
|
|
||
|
$drbg_expectedlen = $drbg_expectedlen / 8;
|
||
|
|
||
|
if ($cipher =~ /aes128/) {
|
||
|
$flags |= (1 << 0 | 1 << 13);
|
||
|
}
|
||
|
if ($cipher =~ /aes192/) {
|
||
|
$flags |= (1 << 0 | 1 << 14);
|
||
|
}
|
||
|
if ($cipher =~ /aes256/) {
|
||
|
$flags |= (1 << 0 | 1 << 15);
|
||
|
}
|
||
|
if ($cipher =~ /sha1/) {
|
||
|
$flags |= 1 << 4;
|
||
|
}
|
||
|
if ($cipher =~ /sha256/) {
|
||
|
$flags |= 1 << 6;
|
||
|
}
|
||
|
if ($cipher =~ /sha384/) {
|
||
|
$flags |= 1 << 7;
|
||
|
}
|
||
|
if ($cipher =~ /sha512/) {
|
||
|
$flags |= 1 << 8;
|
||
|
}
|
||
|
if ($cipher =~ /hmac/) {
|
||
|
$flags |= 1 << 12;
|
||
|
}
|
||
|
|
||
|
if ($drbg_entpra ne "" && $drbg_entprb ne "") {
|
||
|
$flags |= 1 << 28;
|
||
|
}
|
||
|
|
||
|
$parameter .= " -f $flags";
|
||
|
# test drvier requires concatenated entropy/nonce
|
||
|
$drbg_entropy = $drbg_entropy . $drbg_nonce;
|
||
|
$parameter .= " -e $drbg_entropy";
|
||
|
$parameter .= " -l $drbg_expectedlen";
|
||
|
if ($drbg_pers ne "z") { $parameter .= " -p $drbg_pers"; }
|
||
|
if ($drbg_addtla ne "z") { $parameter .= " -c $drbg_addtla";}
|
||
|
if ($drbg_addtlb ne "z") { $parameter .= " -d $drbg_addtlb";}
|
||
|
if ($drbg_entpra ne "z" && $drbg_entpra ne "") {
|
||
|
$parameter .= " -y $drbg_entpra";
|
||
|
}
|
||
|
if ($drbg_entprb ne "z" && $drbg_entprb ne "") {
|
||
|
$parameter .= " -z $drbg_entprb";
|
||
|
}
|
||
|
|
||
|
$out = pipe_through_program("",
|
||
|
"/usr/lib/libgcrypt/drbg_test $parameter 2>/dev/null");
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
|
||
|
######### End of libgcrypt implementation ################
|
||
|
|
||
|
################################################################
|
||
|
###### Kernel Crypto API interface functions
|
||
|
################################################################
|
||
|
|
||
|
#my $DIR = "/sys/kernel/debug/cryptoapi/";
|
||
|
my $DIR = "/sys/kernel/debug/drbg-cavs/";
|
||
|
my $CIPHER_AES = Math::BigInt->new("0x0000000000000001");
|
||
|
my $CIPHER_TDES = Math::BigInt->new("0x0000000000000002");
|
||
|
|
||
|
my $CIPHER_SHA1 = Math::BigInt->new("0x0000000000010000");
|
||
|
my $CIPHER_SHA224 = Math::BigInt->new("0x0000000000020000");
|
||
|
my $CIPHER_SHA256 = Math::BigInt->new("0x0000000000040000");
|
||
|
my $CIPHER_SHA384 = Math::BigInt->new("0x0000000000100000");
|
||
|
my $CIPHER_SHA512 = Math::BigInt->new("0x0000000000200000");
|
||
|
|
||
|
my $CIPHER_X931RNG = Math::BigInt->new("0x0000000001000000");
|
||
|
|
||
|
my $TYPE_CTR = Math::BigInt->new("0x0010000000000000");
|
||
|
my $TYPE_GENERIC = Math::BigInt->new("0x0020000000000000");
|
||
|
my $TYPE_ASM = Math::BigInt->new("0x0040000000000000");
|
||
|
my $TYPE_CBC = Math::BigInt->new("0x0100000000000000");
|
||
|
my $TYPE_ECB = Math::BigInt->new("0x0200000000000000");
|
||
|
my $TYPE_KEEP = Math::BigInt->new("0x0400000000000000");
|
||
|
my $TYPE_HMAC = Math::BigInt->new("0x1000000000000000");
|
||
|
my $TYPE_ENC = Math::BigInt->new("0x2000000000000000");
|
||
|
my $TYPE_DEC = Math::BigInt->new("0x4000000000000000");
|
||
|
|
||
|
sub writedata($$) {
|
||
|
my $file=shift;
|
||
|
my $data=shift;
|
||
|
$file = $DIR . $file;
|
||
|
open(FH, ">$file") or die "Cannot open file $file";
|
||
|
my $dlen = length($data);
|
||
|
my $len = syswrite(FH, $data, $dlen);
|
||
|
if($len != $dlen) {
|
||
|
die "Cannot write data of length $dlen";
|
||
|
}
|
||
|
close(FH);
|
||
|
}
|
||
|
|
||
|
sub readdata($$) {
|
||
|
my $file=shift;
|
||
|
my $bytes=shift;
|
||
|
my $out;
|
||
|
$file = $DIR . $file;
|
||
|
open(FH, "<$file") or die "Cannot open file $file";
|
||
|
my $len = sysread(FH, $out, $bytes);
|
||
|
if(!defined($len)) {
|
||
|
$out="";
|
||
|
}
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
sub cryptoapi_setupencdec($$$$$) {
|
||
|
my $key=shift;
|
||
|
my $iv=shift;
|
||
|
my $cipher=shift;
|
||
|
my $enc = shift;
|
||
|
my $keep = shift;
|
||
|
|
||
|
# enc / dec yet unhandled - should not matter anyhow
|
||
|
if($cipher eq "des-ede3-cbc") {
|
||
|
$cipher = $CIPHER_TDES|$TYPE_CBC;
|
||
|
} elsif($cipher eq "des-ede3") {
|
||
|
$cipher = $CIPHER_TDES|$TYPE_ECB;
|
||
|
} elsif($cipher =~ /^aes-\d{3}-cbc$/) {
|
||
|
$cipher = $CIPHER_AES|$TYPE_CBC;
|
||
|
} elsif($cipher =~ /^aes-\d{3}-ecb$/) {
|
||
|
$cipher = $CIPHER_AES|$TYPE_ECB;
|
||
|
} else {
|
||
|
die "Unknown cipher $cipher for kernel crypto API";
|
||
|
}
|
||
|
if($enc) {
|
||
|
$cipher = $cipher | $TYPE_ENC;
|
||
|
} else {
|
||
|
$cipher = $cipher | $TYPE_DEC;
|
||
|
}
|
||
|
if($keep) {
|
||
|
$cipher = $cipher | $TYPE_KEEP;
|
||
|
}
|
||
|
|
||
|
# DIFFERENT IMPLEMENTATION enable generic implementation!
|
||
|
# $cipher = $cipher | $TYPE_GENERIC;
|
||
|
|
||
|
# DIFFERENT IMPLEMENTATION enable asm implementation!
|
||
|
# $cipher = $cipher | $TYPE_ASM;
|
||
|
|
||
|
$cipher = $cipher->as_hex;
|
||
|
|
||
|
writedata("cipher", $cipher);
|
||
|
writedata("key", hex2bin($key));
|
||
|
|
||
|
# We only invoke the driver with the IV parameter, if we have
|
||
|
# an IV, otherwise, we skip it
|
||
|
if(defined($iv)) {
|
||
|
writedata("iv", hex2bin($iv));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub cryptoapi_encdec($$$$$) {
|
||
|
my $key=shift;
|
||
|
my $iv=shift;
|
||
|
my $cipher=shift;
|
||
|
my $enc = shift;
|
||
|
my $data = shift;
|
||
|
cryptoapi_setupencdec($key, $iv, $cipher, $enc, 0);
|
||
|
writedata("data", hex2bin($data));
|
||
|
my $out;
|
||
|
$out = readdata("data", 100000);
|
||
|
return bin2hex($out);
|
||
|
}
|
||
|
|
||
|
sub cryptoapi_state_cipher($$$$$) {
|
||
|
my $cipher = shift;
|
||
|
my $enc = shift;
|
||
|
my $bufsize = shift;
|
||
|
my $key = bin2hex(shift);
|
||
|
my $iv = shift;
|
||
|
$iv = bin2hex($iv) if ($iv);
|
||
|
cryptoapi_setupencdec($key, $iv, $cipher, $enc, 1);
|
||
|
my $file = $DIR . "data";
|
||
|
return "statewrapper.pl $file $bufsize";
|
||
|
}
|
||
|
|
||
|
sub cryptoapi_hash($$) {
|
||
|
my $pt = shift;
|
||
|
my $hashalgo = shift;
|
||
|
|
||
|
my $out;
|
||
|
if($hashalgo eq "sha1") {
|
||
|
$hashalgo = $CIPHER_SHA1;
|
||
|
} elsif($hashalgo eq "sha224") {
|
||
|
$hashalgo = $CIPHER_SHA224;
|
||
|
} elsif($hashalgo eq "sha256") {
|
||
|
$hashalgo = $CIPHER_SHA256;
|
||
|
} elsif($hashalgo eq "sha384") {
|
||
|
$hashalgo = $CIPHER_SHA384;
|
||
|
} elsif($hashalgo eq "sha512") {
|
||
|
$hashalgo = $CIPHER_SHA512;
|
||
|
} else {
|
||
|
die "Unknown hashalgo $hashalgo for kernel crypto API";
|
||
|
}
|
||
|
|
||
|
# DIFFERENT IMPLEMENTATION enable generic implementation!
|
||
|
# $hashalgo = $hashalgo | $TYPE_GENERIC;
|
||
|
|
||
|
$hashalgo = $hashalgo->as_hex;
|
||
|
writedata("cipher", $hashalgo);
|
||
|
writedata("data", hex2bin($pt));
|
||
|
|
||
|
die "ARCFOUR not available for hashes" if $opt{'R'};
|
||
|
|
||
|
$out = readdata("data", 100000);
|
||
|
return bin2hex($out);
|
||
|
}
|
||
|
|
||
|
sub cryptoapi_hmac($$$$) {
|
||
|
my $key = shift;
|
||
|
my $maclen = shift;
|
||
|
my $msg = shift;
|
||
|
my $hashtype = shift;
|
||
|
|
||
|
my $out;
|
||
|
if($hashtype eq "1") {
|
||
|
$hashtype = $CIPHER_SHA1 | $TYPE_HMAC;
|
||
|
} elsif($hashtype eq "224") {
|
||
|
$hashtype = $CIPHER_SHA224 | $TYPE_HMAC;
|
||
|
} elsif($hashtype eq "256") {
|
||
|
$hashtype = $CIPHER_SHA256 | $TYPE_HMAC;
|
||
|
} elsif($hashtype eq "384") {
|
||
|
$hashtype = $CIPHER_SHA384 | $TYPE_HMAC;
|
||
|
} elsif($hashtype eq "512") {
|
||
|
$hashtype = $CIPHER_SHA512 | $TYPE_HMAC;
|
||
|
} else {
|
||
|
die "Unknown hashalgo $hashtype for kernel crypto API";
|
||
|
}
|
||
|
|
||
|
# DIFFERENT IMPLEMENTATION enable generic implementation!
|
||
|
# $hashtype = $hashalgo | $TYPE_GENERIC;
|
||
|
|
||
|
$hashtype = $hashtype->as_hex;
|
||
|
writedata("cipher", $hashtype);
|
||
|
writedata("key", hex2bin($key));
|
||
|
writedata("data", hex2bin($msg));
|
||
|
|
||
|
$out = readdata("data", 100000);
|
||
|
return bin2hex($out);
|
||
|
}
|
||
|
|
||
|
sub cryptoapi_state_rng($$$) {
|
||
|
my $key = shift;
|
||
|
my $dt = shift;
|
||
|
my $v = shift;
|
||
|
|
||
|
my $seed = $v . $key . $dt;
|
||
|
$seed=hex2bin($seed);
|
||
|
|
||
|
writedata("cipher", $CIPHER_X931RNG->as_hex);
|
||
|
writedata("key", $seed);
|
||
|
|
||
|
my $file = $DIR . "data";
|
||
|
return "statewrapper.pl $file";
|
||
|
}
|
||
|
|
||
|
sub cryptoapi_drbg($$$$$$$$$) {
|
||
|
my $cipher = shift;
|
||
|
my $drbg_expectedlen = shift;
|
||
|
my $drbg_entropy = shift;
|
||
|
my $drbg_nonce = shift;
|
||
|
my $drbg_pers = shift;
|
||
|
my $drbg_addtla = shift;
|
||
|
my $drbg_addtlb = shift;
|
||
|
my $drbg_entpra = shift;
|
||
|
my $drbg_entprb = shift;
|
||
|
my $out = "";
|
||
|
|
||
|
$drbg_expectedlen = $drbg_expectedlen / 8;
|
||
|
|
||
|
if ($cipher =~ /hash\s+(\w+)/) { $cipher = $1; }
|
||
|
if ($cipher =~ /hmac\s+(\w+)/) { $cipher = "hmac($1)"; }
|
||
|
if ($cipher =~ /ctr\s+(\w+)/) { $cipher = "ctr($1)"; }
|
||
|
|
||
|
if ($drbg_entpra ne "" && $drbg_entprb ne "") {
|
||
|
$cipher = "drbg(pr($cipher))";
|
||
|
} else {
|
||
|
$cipher = "drbg(nopr($cipher))";
|
||
|
}
|
||
|
|
||
|
# test drvier requires concatenated entropy/nonce
|
||
|
$drbg_entropy = $drbg_entropy . $drbg_nonce;
|
||
|
writedata("name", $cipher);
|
||
|
writedata("entropy", hex2bin($drbg_entropy));
|
||
|
if ($drbg_pers ne "z") { writedata("pers", hex2bin($drbg_pers)); }
|
||
|
if ($drbg_addtla ne "z") { writedata("addtla", hex2bin($drbg_addtla));}
|
||
|
if ($drbg_addtlb ne "z") { writedata("addtlb", hex2bin($drbg_addtlb));}
|
||
|
if ($drbg_entpra ne "z" && $drbg_entpra ne "") {
|
||
|
writedata("entpra", hex2bin($drbg_entpra));
|
||
|
}
|
||
|
if ($drbg_entprb ne "z" && $drbg_entprb ne "") {
|
||
|
writedata("entprb", hex2bin($drbg_entprb));
|
||
|
}
|
||
|
$out = readdata("data", $drbg_expectedlen);
|
||
|
$out = bin2hex($out);
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
################################################################
|
||
|
###### Vendor1 interface functions
|
||
|
################################################################
|
||
|
|
||
|
sub vendor1_encdec($$$$$) {
|
||
|
my $key=shift;
|
||
|
my $iv=shift;
|
||
|
my $cipher=shift;
|
||
|
my $enc = (shift) ? "encrypt" : "decrypt";
|
||
|
my $data=shift;
|
||
|
|
||
|
$data=hex2bin($data);
|
||
|
my $program = "./aes $enc $key";
|
||
|
$data=pipe_through_program($data,$program);
|
||
|
return bin2hex($data);
|
||
|
}
|
||
|
|
||
|
sub vendor1_state_cipher($$$$$) {
|
||
|
my $cipher = shift;
|
||
|
my $encdec = shift;
|
||
|
my $bufsize = shift;
|
||
|
my $key = shift;
|
||
|
my $iv = shift;
|
||
|
|
||
|
$key = bin2hex($key);
|
||
|
my $enc = $encdec ? "encrypt": "decrypt";
|
||
|
my $out = "./aes $enc $key $bufsize";
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
##### No other interface functions below this point ######
|
||
|
##########################################################
|
||
|
|
||
|
##########################################################
|
||
|
# General helper routines
|
||
|
|
||
|
# Executing a program by feeding STDIN and retrieving
|
||
|
# STDOUT
|
||
|
# $1: data string to be piped to the app on STDIN
|
||
|
# rest: program and args
|
||
|
# returns: STDOUT of program as string
|
||
|
sub pipe_through_program($@) {
|
||
|
my $in = shift;
|
||
|
my @args = @_;
|
||
|
|
||
|
my ($CO, $CI);
|
||
|
my $pid = open2($CO, $CI, @args);
|
||
|
|
||
|
my $out = "";
|
||
|
my $len = length($in);
|
||
|
my $first = 1;
|
||
|
while (1) {
|
||
|
my $rin = "";
|
||
|
my $win = "";
|
||
|
# Output of prog is FD that we read
|
||
|
vec($rin,fileno($CO),1) = 1;
|
||
|
# Input of prog is FD that we write
|
||
|
# check for $first is needed because we can have NULL input
|
||
|
# that is to be written to the app
|
||
|
if ( $len > 0 || $first) {
|
||
|
(vec($win,fileno($CI),1) = 1);
|
||
|
$first=0;
|
||
|
}
|
||
|
# Let us wait for 100ms
|
||
|
my $nfound = select(my $rout=$rin, my $wout=$win, undef, 0.1);
|
||
|
if ( $wout ) {
|
||
|
my $written = syswrite($CI, $in, $len);
|
||
|
die "broken pipe" if !defined $written;
|
||
|
$len -= $written;
|
||
|
substr($in, 0, $written) = "";
|
||
|
if ($len <= 0) {
|
||
|
close $CI or die "broken pipe: $!";
|
||
|
}
|
||
|
}
|
||
|
if ( $rout ) {
|
||
|
my $tmp_out = "";
|
||
|
my $bytes_read = sysread($CO, $tmp_out, 4096);
|
||
|
$out .= $tmp_out;
|
||
|
last if ($bytes_read == 0);
|
||
|
}
|
||
|
}
|
||
|
close $CO or die "broken pipe: $!";
|
||
|
waitpid $pid, 0;
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# convert ASCII hex to binary input
|
||
|
# $1 ASCII hex
|
||
|
# return binary representation
|
||
|
sub hex2bin($) {
|
||
|
my $in = shift;
|
||
|
my $len = length($in);
|
||
|
$len = 0 if ($in eq "00");
|
||
|
return pack("H$len", "$in");
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# convert binary input to ASCII hex
|
||
|
# $1 binary value
|
||
|
# return ASCII hex representation
|
||
|
sub bin2hex($) {
|
||
|
my $in = shift;
|
||
|
my $len = length($in)*2;
|
||
|
return unpack("H$len", "$in");
|
||
|
}
|
||
|
|
||
|
# $1: binary byte (character)
|
||
|
# returns: binary byte with odd parity using low bit as parity bit
|
||
|
sub odd_par($) {
|
||
|
my $in = ord(shift);
|
||
|
my $odd_count=0;
|
||
|
for(my $i=1; $i<8; $i++) {
|
||
|
$odd_count++ if ($in & (1<<$i));
|
||
|
}
|
||
|
|
||
|
my $out = $in;
|
||
|
if ($odd_count & 1) { # check if parity is already odd
|
||
|
$out &= ~1; # clear the low bit
|
||
|
} else {
|
||
|
$out |= 1; # set the low bit
|
||
|
}
|
||
|
|
||
|
return chr($out);
|
||
|
}
|
||
|
|
||
|
# DES keys uses only the 7 high bits of a byte, the 8th low bit
|
||
|
# is the parity bit
|
||
|
# as the new key is calculated from oldkey XOR cipher in the MCT test,
|
||
|
# the parity is not really checked and needs to be set to match
|
||
|
# expectation (OpenSSL does not really care, but the FIPS
|
||
|
# test result is expected that the key has the appropriate parity)
|
||
|
# $1: arbitrary binary string
|
||
|
# returns: string with odd parity set in low bit of each byte
|
||
|
sub fix_key_parity($) {
|
||
|
my $in = shift;
|
||
|
my $out = "";
|
||
|
for (my $i = 0; $i < length($in); $i++) {
|
||
|
$out .= odd_par(substr($in, $i, 1));
|
||
|
}
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
####################################################
|
||
|
# DER/PEM utility functions
|
||
|
# Cf. http://www.columbia.edu/~ariel/ssleay/layman.html
|
||
|
|
||
|
# Convert unsigned integer to base256 bigint bytes
|
||
|
# $1 integer
|
||
|
# returns base256 octet string
|
||
|
sub int_base256_unsigned($) {
|
||
|
my $n = shift;
|
||
|
|
||
|
my $out = chr($n & 255);
|
||
|
while ($n>>=8) {
|
||
|
$out = chr($n & 255) . $out;
|
||
|
}
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
# Convert signed integer to base256 bigint bytes
|
||
|
# $1 integer
|
||
|
# returns base256 octet string
|
||
|
sub int_base256_signed($) {
|
||
|
my $n = shift;
|
||
|
my $negative = ($n < 0);
|
||
|
|
||
|
if ($negative) {
|
||
|
$n = -$n-1;
|
||
|
}
|
||
|
|
||
|
my $out = int_base256_unsigned($n);
|
||
|
|
||
|
if (ord(substr($out, 0, 1)) & 128) {
|
||
|
# it's supposed to be positive but has sign bit set,
|
||
|
# add a leading zero
|
||
|
$out = chr(0) . $out;
|
||
|
}
|
||
|
|
||
|
if ($negative) {
|
||
|
my $neg = chr(255) x length($out);
|
||
|
$out ^= $neg;
|
||
|
}
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
# Length header for specified DER object length
|
||
|
# $1 length as integer
|
||
|
# return octet encoding for length
|
||
|
sub der_len($) {
|
||
|
my $len = shift;
|
||
|
|
||
|
if ($len <= 127) {
|
||
|
return chr($len);
|
||
|
} else {
|
||
|
my $blen = int_base256_unsigned($len);
|
||
|
|
||
|
return chr(128 | length($blen)) . $blen;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# Prepend length header to object
|
||
|
# $1 object as octet sequence
|
||
|
# return length header for object followed by object as octets
|
||
|
sub der_len_obj($) {
|
||
|
my $x = shift;
|
||
|
|
||
|
return der_len(length($x)) . $x;
|
||
|
}
|
||
|
|
||
|
# DER sequence
|
||
|
# $* objects
|
||
|
# returns DER sequence consisting of the objects passed as arguments
|
||
|
sub der_seq {
|
||
|
my $seq = join("", @_);
|
||
|
return chr(0x30) . der_len_obj($seq);
|
||
|
}
|
||
|
|
||
|
# DER bitstring
|
||
|
# $1 input octets (must be full octets, fractional octets not supported)
|
||
|
# returns input encapsulated as bitstring
|
||
|
sub der_bitstring($) {
|
||
|
my $x = shift;
|
||
|
|
||
|
$x = chr(0) . $x;
|
||
|
|
||
|
return chr(0x03) . der_len_obj($x);
|
||
|
}
|
||
|
|
||
|
# base-128-encoded integer, used for object numbers.
|
||
|
# $1 integer
|
||
|
# returns octet sequence
|
||
|
sub der_base128($) {
|
||
|
my $n = shift;
|
||
|
|
||
|
my $out = chr($n & 127);
|
||
|
|
||
|
while ($n>>=7) {
|
||
|
$out = chr(128 | ($n & 127)) . $out;
|
||
|
}
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
# Generating the PEM certificate string
|
||
|
# (base-64-encoded DER string)
|
||
|
# $1 DER string
|
||
|
# returns octet sequence
|
||
|
sub pem_cert($) {
|
||
|
my $n = shift;
|
||
|
|
||
|
my $out = "-----BEGIN PUBLIC KEY-----\n";
|
||
|
$out .= encode_base64($n);
|
||
|
$out .= "-----END PUBLIC KEY-----\n";
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
# DER object identifier
|
||
|
# $* sequence of id numbers
|
||
|
# returns octets
|
||
|
sub der_objectid {
|
||
|
my $v1 = shift;
|
||
|
my $v2 = shift;
|
||
|
|
||
|
my $out = chr(40*$v1 + $v2) . join("", map { der_base128($_) } @_);
|
||
|
|
||
|
return chr(0x06) . der_len_obj($out);
|
||
|
}
|
||
|
|
||
|
# DER signed integer
|
||
|
# $1 number as octet string (base 256 representation, high byte first)
|
||
|
# returns number in DER integer encoding
|
||
|
sub der_bigint($) {
|
||
|
my $x = shift;
|
||
|
|
||
|
return chr(0x02) . der_len_obj($x);
|
||
|
}
|
||
|
|
||
|
# DER positive integer with leading zeroes stripped
|
||
|
# $1 number as octet string (base 256 representation, high byte first)
|
||
|
# returns number in DER integer encoding
|
||
|
sub der_pos_bigint($) {
|
||
|
my $x = shift;
|
||
|
|
||
|
# strip leading zero digits
|
||
|
$x =~ s/^[\0]+//;
|
||
|
|
||
|
# need to prepend a zero if high bit set, since it would otherwise be
|
||
|
# interpreted as a negative number. Also needed for number 0.
|
||
|
if (!length($x) || ord(substr($x, 0, 1)) >= 128) {
|
||
|
$x = chr(0) . $x;
|
||
|
}
|
||
|
|
||
|
return der_bigint($x);
|
||
|
}
|
||
|
|
||
|
# $1 number as signed integer
|
||
|
# returns number as signed DER integer encoding
|
||
|
sub der_int($) {
|
||
|
my $n = shift;
|
||
|
|
||
|
return der_bigint(int_base256_signed($n));
|
||
|
}
|
||
|
|
||
|
# the NULL object constant
|
||
|
sub der_null() {
|
||
|
return chr(0x05) . chr(0x00);
|
||
|
}
|
||
|
|
||
|
# Unit test helper
|
||
|
# $1 calculated result
|
||
|
# $2 expected result
|
||
|
# no return value, dies if results differ, showing caller's line number
|
||
|
sub der_test($$) {
|
||
|
my $actual = bin2hex(shift);
|
||
|
my $expected = shift;
|
||
|
|
||
|
my @caller = caller;
|
||
|
$actual eq $expected or die "Error:line $caller[2]:assertion failed: "
|
||
|
."$actual != $expected\n";
|
||
|
}
|
||
|
|
||
|
# Unit testing for the DER encoding functions
|
||
|
# Examples from http://www.columbia.edu/~ariel/ssleay/layman.html
|
||
|
# No input, no output. Dies if unit tests fail.
|
||
|
sub der_unit_test {
|
||
|
## uncomment these if you want to test the test framework
|
||
|
#print STDERR "Unit test running\n";
|
||
|
#der_test chr(0), "42";
|
||
|
|
||
|
der_test der_null, "0500";
|
||
|
|
||
|
# length bytes
|
||
|
der_test der_len(1), "01";
|
||
|
der_test der_len(127), "7f";
|
||
|
der_test der_len(128), "8180";
|
||
|
der_test der_len(256), "820100";
|
||
|
der_test der_len(65536), "83010000";
|
||
|
|
||
|
# bigint
|
||
|
der_test der_bigint(chr(0)), "020100";
|
||
|
der_test der_bigint(chr(128)), "020180"; # -128
|
||
|
der_test der_pos_bigint(chr(128)), "02020080"; # +128
|
||
|
der_test der_pos_bigint(chr(0).chr(0).chr(1)), "020101";
|
||
|
der_test der_pos_bigint(chr(0)), "020100";
|
||
|
|
||
|
# integers (tests base256 conversion)
|
||
|
der_test der_int( 0), "020100";
|
||
|
der_test der_int( 127), "02017f";
|
||
|
der_test der_int( 128), "02020080";
|
||
|
der_test der_int( 256), "02020100";
|
||
|
der_test der_int( -1), "0201ff";
|
||
|
der_test der_int( -128), "020180";
|
||
|
der_test der_int( -129), "0202ff7f";
|
||
|
der_test der_int(-65536), "0203ff0000";
|
||
|
der_test der_int(-65537), "0203feffff";
|
||
|
|
||
|
# object encoding, "RSA Security"
|
||
|
der_test der_base128(840), "8648";
|
||
|
der_test der_objectid(1, 2, 840, 113549), "06062a864886f70d";
|
||
|
|
||
|
# Combinations
|
||
|
der_test der_bitstring("ABCD"), "03050041424344";
|
||
|
der_test der_bitstring(der_null), "0303000500";
|
||
|
der_test der_seq(der_int(0), der_null), "30050201000500";
|
||
|
|
||
|
# The big picture
|
||
|
der_test der_seq(der_seq(der_objectid(1, 2, 840, 113549), der_null),
|
||
|
der_bitstring(der_seq(der_pos_bigint(chr(5)),
|
||
|
der_pos_bigint(chr(3))))),
|
||
|
"3017300a06062a864886f70d05000309003006020105020103";
|
||
|
}
|
||
|
|
||
|
####################################################
|
||
|
# OpenSSL missing functionality workarounds
|
||
|
|
||
|
## Format of an RSA public key:
|
||
|
# 0:d=0 hl=3 l= 159 cons: SEQUENCE
|
||
|
# 3:d=1 hl=2 l= 13 cons: SEQUENCE
|
||
|
# 5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
|
||
|
# 16:d=2 hl=2 l= 0 prim: NULL
|
||
|
# 18:d=1 hl=3 l= 141 prim: BIT STRING
|
||
|
# [ sequence: INTEGER (n), INTEGER (e) ]
|
||
|
|
||
|
# generate RSA pub key in PEM format
|
||
|
# $1: filename where PEM key is to be stored
|
||
|
# $2: n of the RSA key in hex
|
||
|
# $3: e of the RSA key in hex
|
||
|
# return: nothing, but file created
|
||
|
sub gen_pubrsakey($$$) {
|
||
|
my $filename=shift;
|
||
|
my $n = shift;
|
||
|
my $e = shift;
|
||
|
|
||
|
# make sure the DER encoder works ;-)
|
||
|
der_unit_test();
|
||
|
|
||
|
# generate DER encoding of the public key
|
||
|
|
||
|
my $rsaEncryption = der_objectid(1, 2, 840, 113549, 1, 1, 1);
|
||
|
|
||
|
my $der = der_seq(der_seq($rsaEncryption, der_null),
|
||
|
der_bitstring(der_seq(der_pos_bigint(hex2bin($n)),
|
||
|
der_pos_bigint(hex2bin($e)))));
|
||
|
|
||
|
open(FH, ">", $filename) or die;
|
||
|
print FH pem_cert($der);
|
||
|
close FH;
|
||
|
|
||
|
}
|
||
|
|
||
|
# generate RSA pub key in PEM format
|
||
|
#
|
||
|
# This implementation uses "openssl asn1parse -genconf" which was added
|
||
|
# in openssl 0.9.8. It is not available in older openssl versions.
|
||
|
#
|
||
|
# $1: filename where PEM key is to be stored
|
||
|
# $2: n of the RSA key in hex
|
||
|
# $3: e of the RSA key in hex
|
||
|
# return: nothing, but file created
|
||
|
sub gen_pubrsakey_using_openssl($$$) {
|
||
|
my $filename=shift;
|
||
|
my $n = shift;
|
||
|
my $e = shift;
|
||
|
|
||
|
my $asn1 = "asn1=SEQUENCE:pubkeyinfo
|
||
|
|
||
|
[pubkeyinfo]
|
||
|
algorithm=SEQUENCE:rsa_alg
|
||
|
pubkey=BITWRAP,SEQUENCE:rsapubkey
|
||
|
|
||
|
[rsa_alg]
|
||
|
algorithm=OID:rsaEncryption
|
||
|
parameter=NULL
|
||
|
|
||
|
[rsapubkey]
|
||
|
n=INTEGER:0x$n
|
||
|
|
||
|
e=INTEGER:0x$e";
|
||
|
|
||
|
open(FH, ">$filename.cnf") or die "Cannot create file $filename.cnf: $?";
|
||
|
print FH $asn1;
|
||
|
close FH;
|
||
|
my @args = ("openssl", "asn1parse", "-genconf", "$filename.cnf", "-noout", "-out", "$filename.der");
|
||
|
system(@args) == 0 or die "system @args failed: $?";
|
||
|
@args = ("openssl", "rsa", "-inform", "DER", "-in", "$filename.der",
|
||
|
"-outform", "PEM", "-pubin", "-pubout", "-out", "$filename");
|
||
|
system(@args) == 0 or die "system @args failed: $?";
|
||
|
die "RSA PEM formatted key file $filename was not created"
|
||
|
if (! -f $filename);
|
||
|
|
||
|
unlink("$filename.cnf");
|
||
|
unlink("$filename.der");
|
||
|
}
|
||
|
|
||
|
############################################
|
||
|
# Test cases
|
||
|
|
||
|
# This is the Known Answer Test
|
||
|
# $1: the string that we have to put in front of the key
|
||
|
# when printing the key
|
||
|
# $2: crypto key1 in hex form
|
||
|
# $3: crypto key2 in hex form (TDES, undef otherwise)
|
||
|
# $4: crypto key3 in hex form (TDES, undef otherwise)
|
||
|
# $5: IV in hex form
|
||
|
# $6: Plaintext (enc=1) or Ciphertext (enc=0) in hex form
|
||
|
# $7: cipher
|
||
|
# $8: encrypt=1/decrypt=0
|
||
|
# return: string formatted as expected by CAVS
|
||
|
sub kat($$$$$$$$) {
|
||
|
my $keytype = shift;
|
||
|
my $key1 = shift;
|
||
|
my $key2 = shift;
|
||
|
my $key3 = shift;
|
||
|
my $iv = shift;
|
||
|
my $pt = shift;
|
||
|
my $cipher = shift;
|
||
|
my $enc = shift;
|
||
|
|
||
|
my $out = "";
|
||
|
|
||
|
$out .= "$keytype = $key1\n";
|
||
|
|
||
|
# this is the concardination of the keys for 3DES
|
||
|
if (defined($key2)) {
|
||
|
$out .= "KEY2 = $key2\n";
|
||
|
$key1 = $key1 . $key2;
|
||
|
}
|
||
|
if (defined($key3)) {
|
||
|
$out .= "KEY3 = $key3\n";
|
||
|
$key1= $key1 . $key3;
|
||
|
}
|
||
|
|
||
|
$out .= "IV = $iv\n" if (defined($iv) && $iv ne "");
|
||
|
if ($enc) {
|
||
|
$out .= "PLAINTEXT = $pt\n";
|
||
|
$out .= "CIPHERTEXT = " . &$encdec($key1, $iv, $cipher, 1, $pt) . "\n";
|
||
|
} else {
|
||
|
$out .= "CIPHERTEXT = $pt\n";
|
||
|
$out .= "PLAINTEXT = " . &$encdec($key1, $iv, $cipher, 0, $pt) . "\n";
|
||
|
}
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
# This is the Known Answer Test for Hashes
|
||
|
# $1: Plaintext in hex form
|
||
|
# $2: hash
|
||
|
# $3: hash length (undef if not applicable)
|
||
|
# return: string formatted as expected by CAVS
|
||
|
sub hash_kat($$$) {
|
||
|
my $pt = shift;
|
||
|
my $cipher = shift;
|
||
|
my $len = shift;
|
||
|
|
||
|
my $out = "";
|
||
|
$out .= "Len = $len\n" if (defined($len));
|
||
|
$out .= "Msg = $pt\n";
|
||
|
|
||
|
$pt = "" if(!$len);
|
||
|
$out .= "MD = " . &$hash($pt, $cipher) . "\n";
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
# Known Answer Test for HMAC hash
|
||
|
# $1: key length in bytes
|
||
|
# $2: MAC length in bytes
|
||
|
# $3: key for HMAC in hex form
|
||
|
# $4: message to be hashed
|
||
|
# return: string formatted as expected by CAVS
|
||
|
sub hmac_kat($$$$) {
|
||
|
my $klen = shift;
|
||
|
my $tlen = shift;
|
||
|
my $key = shift;
|
||
|
my $msg = shift;
|
||
|
|
||
|
# XXX this is a hack - we need to decipher the HMAC REQ files in a more
|
||
|
# sane way
|
||
|
#
|
||
|
# This is a conversion table from the expected hash output size
|
||
|
# to the assumed hash type - we only define here the block size of
|
||
|
# the underlying hashes and do not allow any truncation
|
||
|
my %hashtype = (
|
||
|
20 => 1,
|
||
|
28 => 224,
|
||
|
32 => 256,
|
||
|
48 => 384,
|
||
|
64 => 512
|
||
|
);
|
||
|
|
||
|
die "Hash output size $tlen is not supported!"
|
||
|
if(!defined($hashtype{$tlen}));
|
||
|
|
||
|
my $out = "";
|
||
|
$out .= "Klen = $klen\n";
|
||
|
$out .= "Tlen = $tlen\n";
|
||
|
$out .= "Key = $key\n";
|
||
|
$out .= "Msg = $msg\n";
|
||
|
$out .= "Mac = " . lc(&$hmac($key, $tlen, $msg, $hashtype{$tlen})) . "\n";
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
|
||
|
# Cipher Monte Carlo Testing
|
||
|
# $1: the string that we have to put in front of the key
|
||
|
# when printing the key
|
||
|
# $2: crypto key1 in hex form
|
||
|
# $3: crypto key2 in hex form (TDES, undef otherwise)
|
||
|
# $4: crypto key3 in hex form (TDES, undef otherwise)
|
||
|
# $5: IV in hex form
|
||
|
# $6: Plaintext (enc=1) or Ciphertext (enc=0) in hex form
|
||
|
# $7: cipher
|
||
|
# $8: encrypt=1/decrypt=0
|
||
|
# return: string formatted as expected by CAVS
|
||
|
sub crypto_mct($$$$$$$$) {
|
||
|
my $keytype = shift;
|
||
|
my $key1 = hex2bin(shift);
|
||
|
my $key2 = shift;
|
||
|
my $key3 = shift;
|
||
|
my $iv = hex2bin(shift);
|
||
|
my $source_data = hex2bin(shift);
|
||
|
my $cipher = shift;
|
||
|
my $enc = shift;
|
||
|
|
||
|
my $out = "";
|
||
|
|
||
|
$key2 = hex2bin($key2) if (defined($key2));
|
||
|
$key3 = hex2bin($key3) if (defined($key3));
|
||
|
my $bufsize = length($source_data);
|
||
|
|
||
|
# for AES: outer loop 0-99, inner 0-999 based on FIPS compliance tests
|
||
|
# for RC4: outer loop 0-99, inner 0-999 based on atsec compliance tests
|
||
|
# for DES: outer loop 0-399, inner 0-9999 based on FIPS compliance tests
|
||
|
my $ciph = substr($cipher,0,3);
|
||
|
my $oloop=100;
|
||
|
my $iloop=1000;
|
||
|
if ($ciph =~ /des/) {$oloop=400;$iloop=10000;}
|
||
|
|
||
|
for (my $i=0; $i<$oloop; ++$i) {
|
||
|
$out .= "COUNT = $i\n";
|
||
|
if (defined($key2)) {
|
||
|
$out .= "$keytype = ". bin2hex($key1). "\n";
|
||
|
$out .= "KEY2 = ". bin2hex($key2). "\n";
|
||
|
$key1 = $key1 . $key2;
|
||
|
} else {
|
||
|
$out .= "$keytype = ". bin2hex($key1). "\n";
|
||
|
}
|
||
|
if(defined($key3)) {
|
||
|
$out .= "KEY3 = ". bin2hex($key3). "\n";
|
||
|
$key1 = $key1 . $key3;
|
||
|
}
|
||
|
my $keylen = length($key1);
|
||
|
|
||
|
$out .= "IV = ". bin2hex($iv) . "\n"
|
||
|
if (defined($iv) && $iv ne "");
|
||
|
|
||
|
if ($enc) {
|
||
|
$out .= "PLAINTEXT = ". bin2hex($source_data). "\n";
|
||
|
} else {
|
||
|
$out .= "CIPHERTEXT = ". bin2hex($source_data). "\n";
|
||
|
}
|
||
|
my ($CO, $CI);
|
||
|
my $cipher_imp = &$state_cipher($cipher, $enc, $bufsize, $key1, $iv);
|
||
|
$cipher_imp = &$state_cipher_des($cipher, $enc, $bufsize, $key1, $iv) if($cipher =~ /des/ && defined($state_cipher_des));
|
||
|
my $pid = open2($CO, $CI, $cipher_imp);
|
||
|
|
||
|
my $calc_data = $iv; # CT[j]
|
||
|
my $old_calc_data; # CT[j-1]
|
||
|
my $old_old_calc_data; # CT[j-2]
|
||
|
my $next_source;
|
||
|
|
||
|
# TDES inner loop implements logic within driver of libgcrypt
|
||
|
if ($cipher =~ /des/ && $opt{'I'} && $opt{'I'} eq 'libgcrypt' ) {
|
||
|
# Need to provide a dummy IV in case of ECB mode.
|
||
|
my $iv_arg = (defined($iv) && $iv ne "")
|
||
|
? bin2hex($iv)
|
||
|
: "00"x(length($source_data));
|
||
|
print $CI "1\n"
|
||
|
.$iloop."\n"
|
||
|
.bin2hex($key1)."\n"
|
||
|
.$iv_arg."\n"
|
||
|
.bin2hex($source_data)."\n\n" or die;
|
||
|
chomp(my $line = <$CO>);
|
||
|
$calc_data = hex2bin($line);
|
||
|
chomp($line = <$CO>);
|
||
|
$old_calc_data = hex2bin($line);
|
||
|
chomp($line = <$CO>);
|
||
|
$old_old_calc_data = hex2bin($line);
|
||
|
chomp($line = <$CO>);
|
||
|
$iv = hex2bin($line) if (defined($iv) && $iv ne "");
|
||
|
chomp($line = <$CO>);
|
||
|
$next_source = hex2bin($line);
|
||
|
# Skip over empty line.
|
||
|
$line = <$CO>;
|
||
|
} else {
|
||
|
for (my $j = 0; $j < $iloop; ++$j) {
|
||
|
if ($cipher =~ /des-ede3-ofb/ ||
|
||
|
(!$enc && $cipher =~ /des-ede3-cfb/)) {
|
||
|
die "Implementation lacks support for TDES OFB and TDES CFB in encryption mode - the problem is that we would need to extract the IV of the last round of encryption which would be the input for the next round - see comments in this script for implementation requirements";
|
||
|
}
|
||
|
$old_old_calc_data = $old_calc_data;
|
||
|
$old_calc_data = $calc_data;
|
||
|
|
||
|
#print STDERR "source_data=", bin2hex($source_data), "\n";
|
||
|
syswrite $CI, $source_data or die $!;
|
||
|
my $len = sysread $CO, $calc_data, $bufsize;
|
||
|
#my $a = bin2hex($source_data);
|
||
|
#my $b = bin2hex($calc_data);
|
||
|
#warn "$a $b";
|
||
|
#sleep 1;
|
||
|
|
||
|
#print STDERR "len=$len, bufsize=$bufsize\n";
|
||
|
die if $len ne $bufsize;
|
||
|
#print STDERR "calc_data=", bin2hex($calc_data), "\n";
|
||
|
|
||
|
if ( (!$enc && $ciph =~ /des/) ||
|
||
|
$ciph =~ /rc4/ ||
|
||
|
$cipher =~ /ecb/ ) {
|
||
|
#TDES in decryption mode, RC4 and ECB mode
|
||
|
#have a special rule
|
||
|
$source_data = $calc_data;
|
||
|
} else {
|
||
|
$source_data = $old_calc_data;
|
||
|
}
|
||
|
#my $c = bin2hex($source_data);
|
||
|
#my $d = bin2hex($calc_data);
|
||
|
#warn "$c $d";
|
||
|
}
|
||
|
}
|
||
|
close $CO;
|
||
|
close $CI;
|
||
|
waitpid $pid, 0;
|
||
|
|
||
|
if ($enc) {
|
||
|
$out .= "CIPHERTEXT = ". bin2hex($calc_data). "\n\n";
|
||
|
} else {
|
||
|
$out .= "PLAINTEXT = ". bin2hex($calc_data). "\n\n";
|
||
|
}
|
||
|
|
||
|
if ( $ciph =~ /aes/ ) {
|
||
|
$key1 ^= substr($old_calc_data . $calc_data, -$keylen);
|
||
|
#print STDERR bin2hex($key1)."\n";
|
||
|
} elsif ( $ciph =~ /des/ ) {
|
||
|
die "Wrong keylen $keylen" if ($keylen != 24);
|
||
|
|
||
|
# $nkey needed as $key holds the concatenation of the
|
||
|
# old key atm
|
||
|
my $nkey = fix_key_parity(substr($key1,0,8) ^ $calc_data);
|
||
|
#print STDERR "KEY1 = ". bin2hex($nkey)."\n";
|
||
|
if (substr($key1,0,8) ne substr($key1,8,8)) {
|
||
|
#print STDERR "KEY2 recalc: KEY1==KEY3, KEY2 indep. or all KEYs are indep.\n";
|
||
|
$key2 = fix_key_parity((substr($key1,8,8) ^ $old_calc_data));
|
||
|
} else {
|
||
|
#print STDERR "KEY2 recalc: KEY1==KEY2==KEY3\n";
|
||
|
$key2 = fix_key_parity((substr($key1,8,8) ^ $calc_data));
|
||
|
}
|
||
|
#print STDERR "KEY2 = ". bin2hex($key2)."\n";
|
||
|
if ( substr($key1,0,8) eq substr($key1,16)) {
|
||
|
#print STDERR "KEY3 recalc: KEY1==KEY2==KEY3 or KEY1==KEY3, KEY2 indep.\n";
|
||
|
$key3 = fix_key_parity((substr($key1,16) ^ $calc_data));
|
||
|
} else {
|
||
|
#print STDERR "KEY3 recalc: all KEYs are independent\n";
|
||
|
$key3 = fix_key_parity((substr($key1,16) ^ $old_old_calc_data));
|
||
|
}
|
||
|
#print STDERR "KEY3 = ". bin2hex($key3)."\n";
|
||
|
|
||
|
# reset the first key - concardination happens at
|
||
|
# beginning of loop
|
||
|
$key1=$nkey;
|
||
|
} elsif ($ciph =~ /rc4/ ) {
|
||
|
$key1 ^= substr($calc_data, 0, 16);
|
||
|
#print STDERR bin2hex($key1)."\n";
|
||
|
} else {
|
||
|
die "Test limitation: cipher '$cipher' not supported in Monte Carlo testing";
|
||
|
}
|
||
|
|
||
|
if ($cipher =~ /des-ede3-ofb/) {
|
||
|
$source_data = $source_data ^ $next_source;
|
||
|
} elsif (!$enc && $cipher =~ /des-ede3-cfb/) {
|
||
|
#TDES decryption CFB has a special rule
|
||
|
$source_data = $next_source;
|
||
|
} elsif ( $ciph =~ /rc4/ || $cipher eq "des-ede3" || $cipher =~ /ecb/) {
|
||
|
#No resetting of IV as the IV is all zero set initially (i.e. no IV)
|
||
|
$source_data = $calc_data;
|
||
|
} elsif (! $enc && $ciph =~ /des/ ) {
|
||
|
#TDES in decryption mode has a special rule
|
||
|
$iv = $old_calc_data;
|
||
|
$source_data = $calc_data;
|
||
|
} else {
|
||
|
$iv = $calc_data;
|
||
|
$source_data = $old_calc_data;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
# Hash Monte Carlo Testing
|
||
|
# $1: Plaintext in hex form
|
||
|
# $2: hash
|
||
|
# return: string formatted as expected by CAVS
|
||
|
sub hash_mct($$) {
|
||
|
my $pt = shift;
|
||
|
my $cipher = shift;
|
||
|
|
||
|
my $out = "";
|
||
|
|
||
|
$out .= "Seed = $pt\n\n";
|
||
|
|
||
|
for (my $j=0; $j<100; ++$j) {
|
||
|
$out .= "COUNT = $j\n";
|
||
|
my $md0=$pt;
|
||
|
my $md1=$pt;
|
||
|
my $md2=$pt;
|
||
|
for (my $i=0; $i<1000; ++$i) {
|
||
|
#print STDERR "outer loop $j; inner loop $i\n";
|
||
|
my $mi= $md0 . $md1 . $md2;
|
||
|
$md0=$md1;
|
||
|
$md1=$md2;
|
||
|
$md2 = &$hash($mi, $cipher);
|
||
|
$md2 =~ s/\n//;
|
||
|
}
|
||
|
$out .= "MD = $md2\n\n";
|
||
|
$pt=$md2;
|
||
|
}
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
# RSA SigGen test
|
||
|
# $1: Message to be signed in hex form
|
||
|
# $2: Hash algorithm
|
||
|
# $3: file name with RSA key in PEM form
|
||
|
# return: string formatted as expected by CAVS
|
||
|
sub rsa_siggen($$$) {
|
||
|
my $data = shift;
|
||
|
my $cipher = shift;
|
||
|
my $keyfile = shift;
|
||
|
|
||
|
my $out = "";
|
||
|
|
||
|
$out .= "SHAAlg = $cipher\n";
|
||
|
$out .= "Msg = $data\n";
|
||
|
$out .= "S = " . &$rsa_sign($data, lc($cipher), $keyfile) . "\n";
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
# RSA SigVer test
|
||
|
# $1: Message to be verified in hex form
|
||
|
# $2: Hash algoritm
|
||
|
# $3: Signature of message in hex form
|
||
|
# $4: n of the RSA key in hex in hex form
|
||
|
# $5: e of the RSA key in hex in hex form
|
||
|
# return: string formatted as expected by CAVS
|
||
|
sub rsa_sigver($$$$$) {
|
||
|
my $data = shift;
|
||
|
my $cipher = shift;
|
||
|
my $signature = shift;
|
||
|
my $n = shift;
|
||
|
my $e = shift;
|
||
|
|
||
|
my $out = "";
|
||
|
|
||
|
$out .= "SHAAlg = $cipher\n";
|
||
|
$out .= "e = $e\n";
|
||
|
$out .= "Msg = $data\n";
|
||
|
$out .= "S = $signature\n";
|
||
|
|
||
|
# XXX maybe a secure temp file name is better here
|
||
|
# but since it is not run on a security sensitive
|
||
|
# system, I hope that this is fine
|
||
|
my $keyfile = "rsa_sigver.tmp.$$";
|
||
|
gen_pubrsakey($keyfile, $n, $e);
|
||
|
|
||
|
my $sigfile = "$keyfile.sig";
|
||
|
open(FH, ">$sigfile") or die "Cannot create file $sigfile: $?";
|
||
|
print FH hex2bin($signature);
|
||
|
close FH;
|
||
|
|
||
|
$out .= "Result = " . (&$rsa_verify($data, lc($cipher), $keyfile, $sigfile) ? "P\n" : "F\n");
|
||
|
|
||
|
unlink($keyfile);
|
||
|
unlink($sigfile);
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
# RSA X9.31 key generation test
|
||
|
# $1 modulus size
|
||
|
# $2 e
|
||
|
# $3 xp1
|
||
|
# $4 xp2
|
||
|
# $5 Xp
|
||
|
# $6 xq1
|
||
|
# $7 xq2
|
||
|
# $8 Xq
|
||
|
# return: string formatted as expected by CAVS
|
||
|
sub rsa_keygen($$$$$$$$) {
|
||
|
my $modulus = shift;
|
||
|
my $e = shift;
|
||
|
my $xp1 = shift;
|
||
|
my $xp2 = shift;
|
||
|
my $Xp = shift;
|
||
|
my $xq1 = shift;
|
||
|
my $xq2 = shift;
|
||
|
my $Xq = shift;
|
||
|
|
||
|
my $out = "";
|
||
|
|
||
|
my $ret = &$rsa_derive($modulus, $e, $xp1, $xp2, $Xp, $xq1, $xq2, $Xq);
|
||
|
|
||
|
my ($P, $Q, $N, $D) = split(/\n/, $ret);
|
||
|
|
||
|
$out .= "e = $e\n";
|
||
|
$out .= "xp1 = $xp1\n";
|
||
|
$out .= "xp2 = $xp2\n";
|
||
|
$out .= "Xp = $Xp\n";
|
||
|
$out .= "p = $P\n";
|
||
|
$out .= "xq1 = $xq1\n";
|
||
|
$out .= "xq2 = $xq2\n";
|
||
|
$out .= "Xq = $Xq\n";
|
||
|
$out .= "q = $Q\n";
|
||
|
$out .= "n = $N\n";
|
||
|
$out .= "d = $D\n\n";
|
||
|
|
||
|
return $out;
|
||
|
|
||
|
}
|
||
|
|
||
|
# X9.31 RNG test
|
||
|
# $1 key for the AES cipher
|
||
|
# $2 DT value
|
||
|
# $3 V value
|
||
|
# $4 type ("VST", "MCT")
|
||
|
# return: string formatted as expected by CAVS
|
||
|
sub rngx931($$$$) {
|
||
|
my $key=shift;
|
||
|
my $dt=shift;
|
||
|
my $v=shift;
|
||
|
my $type=shift;
|
||
|
|
||
|
my $out = "Key = $key\n";
|
||
|
$out .= "DT = $dt\n";
|
||
|
$out .= "V = $v\n";
|
||
|
|
||
|
my $count = 1;
|
||
|
$count = 10000 if ($type eq "MCT");
|
||
|
|
||
|
my $rnd_val = "";
|
||
|
|
||
|
# we read 16 bytes from RNG
|
||
|
my $bufsize = 16;
|
||
|
|
||
|
my ($CO, $CI);
|
||
|
my $rng_imp = &$state_rng($key, $dt, $v);
|
||
|
my $pid = open2($CO, $CI, $rng_imp);
|
||
|
for (my $i = 0; $i < $count; ++$i) {
|
||
|
my $len = sysread $CO, $rnd_val, $bufsize;
|
||
|
#print STDERR "len=$len, bufsize=$bufsize\n";
|
||
|
die "len=$len != bufsize=$bufsize" if $len ne $bufsize;
|
||
|
#print STDERR "calc_data=", bin2hex($rnd_val), "\n";
|
||
|
}
|
||
|
close $CO;
|
||
|
close $CI;
|
||
|
waitpid $pid, 0;
|
||
|
|
||
|
$out .= "R = " . bin2hex($rnd_val) . "\n\n";
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
sub drbg_kat($$$$$$$$$) {
|
||
|
my $cipher = shift;
|
||
|
my $drbg_expectedlen = shift;
|
||
|
my $drbg_entropy = shift;
|
||
|
my $drbg_nonce = shift;
|
||
|
my $drbg_pers = shift;
|
||
|
my $drbg_addtla = shift;
|
||
|
my $drbg_addtlb = shift;
|
||
|
my $drbg_entpra = shift;
|
||
|
my $drbg_entprb = shift;
|
||
|
my $out = "";
|
||
|
|
||
|
my $ret = &$drbg($cipher, $drbg_expectedlen, $drbg_entropy,
|
||
|
$drbg_nonce, $drbg_pers, $drbg_addtla,
|
||
|
$drbg_addtlb, $drbg_entpra, $drbg_entprb);
|
||
|
$out = "ReturnedBits = " . $ret . "\n";
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
# DSA PQGen test
|
||
|
# $1 modulus size
|
||
|
# $2 q size
|
||
|
# $3 number of rounds to perform the test
|
||
|
# return: string formatted as expected by CAVS
|
||
|
sub dsa_pqgen_driver($$$) {
|
||
|
my $mod = shift;
|
||
|
my $qsize = shift;
|
||
|
my $rounds = shift;
|
||
|
|
||
|
my $out = "";
|
||
|
for(my $i=0; $i<$rounds; $i++) {
|
||
|
my $ret = &$dsa_pqggen($mod, $qsize, "");
|
||
|
my ($P, $Q, $G, $Seed, $c, $H) = split(/\n/, $ret);
|
||
|
die "Return value does not contain all expected values of P, Q, Seed, c for dsa_pqggen"
|
||
|
if (!defined($P) || !defined($Q) ||
|
||
|
!defined($Seed) || !defined($c));
|
||
|
|
||
|
# now change the counter to decimal as CAVS wants decimal
|
||
|
# counter value although all other is HEX
|
||
|
$c = hex($c);
|
||
|
|
||
|
$out .= "P = $P\n";
|
||
|
$out .= "Q = $Q\n";
|
||
|
$out .= "domain_parameter_seed = $Seed\n";
|
||
|
$out .= "counter = $c\n\n";
|
||
|
}
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
# DSA GGen test
|
||
|
# $1 modulus size
|
||
|
# $2 q size
|
||
|
# $3 p in hex form
|
||
|
# $4 q in hex form
|
||
|
# return: string formatted as expected by CAVS
|
||
|
sub dsa_ggen_driver($$$$) {
|
||
|
my $mod = shift;
|
||
|
my $qsize = shift;
|
||
|
my $p = shift;
|
||
|
my $q = shift;
|
||
|
|
||
|
my $out = "";
|
||
|
my $ret = &$dsa_ggen($mod, $qsize, $p, $q);
|
||
|
my ($P, $Q, $G) = split(/\n/, $ret);
|
||
|
die "Return value does not contain all expected values of P, Q, G for dsa_ggen"
|
||
|
if (!defined($P) || !defined($Q) || !defined($G));
|
||
|
|
||
|
$out .= "G = $G\n\n";
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
# DSA PQVer test
|
||
|
# $1 modulus size
|
||
|
# $2 q size
|
||
|
# $3 p in hex form
|
||
|
# $4 q in hex form
|
||
|
# $5 seed in hex form
|
||
|
# $6 c decimal counter
|
||
|
# return: string formatted as expected by CAVS
|
||
|
sub dsa_pqver_driver($$$$$$) {
|
||
|
my $mod = shift;
|
||
|
my $qsize = shift;
|
||
|
my $p = shift;
|
||
|
my $q = shift;
|
||
|
my $seed = shift;
|
||
|
my $c = shift;
|
||
|
|
||
|
my $out = "";
|
||
|
my $ret = &$dsa_pqggen($mod, $qsize, $seed);
|
||
|
my ($P, $Q, $G, $seed2, $c2, $h2) = split(/\n/, $ret);
|
||
|
die "Return value does not contain all expected values of P, Q, G, seed, c for dsa_pqggen"
|
||
|
if (!defined($P) || !defined($Q) || !defined($G) ||
|
||
|
!defined($seed2) || !defined($c2));
|
||
|
|
||
|
$c2 = hex($c2);
|
||
|
|
||
|
$out .= "Seed = $seed\n";
|
||
|
$out .= "c = $c\n";
|
||
|
|
||
|
if ($P eq $p && $Q eq $q && $seed eq lc $seed2 && $c eq $c2) {
|
||
|
$out .= "Result = P\n\n";
|
||
|
}
|
||
|
else {
|
||
|
$out .= "Result = F\n\n";
|
||
|
}
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
sub hexcomp($$) {
|
||
|
my $a = lc shift;
|
||
|
my $b = lc shift;
|
||
|
|
||
|
if (length $a < length $b) {
|
||
|
my $c = $a;
|
||
|
$a = $b;
|
||
|
$b = $a;
|
||
|
}
|
||
|
while (length $b < length $a) {
|
||
|
$b = "00$b";
|
||
|
}
|
||
|
|
||
|
return $a eq $b;
|
||
|
}
|
||
|
|
||
|
# DSA PQGVer test
|
||
|
# $1 modulus size
|
||
|
# $2 q size
|
||
|
# $3 p in hex form
|
||
|
# $4 q in hex form
|
||
|
# $5 g in hex form
|
||
|
# $6 seed in hex form
|
||
|
# $7 c decimal counter
|
||
|
# $8 h in hex form
|
||
|
# return: string formatted as expected by CAVS
|
||
|
sub dsa_pqgver_driver($$$$$$$$) {
|
||
|
my $mod = shift;
|
||
|
my $qsize = shift;
|
||
|
my $p = shift;
|
||
|
my $q = shift;
|
||
|
my $g = shift;
|
||
|
my $seed = shift;
|
||
|
my $c = shift;
|
||
|
my $h = shift;
|
||
|
|
||
|
my $out = "";
|
||
|
my $ret = &$dsa_pqggen($mod, $qsize, $seed);
|
||
|
my ($P, $Q, $G, $seed2, $c2, $h2) = split(/\n/, $ret);
|
||
|
die "Return value does not contain all expected values of P, Q, G, seed, c, H for dsa_pqggen"
|
||
|
if (!defined($P) || !defined($Q) || !defined($G) ||
|
||
|
!defined($seed2) || !defined($c2) || !defined($h2));
|
||
|
|
||
|
|
||
|
|
||
|
$out .= "Seed = $seed\n";
|
||
|
$out .= "c = $c\n";
|
||
|
$out .= "H = $h\n";
|
||
|
|
||
|
$c2 = hex($c2);
|
||
|
|
||
|
if (hexcomp($P, $p) && hexcomp($Q, $q) && hexcomp($G, $g) && hexcomp($seed, $seed2) &&
|
||
|
$c == $c2 && hex($h) == hex($h2)) {
|
||
|
$out .= "Result = P\n\n";
|
||
|
}
|
||
|
else {
|
||
|
$out .= "Result = F\n\n";
|
||
|
}
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
# DSA Keypair test
|
||
|
# $1 modulus size
|
||
|
# $2 q size
|
||
|
# $3 number of rounds to perform the test
|
||
|
# return: string formatted as expected by CAVS
|
||
|
sub dsa_keypair_driver($$$) {
|
||
|
my $mod = shift;
|
||
|
my $qsize = shift;
|
||
|
my $rounds = shift;
|
||
|
|
||
|
my $out = "";
|
||
|
my $tmpkeyfile = "dsa_siggen.tmp.$$";
|
||
|
my %pqg = &$gen_dsakey($mod, $qsize, $tmpkeyfile);
|
||
|
$out .= "P = " . $pqg{'P'} . "\n";
|
||
|
$out .= "Q = " . $pqg{'Q'} . "\n";
|
||
|
$out .= "G = " . $pqg{'G'} . "\n\n";
|
||
|
unlink($tmpkeyfile);
|
||
|
|
||
|
for(my $i=0; $i<$rounds; $i++) {
|
||
|
my $ret = &$gen_dsakey_domain($pqg{'P'}, $pqg{'Q'}, $pqg{'G'});
|
||
|
my ($X, $Y) = split(/\n/, $ret);
|
||
|
die "Return value does not contain all expected values of X, Y for gen_dsakey_domain"
|
||
|
if (!defined($X) || !defined($Y));
|
||
|
|
||
|
$out .= "X = $X\n";
|
||
|
$out .= "Y = $Y\n\n";
|
||
|
}
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
# DSA SigGen test
|
||
|
# $1: Message to be signed in hex form
|
||
|
# $2: file name with DSA key in PEM form
|
||
|
# return: string formatted as expected by CAVS
|
||
|
sub dsa_siggen($$) {
|
||
|
my $data = shift;
|
||
|
my $keyfile = shift;
|
||
|
|
||
|
my $out = "";
|
||
|
|
||
|
my %ret = &$dsa_sign($data, $keyfile);
|
||
|
|
||
|
$out .= "Msg = $data\n";
|
||
|
$out .= "Y = " . $ret{'Y'} . "\n";
|
||
|
$out .= "R = " . $ret{'R'} . "\n";
|
||
|
$out .= "S = " . $ret{'S'} . "\n";
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
|
||
|
# DSA signature verification
|
||
|
# $1 modulus
|
||
|
# $2 P
|
||
|
# $3 Q
|
||
|
# $4 G
|
||
|
# $5 Y - public key
|
||
|
# $6 r
|
||
|
# $7 s
|
||
|
# $8 message to be verified
|
||
|
# return: string formatted as expected by CAVS
|
||
|
sub dsa_sigver($$$$$$$$) {
|
||
|
my $modulus = shift;
|
||
|
my $p = shift;
|
||
|
my $q = shift;
|
||
|
my $g = shift;
|
||
|
my $y = shift;
|
||
|
my $r = shift;
|
||
|
my $s = shift;
|
||
|
my $msg = shift;
|
||
|
|
||
|
my $out = "";
|
||
|
|
||
|
#PQG are already printed - do not print them here
|
||
|
|
||
|
$out .= "Msg = $msg\n";
|
||
|
$out .= "Y = $y\n";
|
||
|
$out .= "R = $r\n";
|
||
|
$out .= "S = $s\n";
|
||
|
|
||
|
# XXX maybe a secure temp file name is better here
|
||
|
# but since it is not run on a security sensitive
|
||
|
# system, I hope that this is fine
|
||
|
my $keyfile = "dsa_sigver.tmp.$$";
|
||
|
&$dsa_genpubkey($keyfile, $p, $q, $g, $y);
|
||
|
|
||
|
$out .= "Result = " . (&$dsa_verify($msg, $keyfile, $r, $s) ? "P\n" : "F\n");
|
||
|
|
||
|
unlink($keyfile);
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
##############################################################
|
||
|
# Parser of input file and generator of result file
|
||
|
#
|
||
|
|
||
|
sub usage() {
|
||
|
|
||
|
print STDERR "Usage:
|
||
|
$0 [-R] [-D] [-I name] <CAVS-test vector file>
|
||
|
|
||
|
-R execution of ARCFOUR instead of OpenSSL
|
||
|
-I NAME Use interface style NAME:
|
||
|
openssl OpenSSL (default)
|
||
|
libgcrypt Libgcrypt
|
||
|
cryptoapi Kernel
|
||
|
-D SigGen and SigVer are executed with DSA
|
||
|
Please note that the DSA CAVS vectors do not allow distinguishing
|
||
|
them from the RSA vectors. As the RSA test is the default, you have
|
||
|
to supply this option to apply the DSA logic";
|
||
|
}
|
||
|
|
||
|
# Parser of CAVS test vector file
|
||
|
# $1: Test vector file
|
||
|
# $2: Output file for test results
|
||
|
# return: nothing
|
||
|
sub parse($$) {
|
||
|
my $infile = shift;
|
||
|
my $outfile = shift;
|
||
|
|
||
|
my $out = "";
|
||
|
|
||
|
# this is my cipher/hash type
|
||
|
my $cipher = "";
|
||
|
|
||
|
# Test type
|
||
|
# 1 - cipher known answer test
|
||
|
# 2 - cipher Monte Carlo test
|
||
|
# 3 - hash known answer test
|
||
|
# 4 - hash Monte Carlo test
|
||
|
# 5 - RSA signature generation
|
||
|
# 6 - RSA signature verification
|
||
|
my $tt = 0;
|
||
|
|
||
|
# Variables for tests
|
||
|
my $keytype = ""; # we can have "KEY", "KEYs", "KEY1"
|
||
|
my $key1 = "";
|
||
|
my $key2 = undef; #undef needed for allowing
|
||
|
my $key3 = undef; #the use of them as input variables
|
||
|
my $pt = "";
|
||
|
my $enc = 1;
|
||
|
my $iv = "";
|
||
|
my $len = undef; #see key2|3
|
||
|
my $n = "";
|
||
|
my $e = "";
|
||
|
my $signature = "";
|
||
|
my $rsa_keyfile = "";
|
||
|
my $dsa_keyfile = "";
|
||
|
my $dt = "";
|
||
|
my $v = "";
|
||
|
my $klen = "";
|
||
|
my $tlen = "";
|
||
|
my $modulus = "";
|
||
|
my $qsize = "";
|
||
|
my $capital_n = 0;
|
||
|
my $num = 0;
|
||
|
my $capital_p = "";
|
||
|
my $capital_q = "";
|
||
|
my $capital_g = "";
|
||
|
my $capital_y = "";
|
||
|
my $capital_r = "";
|
||
|
my $capital_h = "";
|
||
|
my $c = "";
|
||
|
my $xp1 = "";
|
||
|
my $xp2 = "";
|
||
|
my $Xp = "";
|
||
|
my $xq1 = "";
|
||
|
my $xq2 = "";
|
||
|
my $Xq = "";
|
||
|
my $drbg_expectedlen = "";
|
||
|
my $drbg_entropy = "";
|
||
|
my $drbg_nonce = "";
|
||
|
my $drbg_pers = "";
|
||
|
my $drbg_addtla = "";
|
||
|
my $drbg_addtlb = "";
|
||
|
my $drbg_entpra = "";
|
||
|
my $drbg_entprb = "";
|
||
|
|
||
|
my $mode = "";
|
||
|
|
||
|
open(IN, "<$infile");
|
||
|
while(<IN>) {
|
||
|
|
||
|
my $line = $_;
|
||
|
chomp($line);
|
||
|
$line =~ s/\r//;
|
||
|
|
||
|
my $keylen = "";
|
||
|
|
||
|
# Mode and type check
|
||
|
# consider the following parsed line
|
||
|
# '# AESVS MCT test data for CBC'
|
||
|
# '# TDES Multi block Message Test for CBC'
|
||
|
# '# INVERSE PERMUTATION - KAT for CBC'
|
||
|
# '# SUBSTITUTION TABLE - KAT for CBC'
|
||
|
# '# TDES Monte Carlo (Modes) Test for CBC'
|
||
|
# '# "SHA-1 Monte" information for "IBMRHEL5"'
|
||
|
# '# "SigVer PKCS#1 Ver 1.5" information for "IBMRHEL5"'
|
||
|
# '# "SigGen PKCS#1 Ver 1.5" information for "IBMRHEL5"'
|
||
|
# '#RC4VS MCT test data'
|
||
|
|
||
|
# avoid false positives from user specified 'for "PRODUCT"' strings
|
||
|
my $tmpline = $line;
|
||
|
$tmpline =~ s/ for ".*"//;
|
||
|
|
||
|
##### Extract cipher
|
||
|
# XXX there may be more - to be added
|
||
|
if ($tmpline =~ /^#.*(CBC|ECB|OFB|CFB|SHA-|SigGen|SigVer|RC4VS|ANSI X9\.31|Hash sizes tested|PQGGen|KeyGen RSA|KeyPair|PQGVer|DRBG)/) {
|
||
|
if ($tmpline =~ /CBC/) { $mode="cbc"; }
|
||
|
elsif ($tmpline =~ /ECB/) { $mode="ecb"; }
|
||
|
elsif ($tmpline =~ /OFB/) { $mode="ofb"; }
|
||
|
elsif ($tmpline =~ /CFB/) { $mode="cfb"; }
|
||
|
#we do not need mode as the cipher is already clear
|
||
|
elsif ($tmpline =~ /SHA-1/) { $cipher="sha1"; }
|
||
|
elsif ($tmpline =~ /SHA-224/) { $cipher="sha224"; }
|
||
|
elsif ($tmpline =~ /SHA-256/) { $cipher="sha256"; }
|
||
|
elsif ($tmpline =~ /SHA-384/) { $cipher="sha384"; }
|
||
|
elsif ($tmpline =~ /SHA-512/) { $cipher="sha512"; }
|
||
|
#we do not need mode as the cipher is already clear
|
||
|
elsif ($tmpline =~ /RC4VS/) { $cipher="rc4"; }
|
||
|
elsif ($tmpline =~ /SigGen|SigVer/) {
|
||
|
die "Error: X9.31 is not supported"
|
||
|
if ($tmpline =~ /X9/);
|
||
|
$cipher="sha1"; #place holder - might be overwritten later
|
||
|
}
|
||
|
|
||
|
if ($tmpline =~ /^#.*AESVS/) {
|
||
|
# AES cipher (part of it)
|
||
|
$cipher="aes";
|
||
|
}
|
||
|
if ($tmpline =~ /^#.*(TDES|KAT)/) {
|
||
|
# TDES cipher (full definition)
|
||
|
# the FIPS-140 test generator tool does not produce
|
||
|
# machine readable output!
|
||
|
if ($mode eq "cbc") { $cipher="des-ede3-cbc"; }
|
||
|
if ($mode eq "ecb") { $cipher="des-ede3"; }
|
||
|
if ($mode eq "ofb") { $cipher="des-ede3-ofb"; }
|
||
|
if ($mode eq "cfb") { $cipher="des-ede3-cfb"; }
|
||
|
}
|
||
|
|
||
|
# check for RNG
|
||
|
if ($tmpline =~ /ANSI X9\.31/) {
|
||
|
# change the tmpline to add the type of the
|
||
|
# test which is ONLY visible from the file
|
||
|
# name :-(
|
||
|
if ($infile =~ /MCT\.req/) {
|
||
|
$tmpline .= " MCT";
|
||
|
} elsif ($infile =~ /VST\.req/) {
|
||
|
$tmpline .= " VST";
|
||
|
} else {
|
||
|
die "Unexpected cipher type with $infile";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ($tt == 0) {
|
||
|
##### Identify the test type
|
||
|
if ($tmpline =~ /DRBG/) {
|
||
|
$tt = 18;
|
||
|
die "Interface function for SP800-90A DRBG testing not defined for tested library"
|
||
|
if (!defined($drbg));
|
||
|
} elsif ($tmpline =~ /PQGVer/) {
|
||
|
$tt = 16;
|
||
|
die "Interface function for DSA PQGVer testing not defined for tested library"
|
||
|
if (!defined($dsa_pqggen));
|
||
|
} elsif ($tmpline =~ /KeyPair/) {
|
||
|
$tt = 14;
|
||
|
die "Interface function dsa_keygen for DSA key generation not defined for tested library"
|
||
|
if (!defined($gen_dsakey_domain));
|
||
|
} elsif ($tmpline =~ /KeyGen RSA \(X9\.31\)/) {
|
||
|
$tt = 13;
|
||
|
die "Interface function rsa_derive for RSA key generation not defined for tested library"
|
||
|
if (!defined($rsa_derive));
|
||
|
} elsif ($tmpline =~ /SigVer/ && $opt{'D'} ) {
|
||
|
$tt = 12;
|
||
|
die "Interface function dsa_verify or dsa_genpubkey for DSA verification not defined for tested library"
|
||
|
if (!defined($dsa_verify) || !defined($dsa_genpubkey));
|
||
|
} elsif ($tmpline =~ /SigGen/ && $opt{'D'}) {
|
||
|
$tt = 11;
|
||
|
die "Interface function dsa_sign or gen_dsakey for DSA sign not defined for tested library"
|
||
|
if (!defined($dsa_sign) || !defined($gen_dsakey));
|
||
|
} elsif ($tmpline =~ /PQGGen/) {
|
||
|
$tt = 10;
|
||
|
die "Interface function for DSA PQGGen testing not defined for tested library"
|
||
|
if (!defined($dsa_pqggen) || !defined($dsa_ggen));
|
||
|
} elsif ($tmpline =~ /Hash sizes tested/) {
|
||
|
$tt = 9;
|
||
|
die "Interface function hmac for HMAC testing not defined for tested library"
|
||
|
if (!defined($hmac));
|
||
|
} elsif ($tmpline =~ /ANSI X9\.31/ && $tmpline =~ /MCT/) {
|
||
|
$tt = 8;
|
||
|
die "Interface function state_rng for RNG MCT not defined for tested library"
|
||
|
if (!defined($state_rng));
|
||
|
} elsif ($tmpline =~ /ANSI X9\.31/ && $tmpline =~ /VST/) {
|
||
|
$tt = 7;
|
||
|
die "Interface function state_rng for RNG KAT not defined for tested library"
|
||
|
if (!defined($state_rng));
|
||
|
} elsif ($tmpline =~ /SigVer/ ) {
|
||
|
$tt = 6;
|
||
|
die "Interface function rsa_verify or gen_rsakey for RSA verification not defined for tested library"
|
||
|
if (!defined($rsa_verify) || !defined($gen_rsakey));
|
||
|
} elsif ($tmpline =~ /SigGen/ ) {
|
||
|
$tt = 5;
|
||
|
die "Interface function rsa_sign or gen_rsakey for RSA sign not defined for tested library"
|
||
|
if (!defined($rsa_sign) || !defined($gen_rsakey));
|
||
|
} elsif ($tmpline =~ /Monte|MCT|Carlo/ && $cipher =~ /^sha/) {
|
||
|
$tt = 4;
|
||
|
die "Interface function hash for Hashing not defined for tested library"
|
||
|
if (!defined($hash));
|
||
|
} elsif ($tmpline =~ /Monte|MCT|Carlo/) {
|
||
|
$tt = 2;
|
||
|
die "Interface function state_cipher for Stateful Cipher operation defined for tested library"
|
||
|
if (!defined($state_cipher) && !defined($state_cipher_des));
|
||
|
} elsif ($cipher =~ /^sha/) {
|
||
|
$tt = 3;
|
||
|
die "Interface function hash for Hashing not defined for tested library"
|
||
|
if (!defined($hash));
|
||
|
} else {
|
||
|
$tt = 1;
|
||
|
die "Interface function encdec for Encryption/Decryption not defined for tested library"
|
||
|
if (!defined($encdec));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# This is needed as ARCFOUR does not operate with an IV
|
||
|
$iv = "00000000000000000000000000000000" if ($cipher eq "rc4"
|
||
|
&& $iv eq "" );
|
||
|
|
||
|
# we are now looking for the string
|
||
|
# '# Key Length : 256'
|
||
|
# found in AES
|
||
|
if ($tmpline =~ /^# Key Length.*?(128|192|256)/) {
|
||
|
if ($cipher eq "aes") {
|
||
|
$cipher="$cipher-$1-$mode";
|
||
|
} else {
|
||
|
die "Error: Key length $1 given for cipher $cipher which is unexpected";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# Get the test data
|
||
|
if ($line =~ /^(KEY|KEY1|Key)\s*=\s*(.*)/) { # found in ciphers and RNG
|
||
|
die "KEY seen twice - input file crap" if ($key1 ne "");
|
||
|
$keytype=$1;
|
||
|
$key1=$2;
|
||
|
$key1 =~ s/\s//g; #replace potential white spaces
|
||
|
}
|
||
|
elsif ($line =~ /^(KEYs)\s*=\s*(.*)/) { # found in ciphers and RNG
|
||
|
die "KEY seen twice - input file crap" if ($key1 ne "");
|
||
|
$keytype=$1;
|
||
|
$key1=$2;
|
||
|
$key1 =~ s/\s//g; #replace potential white spaces
|
||
|
$key2 = $key1;
|
||
|
$key3 = $key1;
|
||
|
}
|
||
|
elsif ($line =~ /^KEY2\s*=\s*(.*)/) { # found in TDES
|
||
|
die "First key not set, but got already second key - input file crap" if ($key1 eq "");
|
||
|
die "KEY2 seen twice - input file crap" if (defined($key2));
|
||
|
$key2=$1;
|
||
|
$key2 =~ s/\s//g; #replace potential white spaces
|
||
|
}
|
||
|
elsif ($line =~ /^KEY3\s*=\s*(.*)/) { # found in TDES
|
||
|
die "Second key not set, but got already third key - input file crap" if ($key2 eq "");
|
||
|
die "KEY3 seen twice - input file crap" if (defined($key3));
|
||
|
$key3=$1;
|
||
|
$key3 =~ s/\s//g; #replace potential white spaces
|
||
|
}
|
||
|
elsif ($line =~ /^IV\s*=\s*(.*)/) { # found in ciphers
|
||
|
die "IV seen twice - input file crap" if ($iv ne "");
|
||
|
$iv=$1;
|
||
|
$iv =~ s/\s//g; #replace potential white spaces
|
||
|
}
|
||
|
elsif ($line =~ /^PLAINTEXT\s*=\s*(.*)/) { # found in ciphers
|
||
|
if ( $1 !~ /\?/ ) { #only use it if there is valid hex data
|
||
|
die "PLAINTEXT/CIPHERTEXT seen twice - input file crap" if ($pt ne "");
|
||
|
$pt=$1;
|
||
|
$pt =~ s/\s//g; #replace potential white spaces
|
||
|
$enc=1;
|
||
|
}
|
||
|
}
|
||
|
elsif ($line =~ /^CIPHERTEXT\s*=\s*(.*)/) { # found in ciphers
|
||
|
if ( $1 !~ /\?/ ) { #only use it if there is valid hex data
|
||
|
die "PLAINTEXT/CIPHERTEXT seen twice - input file crap" if ($pt ne "");
|
||
|
$pt=$1;
|
||
|
$pt =~ s/\s//g; #replace potential white spaces
|
||
|
$enc=0;
|
||
|
}
|
||
|
}
|
||
|
elsif ($line =~ /^Len\s*=\s*(.*)/) { # found in hashs
|
||
|
$len=$1;
|
||
|
}
|
||
|
elsif ($line =~ /^(Msg|Seed)\s*=\s*(.*)/) { # found in hashs
|
||
|
die "Msg/Seed seen twice - input file crap" if ($pt ne "");
|
||
|
$pt=$2;
|
||
|
}
|
||
|
elsif ($line =~ /^\[A.2.1\s.*\]$/) { # found in DSA2 PQGGen request
|
||
|
$out .= $line . "\n"; # print it
|
||
|
if ($tt == 10) {
|
||
|
# now generate G from PQ
|
||
|
$tt = 15;
|
||
|
}
|
||
|
}
|
||
|
elsif ($line =~ /^\[A.2.2\s.*\]$/) { # found in DSA2 PQGVer request
|
||
|
$out .= $line . "\n"; # print it
|
||
|
if ($tt == 16) {
|
||
|
# now verify PQG
|
||
|
$tt = 17;
|
||
|
}
|
||
|
}
|
||
|
elsif ($line =~ /^\[mod\s*=\s*L=([0-9]*),\s*N=([0-9]*).*\]$/) { # found in DSA2 requests
|
||
|
$modulus = $1;
|
||
|
$qsize = $2;
|
||
|
$out .= $line . "\n\n"; # print it
|
||
|
# clear eventual PQG
|
||
|
$capital_p = "";
|
||
|
$capital_q = "";
|
||
|
$capital_g = "";
|
||
|
# generate the private key with given bit length now
|
||
|
# as we have the required key length in bit
|
||
|
if ($tt == 11) {
|
||
|
$dsa_keyfile = "dsa_siggen.tmp.$$";
|
||
|
my %pqg = &$gen_dsakey($modulus, $qsize, $dsa_keyfile);
|
||
|
$out .= "P = " . $pqg{'P'} . "\n";
|
||
|
$out .= "Q = " . $pqg{'Q'} . "\n";
|
||
|
$out .= "G = " . $pqg{'G'} . "\n\n";
|
||
|
}
|
||
|
}
|
||
|
elsif ($line =~ /^\[mod\s*=\s*(.*)\]$/) { # found in RSA requests
|
||
|
$modulus = $1;
|
||
|
$out .= $line . "\n\n"; # print it
|
||
|
# generate the private key with given bit length now
|
||
|
# as we have the required key length in bit
|
||
|
if ( $tt == 5 ) {
|
||
|
# XXX maybe a secure temp file name is better here
|
||
|
# but since it is not run on a security sensitive
|
||
|
# system, I hope that this is fine
|
||
|
$rsa_keyfile = "rsa_siggen.tmp.$$";
|
||
|
&$gen_rsakey($modulus, $rsa_keyfile);
|
||
|
my $modulus = pipe_through_program("", "openssl rsa -pubout -modulus -in $rsa_keyfile");
|
||
|
$modulus =~ s/Modulus=(.*?)\s(.|\s)*/$1/;
|
||
|
$out .= "n = $modulus\n";
|
||
|
$out .= "\ne = 10001\n"
|
||
|
}
|
||
|
}
|
||
|
elsif ($line =~ /^SHAAlg\s*=\s*(.*)/) { #found in RSA requests
|
||
|
$cipher=$1;
|
||
|
}
|
||
|
elsif($line =~ /^n\s*=\s*(.*)/) { # found in RSA requests
|
||
|
$out .= $line . "\n";
|
||
|
$n=$1;
|
||
|
}
|
||
|
elsif ($line =~ /^e\s*=\s*(.*)/) { # found in RSA requests
|
||
|
$e=$1;
|
||
|
}
|
||
|
elsif ($line =~ /^S\s*=\s*(.*)/) { # found in RSA requests
|
||
|
die "S seen twice - input file crap" if ($signature ne "");
|
||
|
$signature=$1;
|
||
|
}
|
||
|
elsif ($line =~ /^DT\s*=\s*(.*)/) { # X9.31 RNG requests
|
||
|
die "DT seen twice - check input file"
|
||
|
if ($dt ne "");
|
||
|
$dt=$1;
|
||
|
}
|
||
|
elsif ($line =~ /^V\s*=\s*(.*)/) { # X9.31 RNG requests
|
||
|
die "V seen twice - check input file"
|
||
|
if ($v ne "");
|
||
|
$v=$1;
|
||
|
}
|
||
|
elsif ($line =~ /^Klen\s*=\s*(.*)/) { # HMAC requests
|
||
|
die "Klen seen twice - check input file"
|
||
|
if ($klen ne "");
|
||
|
$klen=$1;
|
||
|
}
|
||
|
elsif ($line =~ /^Tlen\s*=\s*(.*)/) { # HMAC RNG requests
|
||
|
die "Tlen seen twice - check input file"
|
||
|
if ($tlen ne "");
|
||
|
$tlen=$1;
|
||
|
}
|
||
|
elsif ($line =~ /^N\s*=\s*(.*)/) { #DSA KeyPair
|
||
|
die "N seen twice - check input file"
|
||
|
if ($capital_n);
|
||
|
$capital_n = $1;
|
||
|
}
|
||
|
elsif ($line =~ /^Num\s*=\s*(.*)/) { #DSA PQGGen
|
||
|
die "Num seen twice - check input file"
|
||
|
if ($num);
|
||
|
$num = $1;
|
||
|
}
|
||
|
elsif ($line =~ /^P\s*=\s*(.*)/) { #DSA SigVer
|
||
|
die "P seen twice - check input file"
|
||
|
if ($capital_p);
|
||
|
$capital_p = $1;
|
||
|
$out .= $line . "\n"; # print it
|
||
|
}
|
||
|
elsif ($line =~ /^Q\s*=\s*(.*)/) { #DSA SigVer
|
||
|
die "Q seen twice - check input file"
|
||
|
if ($capital_q);
|
||
|
$capital_q = $1;
|
||
|
$out .= $line . "\n"; # print it
|
||
|
}
|
||
|
elsif ($line =~ /^G\s*=\s*(.*)/) { #DSA SigVer
|
||
|
die "G seen twice - check input file"
|
||
|
if ($capital_g);
|
||
|
$capital_g = $1;
|
||
|
$out .= $line . "\n"; # print it
|
||
|
}
|
||
|
elsif ($line =~ /^Y\s*=\s*(.*)/) { #DSA SigVer
|
||
|
die "Y seen twice - check input file"
|
||
|
if ($capital_y);
|
||
|
$capital_y = $1;
|
||
|
}
|
||
|
elsif ($line =~ /^R\s*=\s*(.*)/) { #DSA SigVer
|
||
|
die "R seen twice - check input file"
|
||
|
if ($capital_r);
|
||
|
$capital_r = $1;
|
||
|
}
|
||
|
elsif ($line =~ /^H\s*=\s*(.*)/) { #DSA PQGVer
|
||
|
die "H seen twice - check input file"
|
||
|
if ($capital_h);
|
||
|
$capital_h = $1;
|
||
|
}
|
||
|
elsif ($line =~ /^c\s*=\s*(.*)/) { #DSA PQGVer
|
||
|
die "c seen twice - check input file"
|
||
|
if ($c);
|
||
|
$c = $1;
|
||
|
}
|
||
|
elsif ($line =~ /^xp1\s*=\s*(.*)/) { #RSA key gen
|
||
|
die "xp1 seen twice - check input file"
|
||
|
if ($xp1);
|
||
|
$xp1 = $1;
|
||
|
}
|
||
|
elsif ($line =~ /^xp2\s*=\s*(.*)/) { #RSA key gen
|
||
|
die "xp2 seen twice - check input file"
|
||
|
if ($xp2);
|
||
|
$xp2 = $1;
|
||
|
}
|
||
|
elsif ($line =~ /^Xp\s*=\s*(.*)/) { #RSA key gen
|
||
|
die "Xp seen twice - check input file"
|
||
|
if ($Xp);
|
||
|
$Xp = $1;
|
||
|
}
|
||
|
elsif ($line =~ /^xq1\s*=\s*(.*)/) { #RSA key gen
|
||
|
die "xq1 seen twice - check input file"
|
||
|
if ($xq1);
|
||
|
$xq1 = $1;
|
||
|
}
|
||
|
elsif ($line =~ /^xq2\s*=\s*(.*)/) { #RSA key gen
|
||
|
die "xq2 seen twice - check input file"
|
||
|
if ($xq2);
|
||
|
$xq2 = $1;
|
||
|
}
|
||
|
elsif ($line =~ /^Xq\s*=\s*(.*)/) { #RSA key gen
|
||
|
die "Xq seen twice - check input file"
|
||
|
if ($Xq);
|
||
|
$Xq = $1;
|
||
|
}
|
||
|
# DRBG types
|
||
|
elsif ($line =~ /^\[SHA-1\]/) { $cipher="sha1"; $out .= $line . "\n";}
|
||
|
elsif ($line =~ /^\[SHA-224\]/) { $cipher="sha224"; $out .= $line . "\n";}
|
||
|
elsif ($line =~ /^\[SHA-256\]/) { $cipher="sha256"; $out .= $line . "\n";}
|
||
|
elsif ($line =~ /^\[SHA-384\]/) { $cipher="sha384"; $out .= $line . "\n";}
|
||
|
elsif ($line =~ /^\[SHA-512\]/) { $cipher="sha512"; $out .= $line . "\n";}
|
||
|
elsif ($line =~ /^\[AES-128/) { $cipher="aes128"; $out .= $line . "\n";}
|
||
|
elsif ($line =~ /^\[AES-192/) { $cipher="aes192"; $out .= $line . "\n";}
|
||
|
elsif ($line =~ /^\[AES-256/) { $cipher="aes256"; $out .= $line . "\n";}
|
||
|
elsif ($line =~ /^\[ReturnedBitsLen\s*=\s*(.*)]/) { $drbg_expectedlen = $1; $out .= $line . "\n";}
|
||
|
elsif ($line =~ /^EntropyInput\s*=\s*(.*)/) { $drbg_entropy=$1; $out .= $line . "\n";}
|
||
|
elsif ($line =~ /^Nonce\s*=\s*(.*)/) { $drbg_nonce=$1; $out .= $line . "\n";}
|
||
|
elsif ($line =~ /^PersonalizationString\s*=\s*(.*)/) {
|
||
|
$drbg_pers=$1;
|
||
|
if ($drbg_pers eq "") {
|
||
|
$drbg_pers = "z";
|
||
|
}
|
||
|
$out .= $line . "\n";
|
||
|
}
|
||
|
elsif ($line =~ /^AdditionalInput\s*=\s*(.*)/) {
|
||
|
if ($drbg_addtla eq "") {
|
||
|
$drbg_addtla=$1;
|
||
|
if ($drbg_addtla eq "") {
|
||
|
$drbg_addtla = "z";
|
||
|
}
|
||
|
} else {
|
||
|
$drbg_addtlb=$1;
|
||
|
if ($drbg_addtlb eq "") {
|
||
|
$drbg_addtlb = "z";
|
||
|
}
|
||
|
}
|
||
|
$out .= $line . "\n";
|
||
|
}
|
||
|
elsif ($line =~ /^EntropyInputPR\s*=\s*(.*)/) {
|
||
|
if ($drbg_entpra eq "") {
|
||
|
$drbg_entpra=$1;
|
||
|
if ($drbg_entpra eq "") {
|
||
|
$drbg_entpra = "z";
|
||
|
}
|
||
|
} else {
|
||
|
$drbg_entprb=$1;
|
||
|
if ($drbg_entprb eq "") {
|
||
|
$drbg_entprb = "z";
|
||
|
}
|
||
|
}
|
||
|
$out .= $line . "\n";
|
||
|
}
|
||
|
else {
|
||
|
$out .= $line . "\n";
|
||
|
}
|
||
|
|
||
|
# call tests if all input data is there
|
||
|
if ($tt == 1) {
|
||
|
if ($key1 ne "" && $pt ne "" && $cipher ne "") {
|
||
|
$out .= kat($keytype, $key1, $key2, $key3, $iv, $pt, $cipher, $enc);
|
||
|
$keytype = "";
|
||
|
$key1 = "";
|
||
|
$key2 = undef;
|
||
|
$key3 = undef;
|
||
|
$iv = "";
|
||
|
$pt = "";
|
||
|
}
|
||
|
}
|
||
|
elsif ($tt == 2) {
|
||
|
if ($key1 ne "" && $pt ne "" && $cipher ne "") {
|
||
|
$out .= crypto_mct($keytype, $key1, $key2, $key3, $iv, $pt, $cipher, $enc);
|
||
|
$keytype = "";
|
||
|
$key1 = "";
|
||
|
$key2 = undef;
|
||
|
$key3 = undef;
|
||
|
$iv = "";
|
||
|
$pt = "";
|
||
|
}
|
||
|
}
|
||
|
elsif ($tt == 3) {
|
||
|
if ($pt ne "" && $cipher ne "") {
|
||
|
$out .= hash_kat($pt, $cipher, $len);
|
||
|
$pt = "";
|
||
|
$len = undef;
|
||
|
}
|
||
|
}
|
||
|
elsif ($tt == 4) {
|
||
|
if ($pt ne "" && $cipher ne "") {
|
||
|
$out .= hash_mct($pt, $cipher);
|
||
|
$pt = "";
|
||
|
}
|
||
|
}
|
||
|
elsif ($tt == 5) {
|
||
|
if ($pt ne "" && $cipher ne "" && $rsa_keyfile ne "") {
|
||
|
$out .= rsa_siggen($pt, $cipher, $rsa_keyfile);
|
||
|
$pt = "";
|
||
|
}
|
||
|
}
|
||
|
elsif ($tt == 6) {
|
||
|
if ($pt ne "" && $cipher ne "" && $signature ne "" && $n ne "" && $e ne "") {
|
||
|
$out .= rsa_sigver($pt, $cipher, $signature, $n, $e);
|
||
|
$pt = "";
|
||
|
$signature = "";
|
||
|
}
|
||
|
}
|
||
|
elsif ($tt == 7 ) {
|
||
|
if ($key1 ne "" && $dt ne "" && $v ne "") {
|
||
|
$out .= rngx931($key1, $dt, $v, "VST");
|
||
|
$key1 = "";
|
||
|
$dt = "";
|
||
|
$v = "";
|
||
|
}
|
||
|
}
|
||
|
elsif ($tt == 8 ) {
|
||
|
if ($key1 ne "" && $dt ne "" && $v ne "") {
|
||
|
$out .= rngx931($key1, $dt, $v, "MCT");
|
||
|
$key1 = "";
|
||
|
$dt = "";
|
||
|
$v = "";
|
||
|
}
|
||
|
}
|
||
|
elsif ($tt == 9) {
|
||
|
if ($klen ne "" && $tlen ne "" && $key1 ne "" && $pt ne "") {
|
||
|
$out .= hmac_kat($klen, $tlen, $key1, $pt);
|
||
|
$key1 = "";
|
||
|
$tlen = "";
|
||
|
$klen = "";
|
||
|
$pt = "";
|
||
|
}
|
||
|
}
|
||
|
elsif ($tt == 10) {
|
||
|
if ($modulus ne "" && $qsize ne "" && $num > 0) {
|
||
|
$out .= dsa_pqgen_driver($modulus, $qsize, $num);
|
||
|
$num = 0;
|
||
|
}
|
||
|
}
|
||
|
elsif ($tt == 11) {
|
||
|
if ($pt ne "" && $dsa_keyfile ne "") {
|
||
|
$out .= dsa_siggen($pt, $dsa_keyfile);
|
||
|
$pt = "";
|
||
|
}
|
||
|
}
|
||
|
elsif ($tt == 12) {
|
||
|
if ($modulus ne "" &&
|
||
|
$capital_p ne "" &&
|
||
|
$capital_q ne "" &&
|
||
|
$capital_g ne "" &&
|
||
|
$capital_y ne "" &&
|
||
|
$capital_r ne "" &&
|
||
|
$signature ne "" &&
|
||
|
$pt ne "") {
|
||
|
$out .= dsa_sigver($modulus,
|
||
|
$capital_p,
|
||
|
$capital_q,
|
||
|
$capital_g,
|
||
|
$capital_y,
|
||
|
$capital_r,
|
||
|
$signature,
|
||
|
$pt);
|
||
|
|
||
|
# We do not clear the domain values PQG and
|
||
|
# the modulus value as they
|
||
|
# are specified only once in a file
|
||
|
# and we do not need to print them as they
|
||
|
# are already printed above
|
||
|
$capital_y = "";
|
||
|
$capital_r = "";
|
||
|
$signature = "";
|
||
|
$pt = "";
|
||
|
}
|
||
|
}
|
||
|
elsif ($tt == 13) {
|
||
|
if($modulus ne "" &&
|
||
|
$e ne "" &&
|
||
|
$xp1 ne "" &&
|
||
|
$xp2 ne "" &&
|
||
|
$Xp ne "" &&
|
||
|
$xq1 ne "" &&
|
||
|
$xq2 ne "" &&
|
||
|
$Xq ne "") {
|
||
|
$out .= rsa_keygen($modulus,
|
||
|
$e,
|
||
|
$xp1,
|
||
|
$xp2,
|
||
|
$Xp,
|
||
|
$xq1,
|
||
|
$xq2,
|
||
|
$Xq);
|
||
|
$e = "";
|
||
|
$xp1 = "";
|
||
|
$xp2 = "";
|
||
|
$Xp = "";
|
||
|
$xq1 = "";
|
||
|
$xq2 = "";
|
||
|
$Xq = "";
|
||
|
}
|
||
|
}
|
||
|
elsif ($tt == 14) {
|
||
|
if ($modulus ne "" &&
|
||
|
$qsize ne "" &&
|
||
|
$capital_n > 0) {
|
||
|
$out .= dsa_keypair_driver($modulus,
|
||
|
$qsize,
|
||
|
$capital_n);
|
||
|
$capital_n = 0;
|
||
|
}
|
||
|
}
|
||
|
elsif ($tt == 15) {
|
||
|
if ($modulus ne "" &&
|
||
|
$qsize ne "" &&
|
||
|
$capital_p ne "" &&
|
||
|
$capital_q ne "") {
|
||
|
$out .= dsa_ggen_driver($modulus,
|
||
|
$qsize,
|
||
|
$capital_p,
|
||
|
$capital_q);
|
||
|
$capital_p = "";
|
||
|
$capital_q = "";
|
||
|
$num--;
|
||
|
}
|
||
|
}
|
||
|
elsif ($tt == 16) {
|
||
|
if ($modulus ne "" &&
|
||
|
$qsize ne "" &&
|
||
|
$capital_p ne "" &&
|
||
|
$capital_q ne "" &&
|
||
|
$pt ne "" &&
|
||
|
$c ne "") {
|
||
|
$out .= dsa_pqver_driver($modulus,
|
||
|
$qsize,
|
||
|
$capital_p,
|
||
|
$capital_q,
|
||
|
$pt,
|
||
|
$c);
|
||
|
$capital_p = "";
|
||
|
$capital_q = "";
|
||
|
$pt = "";
|
||
|
$c = "";
|
||
|
}
|
||
|
}
|
||
|
elsif ($tt == 17) {
|
||
|
if ($modulus ne "" &&
|
||
|
$qsize ne "" &&
|
||
|
$capital_p ne "" &&
|
||
|
$capital_q ne "" &&
|
||
|
$capital_g ne "" &&
|
||
|
$pt ne "" &&
|
||
|
$c ne "" &&
|
||
|
$capital_h ne "") {
|
||
|
$out .= dsa_pqgver_driver($modulus,
|
||
|
$qsize,
|
||
|
$capital_p,
|
||
|
$capital_q,
|
||
|
$capital_g,
|
||
|
$pt,
|
||
|
$c,
|
||
|
$capital_h);
|
||
|
$capital_p = "";
|
||
|
$capital_q = "";
|
||
|
$capital_g = "";
|
||
|
$pt = "";
|
||
|
$c = "";
|
||
|
$capital_h = "";
|
||
|
}
|
||
|
}
|
||
|
elsif ($tt == 18) {
|
||
|
if ($cipher ne "" &&
|
||
|
$drbg_expectedlen ne "" &&
|
||
|
$drbg_entropy ne "" &&
|
||
|
$drbg_nonce ne "" &&
|
||
|
$drbg_pers ne "" &&
|
||
|
$drbg_addtla ne "" &&
|
||
|
$drbg_addtlb ne "") {
|
||
|
if ($drbg_entpra ne "" && $drbg_entprb eq "") {
|
||
|
next;
|
||
|
}
|
||
|
my $tmpcipher = $cipher;
|
||
|
if ($infile =~ /HMAC_DRBG\.req/) {
|
||
|
$tmpcipher = "hmac $tmpcipher";
|
||
|
} elsif ($infile =~ /Hash_DRBG\.req/) {
|
||
|
$tmpcipher = "hash $tmpcipher";
|
||
|
} elsif ($infile =~ /CTR_DRBG\.req/) {
|
||
|
$tmpcipher = "ctr $tmpcipher";
|
||
|
} else {
|
||
|
die "unknown DRBG input file $infile";
|
||
|
}
|
||
|
$out .= drbg_kat($tmpcipher, $drbg_expectedlen,
|
||
|
$drbg_entropy, $drbg_nonce,
|
||
|
$drbg_pers, $drbg_addtla,
|
||
|
$drbg_addtlb, $drbg_entpra,
|
||
|
$drbg_entprb);
|
||
|
$drbg_entropy = "";
|
||
|
$drbg_nonce = "";
|
||
|
$drbg_pers = "";
|
||
|
$drbg_addtla = "";
|
||
|
$drbg_addtlb = "";
|
||
|
$drbg_entpra = "";
|
||
|
$drbg_entprb = "";
|
||
|
}
|
||
|
}
|
||
|
elsif ($tt > 0) {
|
||
|
die "Test case $tt not defined";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
close IN;
|
||
|
$out =~ s/\n/\r\n/g; # make it a dos file
|
||
|
open(OUT, ">$outfile") or die "Cannot create output file $outfile: $?";
|
||
|
print OUT $out;
|
||
|
close OUT;
|
||
|
|
||
|
}
|
||
|
|
||
|
# Signalhandler
|
||
|
sub cleanup() {
|
||
|
unlink("rsa_siggen.tmp.$$");
|
||
|
unlink("rsa_sigver.tmp.$$");
|
||
|
unlink("rsa_sigver.tmp.$$.sig");
|
||
|
unlink("rsa_sigver.tmp.$$.der");
|
||
|
unlink("rsa_sigver.tmp.$$.cnf");
|
||
|
unlink("dsa_siggen.tmp.$$");
|
||
|
unlink("dsa_sigver.tmp.$$");
|
||
|
unlink("dsa_sigver.tmp.$$.sig");
|
||
|
exit;
|
||
|
}
|
||
|
|
||
|
############################################################
|
||
|
#
|
||
|
# let us pretend to be C :-)
|
||
|
sub main() {
|
||
|
|
||
|
usage() unless @ARGV;
|
||
|
|
||
|
getopts("DRI:", \%opt) or die "bad option";
|
||
|
|
||
|
##### Set library
|
||
|
|
||
|
if ( ! defined $opt{'I'} || $opt{'I'} eq 'libgcrypt' ) {
|
||
|
print STDERR "Using libgcrypt interface functions\n";
|
||
|
$encdec = \&libgcrypt_encdec;
|
||
|
$rsa_sign = \&libgcrypt_rsa_sign;
|
||
|
$rsa_verify = \&libgcrypt_rsa_verify;
|
||
|
$gen_rsakey = \&libgcrypt_gen_rsakey;
|
||
|
$rsa_derive = \&libgcrypt_rsa_derive;
|
||
|
$hash = \&libgcrypt_hash;
|
||
|
$state_cipher = \&libgcrypt_state_cipher;
|
||
|
$state_cipher_des = \&libgcrypt_state_cipher_des;
|
||
|
$state_rng = \&libgcrypt_state_rng;
|
||
|
$hmac = \&libgcrypt_hmac;
|
||
|
$dsa_pqggen = \&libgcrypt_dsa_pqggen;
|
||
|
$dsa_ggen = \&libgcrypt_dsa_ggen;
|
||
|
$gen_dsakey = \&libgcrypt_gen_dsakey;
|
||
|
$gen_dsakey_domain = \&libgcrypt_gen_dsakey_domain;
|
||
|
$dsa_sign = \&libgcrypt_dsa_sign;
|
||
|
$dsa_verify = \&libgcrypt_dsa_verify;
|
||
|
$dsa_genpubkey = \&libgcrypt_dsa_genpubkey;
|
||
|
$drbg = \&libgcrypt_drbg;
|
||
|
} elsif ( $opt{'I'} eq 'openssl' ) {
|
||
|
print STDERR "Using OpenSSL interface functions\n";
|
||
|
$encdec = \&openssl_encdec;
|
||
|
$rsa_sign = \&openssl_rsa_sign;
|
||
|
$rsa_verify = \&openssl_rsa_verify;
|
||
|
$gen_rsakey = \&openssl_gen_rsakey;
|
||
|
$hash = \&openssl_hash;
|
||
|
$state_cipher = \&openssl_state_cipher;
|
||
|
} elsif ( $opt{'I'} eq 'cryptoapi' ) {
|
||
|
print STDERR "Using cryptoapi interface functions\n";
|
||
|
$encdec = \&cryptoapi_encdec;
|
||
|
$hash = \&cryptoapi_hash;
|
||
|
$state_cipher = \&cryptoapi_state_cipher;
|
||
|
$hmac = \&cryptoapi_hmac;
|
||
|
$state_rng = \&cryptoapi_state_rng;
|
||
|
$drbg = \&cryptoapi_drbg;
|
||
|
} else {
|
||
|
die "Invalid interface option given";
|
||
|
}
|
||
|
|
||
|
my $infile=$ARGV[0];
|
||
|
die "Error: Test vector file $infile not found" if (! -f $infile);
|
||
|
|
||
|
my $outfile = $infile;
|
||
|
# let us add .rsp regardless whether we could strip .req
|
||
|
$outfile =~ s/\.req$//;
|
||
|
if ($opt{'R'}) {
|
||
|
$outfile .= ".rc4";
|
||
|
} else {
|
||
|
$outfile .= ".rsp";
|
||
|
}
|
||
|
if (-f $outfile) {
|
||
|
die "Output file $outfile could not be removed: $?"
|
||
|
unless unlink($outfile);
|
||
|
}
|
||
|
print STDERR "Performing tests from source file $infile with results stored in destination file $outfile\n";
|
||
|
|
||
|
#Signal handler
|
||
|
$SIG{HUP} = \&cleanup;
|
||
|
$SIG{INT} = \&cleanup;
|
||
|
$SIG{QUIT} = \&cleanup;
|
||
|
$SIG{TERM} = \&cleanup;
|
||
|
|
||
|
# Do the job
|
||
|
parse($infile, $outfile);
|
||
|
|
||
|
cleanup();
|
||
|
|
||
|
}
|
||
|
|
||
|
###########################################
|
||
|
# Call it
|
||
|
main();
|
||
|
1;
|