]> www.wagner.pp.ru Git - openssl-gost/engine.git/commitdiff
Merge pull request #80 from glebfm/openssl_1_1_0-testsuite-ci
authorDmitry Belyavskiy <beldmit@users.noreply.github.com>
Thu, 23 Aug 2018 20:02:58 +0000 (23:02 +0300)
committerGitHub <noreply@github.com>
Thu, 23 Aug 2018 20:02:58 +0000 (23:02 +0300)
Backport testsuite and travis-ci support to 1.1.0 branch

.travis.yml [new file with mode: 0644]
CMakeLists.txt
test/00-engine.t [new file with mode: 0644]
test/01-digest.t [new file with mode: 0644]
test/02-mac.t [new file with mode: 0644]
test/03-encrypt.t [new file with mode: 0644]
test/04-pkey.t [new file with mode: 0644]
test/Makefile.am [new file with mode: 0644]
test/run_tests [new file with mode: 0644]
test_grasshopper.c [new file with mode: 0644]

diff --git a/.travis.yml b/.travis.yml
new file mode 100644 (file)
index 0000000..4d68008
--- /dev/null
@@ -0,0 +1,32 @@
+sudo: required
+dist: trusty
+
+os: linux
+
+language: c
+
+env:
+  global:
+    - PREFIX=${HOME}/opt
+    - LD_LIBRARY_PATH=${PREFIX}/lib
+    - PATH=${PREFIX}/bin:${PATH}
+    - OPENSSL_ENGINES=${TRAVIS_BUILD_DIR}/bin
+
+matrix:
+  include:
+    - env: OPENSSL_BRANCH=master
+      os: linux
+      compiler: gcc
+    - env: OPENSSL_BRANCH=OpenSSL_1_1_0-stable
+      os: linux
+      compiler: gcc
+
+before_script:
+  - git clone -b ${OPENSSL_BRANCH} https://github.com/openssl/openssl.git
+  - cd openssl
+  - ./config shared --prefix=${PREFIX} --openssldir=${PREFIX} && make all install_sw > build.log 2>&1 || (cat build.log && exit 1)
+  - cd ..
+
+script:
+  - cmake -DOPENSSL_ROOT_DIR=${PREFIX} -DOPENSSL_LIBRARIES=${PREFIX}/lib && make VERBOSE=1
+  - make test ARGS='--verbose'
index 72fef26583671c8da4e6344ca69a2d7a1ed2a254..51eb221ef558f65961c99b1962a1105c55431978 100644 (file)
@@ -1,6 +1,11 @@
 cmake_minimum_required(VERSION 2.8)
 project(ccgost C)
 
+find_package(OpenSSL 1.1 REQUIRED)
+include_directories(${OPENSSL_INCLUDE_DIR})
+
+enable_testing()
+
 if (CMAKE_C_COMPILER_ID MATCHES "Clang")
    message(STATUS "Using Clang and adding -Qunused-arguments flag")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Qunused-arguments")
@@ -93,13 +98,22 @@ set(GOST_ENGINE_SOURCE_FILES
         gost_md2012.c
         gost_pmeth.c)
 
+add_test(NAME engine
+        COMMAND perl run_tests
+        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/test)
+
+add_executable(test_grasshopper test_grasshopper.c)
+target_link_libraries(test_grasshopper gost_engine gost ${OPENSSL_CRYPTO_LIBRARY})
+add_test(NAME grasshopper
+       COMMAND test_grasshopper)
+
 add_library(gost STATIC ${GOST_LIB_SOURCE_FILES})
 set_target_properties(gost PROPERTIES POSITION_INDEPENDENT_CODE ON)
 
 add_library(gost_engine MODULE ${GOST_ENGINE_SOURCE_FILES})
 set_target_properties(gost_engine PROPERTIES PREFIX "" OUTPUT_NAME "gost")
 
-target_link_libraries(gost_engine crypto gost)
+target_link_libraries(gost_engine ${OPENSSL_CRYPTO_LIBRARY} gost)
 
 set(GOST_12_SUM_SOURCE_FILES
         gost12sum.c
diff --git a/test/00-engine.t b/test/00-engine.t
new file mode 100644 (file)
index 0000000..9104ab0
--- /dev/null
@@ -0,0 +1,88 @@
+#!/usr/bin/perl
+use Test::More tests => 7;
+use Cwd 'abs_path';
+
+# prepare data for 
+
+open F,">","testdata.dat";
+print F "12345670" x 128;
+close F;
+
+# Set OPENSSL_ENGINES environment variable to just built engine
+if(!defined $ENV{'OPENSSL_ENGINES'}){
+       $ENV{'OPENSSL_ENGINES'} = abs_path("../.libs");
+}
+
+$key='0123456789abcdef' x 2;
+
+#
+# You can redefine engine to use using ENGINE_NAME environment variable
+# 
+$engine=$ENV{'ENGINE_NAME'}||"gost";
+
+# Reopen STDERR to eliminate extra output
+open STDERR, ">>","tests.err";
+
+if (exists $ENV{'OPENSSL_CONF'}) {
+       delete $ENV{'OPENSSL_CONF'}
+}
+#
+# This test needs output of openssl engine -c command.
+# Default one  is hardcoded below, but you can place file
+# ${ENGINE_NAME}.info into this directory if you use this test suite
+# to test other engine implementing GOST cryptography.
+#
+if ( -f $engine . ".info") {
+       diag("Reading $engine.info");
+       open F, "<", $engine . ".info";
+       read F,$engine_info,1024;
+} else {
+
+$engine_info= <<EOINF;
+(gost) Reference implementation of GOST engine
+ [gost89, gost89-cnt, gost89-cnt-12, gost89-cbc, grasshopper-ecb, grasshopper-cbc, grasshopper-cfb, grasshopper-ofb, grasshopper-ctr, md_gost94, gost-mac, md_gost12_256, md_gost12_512, gost-mac-12, gost2001, gost-mac, gost2012_256, gost2012_512, gost-mac-12]
+EOINF
+}
+
+$ENV{'OPENSSL_CONF'}=abs_path("no_such_file.cfg");
+is(`openssl engine -c $engine`,
+$engine_info,
+"load engine without any config");
+
+is(`openssl dgst -engine $engine -md_gost94 testdata.dat`,
+"md_gost94(testdata.dat)= f7fc6d16a6a5c12ac4f7d320e0fd0d8354908699125e09727a4ef929122b1cae\n",
+"compute digest without config");
+
+
+open F,">","test.cnf";
+print F <<EOCFG;
+openssl_conf = openssl_def
+[openssl_def]
+engines = engines
+[engines]
+${engine}=gost_conf
+[gost_conf]
+default_algorithms = ALL
+
+EOCFG
+close F;
+$ENV{'OPENSSL_CONF'}=abs_path('test.cnf');
+
+is(`openssl engine -c $engine`,
+$engine_info,
+"load engine with config");
+
+is(`openssl dgst -md_gost94 testdata.dat`,
+"md_gost94(testdata.dat)= f7fc6d16a6a5c12ac4f7d320e0fd0d8354908699125e09727a4ef929122b1cae\n",
+"compute digest with config without explicit engine param");
+
+is(`openssl dgst -engine $engine -md_gost94 testdata.dat`,
+"md_gost94(testdata.dat)= f7fc6d16a6a5c12ac4f7d320e0fd0d8354908699125e09727a4ef929122b1cae\n",
+"compute digest with both config and explicit engine param");
+
+like(`openssl ciphers`, qr|GOST2001-GOST89-GOST89|, 'display GOST2001-GOST89-GOST89 cipher');
+
+like(`openssl ciphers`, qr|GOST2012-GOST8912-GOST8912|, 'display GOST2012-GOST8912-GOST8912 cipher');
+
+unlink('testdata.dat');
+unlink('test.cnf');
diff --git a/test/01-digest.t b/test/01-digest.t
new file mode 100644 (file)
index 0000000..3838fd2
--- /dev/null
@@ -0,0 +1,115 @@
+#!/usr/bin/perl 
+use Test::More tests => 16;
+use Cwd 'abs_path';
+
+# Set OPENSSL_ENGINES environment variable to just built engine
+if(!defined $ENV{'OPENSSL_ENGINES'}){
+        $ENV{'OPENSSL_ENGINES'} = abs_path("../.libs");
+}
+# Set engine name from environment to allow testing of different engines
+$engine=$ENV{'ENGINE_NAME'}||"gost";
+# Reopen STDERR to eliminate extra output
+open STDERR, ">>","tests.err";
+
+# prepare data for 
+
+open F,">","testm1.dat";
+print F "012345678901234567890123456789012345678901234567890123456789012";
+close F;
+is(`openssl dgst -engine ${engine} -md_gost12_256 testm1.dat`,
+"md_gost12_256(testm1.dat)= 9d151eefd8590b89daa6ba6cb74af9275dd051026bb149a452fd84e5e57b5500\n",
+"GOST R 34.11-2012 256bit example 1 from standard");
+
+is(`openssl dgst -engine ${engine} -md_gost12_512 testm1.dat`,
+"md_gost12_512(testm1.dat)= 1b54d01a4af5b9d5cc3d86d68d285462b19abc2475222f35c085122be4ba1ffa00ad30f8767b3a82384c6574f024c311e2a481332b08ef7f41797891c1646f48\n",
+"GOST R 34.11-2012 512bit example 1 from standard");
+
+unlink("testm1.dat");
+
+open F,">","testm2.dat";
+print F pack("H*","d1e520e2e5f2f0e82c20d1f2f0e8e1eee6e820e2edf3f6e82c20e2e5fef2fa20f120eceef0ff20f1f2f0e5ebe0ece820ede020f5f0e0e1f0fbff20efebfaeafb20c8e3eef0e5e2fb");
+close F;
+is(`openssl dgst -engine ${engine} -md_gost12_256 testm2.dat`,
+"md_gost12_256(testm2.dat)= 9dd2fe4e90409e5da87f53976d7405b0c0cac628fc669a741d50063c557e8f50\n",
+"GOST R 34.11-2012 256bit example 2 from standard");
+
+is(`openssl dgst -engine ${engine} -md_gost12_512 testm2.dat`,
+"md_gost12_512(testm2.dat)= 1e88e62226bfca6f9994f1f2d51569e0daf8475a3b0fe61a5300eee46d961376035fe83549ada2b8620fcd7c496ce5b33f0cb9dddc2b6460143b03dabac9fb28\n",
+"GOST R 34.11-2012 512bit example 2 from standard");
+
+unlink("testm2.dat");
+
+
+open F,">","testdata.dat";
+binmode F;
+print F "12345670" x 128;
+close F;
+is(`openssl dgst -engine ${engine} -md_gost94 testdata.dat`,
+"md_gost94(testdata.dat)= f7fc6d16a6a5c12ac4f7d320e0fd0d8354908699125e09727a4ef929122b1cae\n",
+"GOST R 34.11-94 1K ascii");
+
+is(`openssl dgst -engine ${engine} -md_gost12_256 testdata.dat`,
+"md_gost12_256(testdata.dat)= 1906512b86a1283c68cec8419e57113efc562a1d0e95d8f4809542900c416fe4\n",
+"GOST R 34.11-2012 256bit 1K ascii");
+
+is(`openssl dgst -engine ${engine} -md_gost12_512 testdata.dat`,
+"md_gost12_512(testdata.dat)= 283587e434864d0d4bea97c0fb10e2dd421572fc859304bdf6a94673d652c59049212bad7802b4fcf5eecc1f8fab569d60f2c20dbd789a7fe4efbd79d8137ee7\n",
+"GOST R 34.11-2012 512bit 1K ascii");
+
+unlink("testdata.dat");
+
+open F,">","testdata2.dat";
+binmode F;
+print F "\x00\x01\x02\x15\x84\x67\x45\x31" x 128;
+close F;
+
+is(`openssl dgst -engine ${engine} -md_gost94 testdata2.dat`,
+"md_gost94(testdata2.dat)= 69f529aa82d9344ab0fa550cdf4a70ecfd92a38b5520b1906329763e09105196\n",
+"GOST R 34.11-94 1K binary");
+
+is(`openssl dgst -engine ${engine} -md_gost12_256 testdata2.dat`,
+"md_gost12_256(testdata2.dat)= 2eb1306be3e490f18ff0e2571a077b3831c815c46c7d4fdf9e0e26de4032b3f3\n",
+"GOST R 34.11-2012 256bit 1K binary");
+
+is(`openssl dgst -engine ${engine} -md_gost12_512 testdata2.dat`,
+"md_gost12_512(testdata2.dat)= 55656e5bcf795b499031a7833cd7dc18fe10d4a47e15be545c6ab3f304a4fe411c4c39de5b1fc6844880111441e0b92bf1ec2fb7840453fe39a2b70ced461968\n",
+"GOST R 34.11-2012 512bit 1K binary");
+
+unlink("testdata2.dat");
+
+open F, ">","testdata3.dat";
+binmode F;
+print F substr("12345670" x 128,0,539);
+close F;
+
+is(`openssl dgst -engine ${engine} -md_gost94 testdata3.dat`,
+"md_gost94(testdata3.dat)= bd5f1e4b539c7b00f0866afdbc8ed452503a18436061747a343f43efe888aac9\n",
+"GOST R 34.11-94 539 bytes");
+
+is(`openssl dgst -engine ${engine} -md_gost12_256 testdata3.dat`,
+"md_gost12_256(testdata3.dat)= c98a17f9fadff78d08521e4179a7b2e6275f3b1da88339a3cb961a3514e5332e\n",
+"GOST R 34.11-2012 256bit 539 bytes");
+
+is(`openssl dgst -engine ${engine} -md_gost12_512 testdata3.dat`,
+"md_gost12_512(testdata3.dat)= d5ad93fbc9ed7abc1cf28d00827a052b40bea74b04c4fd753102c1bcf9f9dad5142887f8a4cceaa0d64a0a8291592413d6adb956b99138a0023e127ff37bdf08\n",
+"GOST R 34.11-2012 512bit 539 bytes");
+
+unlink "testdata3.dat";
+open F , ">","bigdata.dat";
+binmode F;
+print F  ("121345678" x 7 . "1234567\n") x 4096,"12345\n";
+close F;
+
+is(`openssl dgst -engine ${engine} -md_gost94 bigdata.dat`,
+"md_gost94(bigdata.dat)= e5d3ac4ea3f67896c51ff919cedb9405ad771e39f0f2eab103624f9a758e506f\n",
+"GOST R 34.11-94 128K");
+
+is(`openssl dgst -engine ${engine} -md_gost12_256 bigdata.dat`,
+"md_gost12_256(bigdata.dat)= 50e935d725d9359e5991b6b7eba8b3539fca03584d26adf4c827c982ffd49367\n",
+"GOST R 34.11-2012 256bit 128K");
+
+is(`openssl dgst -engine ${engine} -md_gost12_512 bigdata.dat`,
+"md_gost12_512(bigdata.dat)= 1d93645ebfbb477660f98b7d1598e37fbf3bfc8234ead26e2246e1b979e590ac46138158a692f9a0c9ac2550758b4d0d4c9fb8af5e595a16d3760c6516443f82\n",
+"GOST R 34.11-2012 512bit 128K");
+
+unlink "bigdata.dat";
diff --git a/test/02-mac.t b/test/02-mac.t
new file mode 100644 (file)
index 0000000..5713dca
--- /dev/null
@@ -0,0 +1,53 @@
+#!/usr/bin/perl 
+use Test::More tests => 19;
+use Cwd 'abs_path';
+
+# prepare data for 
+
+open F,">","testdata.dat";
+print F "12345670" x 128;
+close F;
+
+open F,">","testbig.dat";
+print F ("12345670" x 8 . "\n") x  4096;
+close F;
+# Set OPENSSL_ENGINES environment variable to just built engine
+if(!defined $ENV{'OPENSSL_ENGINES'}){
+        $ENV{'OPENSSL_ENGINES'} = abs_path("../.libs");
+}
+
+$key='0123456789abcdef' x 2;
+
+$engine=$ENV{'ENGINE_NAME'}||"gost";
+
+# Reopen STDERR to eliminate extra output
+open STDERR, ">>","tests.err";
+
+is(`openssl dgst -engine ${engine} -mac gost-mac -macopt key:${key} testdata.dat`,
+"GOST-MAC-gost-mac(testdata.dat)= 2ee8d13d\n",
+"GOST MAC - default size");
+
+for ($i=1;$i<=8; $i++) {
+       is(`openssl dgst -engine ${engine} -mac gost-mac -macopt key:${key} -sigopt size:$i testdata.dat`,
+"GOST-MAC-gost-mac(testdata.dat)= ".substr("2ee8d13dff7f037d",0,$i*2)."\n",
+"GOST MAC - size $i bytes");
+}
+
+
+
+is(`openssl dgst -engine ${engine} -mac gost-mac -macopt key:${key} testbig.dat`,
+"GOST-MAC-gost-mac(testbig.dat)= 5efab81f\n",
+"GOST MAC - big data");
+
+is(`openssl dgst -engine ${engine} -mac gost-mac-12 -macopt key:${key} testdata.dat`,
+"GOST-MAC-12-gost-mac-12(testdata.dat)= be4453ec\n",
+"GOST MAC - parameters 2012");
+
+
+for ($i=1;$i<=8; $i++) {
+       is(`openssl dgst -engine ${engine} -mac gost-mac-12 -macopt key:${key} -sigopt size:$i testdata.dat`,
+"GOST-MAC-12-gost-mac-12(testdata.dat)= ".substr("be4453ec1ec327be",0,$i*2)."\n",
+"GOST MAC parameters 2012 - size $i bytes");
+}
+unlink('testdata.dat');
+unlink('testbig.dat');
diff --git a/test/03-encrypt.t b/test/03-encrypt.t
new file mode 100644 (file)
index 0000000..d5b56c4
--- /dev/null
@@ -0,0 +1,161 @@
+#!/usr/bin/perl
+use Test::More tests => 48;
+use Cwd 'abs_path';
+
+#
+# If this variable is set, engine would be loaded via configuration
+# file. Otherwise - via command line
+# 
+$use_config = 1;
+
+# prepare data for 
+
+
+# Set OPENSSL_ENGINES environment variable to just built engine
+if(!defined $ENV{'OPENSSL_ENGINES'}){
+        $ENV{'OPENSSL_ENGINES'} = abs_path("../.libs");
+}
+
+$key='0123456789abcdef' x 2;
+
+#
+# You can redefine engine to use using ENGINE_NAME environment variable
+# 
+$engine=$ENV{'ENGINE_NAME'}||"gost";
+
+# Reopen STDERR to eliminate extra output
+open STDERR, ">>","tests.err";
+
+our $count=0;
+
+#
+# parameters -paramset = oid of the parameters
+# -cleartext - data to encrypt
+# -ciphertext - expected ciphertext (hex-encoded)
+# -key - key (hex-encoded)
+# -iv  - IV (hex-encoded)
+# 
+
+open F,">","test.cnf";
+if (defined($use_config) && $use_config) {
+       $eng_param = "";
+       open F,">","test.cnf";
+       print F <<EOCFG;
+openssl_conf = openssl_def
+[openssl_def]
+engines = engines
+[engines]
+${engine}=gost_conf
+[gost_conf]
+default_algorithms = ALL
+
+EOCFG
+} else {
+       $eng_param = "-engine $engine"
+}
+close F;
+$ENV{'OPENSSL_CONF'}=abs_path('test.cnf');
+       
+sub crypt_test {
+       my %p = @_;
+       our $count++;
+       open my $f, ">", "test$count.clear";
+       print $f $p{-cleartext};
+       close $f;
+       
+       $ENV{'CRYPT_PARAMS'} = $p{-paramset} if exists $p{-paramset};
+       my $ctext = `openssl enc ${eng_param} -e -$p{-alg} -K $p{-key} -iv $p{-iv} -in test$count.clear`;
+       is($?,0,"$p{-name} - encrypt successful");
+       is(unpack("H*",$ctext),$p{-ciphertext},"$p{-name} - ciphertext expected");
+       open my $f, ">", "test$count.enc";
+       print $f $ctext;
+       close $f;
+       my $otext = `openssl enc ${eng_param} -d -$p{-alg} -K $p{-key} -iv $p{-iv} -in test$count.enc`;
+       is($?,0,"$p{-name} - decrypt successful");
+       is($otext,$p{-cleartext},"$p{-name} - decrypted correctly");
+       unlink "test$count.enc";
+       unlink "test$count.clear";
+       delete $ENV{'CRYPT_PARAMS'};
+}
+
+$key = '0123456789ABCDEF' x 4;
+$iv =  '0000000000000000';
+$clear1 = "The quick brown fox jumps over the lazy dog\n";
+
+crypt_test(-paramset=> "1.2.643.2.2.31.1", -key => $key, -iv => $iv,
+                  -cleartext => $clear1,
+                  -ciphertext => '07f4102c6185c4a09e676e269bfa4bc9c5df6575916b879bd13a893a2285ee6690107cdeef7a315d2eb54bfa', 
+                  -alg => 'gost89',
+                  -name=> 'CFB short text, paramset A');
+
+crypt_test(-paramset=> "1.2.643.2.2.31.2", -key => $key, -iv => $iv,
+                  -cleartext => $clear1,
+                  -ciphertext => '11465c1c9708033e784fbb5536f2719c38353cb488b01f195c20d4c027022e8300d98bb66c138afbe878c88b', 
+                  -alg => 'gost89',
+                  -name=> 'CFB short text, paramset B');
+
+crypt_test(-paramset=> "1.2.643.2.2.31.3", -key => $key, -iv => $iv,
+                  -cleartext => $clear1,
+                  -ciphertext => '2f213b390c9b6ceb18de479686d23f4f03c76644a0aab8894b50b71a3bbb3c027ec4c2d569ba0e6a873bd46e', 
+                  -alg => 'gost89',
+                  -name=> 'CFB short text, paramset C');
+
+crypt_test(-paramset=> "1.2.643.2.2.31.4", -key => $key, -iv => $iv,
+                  -cleartext => $clear1,
+                  -ciphertext => 'e835f59a7fdfd84764efe1e987660327f5d0de187afea72f9cd040983a5e5bbeb4fe1aa5ff85d623ebc4d435', 
+                  -alg => 'gost89',
+                  -name=> 'CFB short text, paramset D');
+
+
+crypt_test(-paramset=> "1.2.643.2.2.31.1", -key => $key, -iv => $iv,
+                  -cleartext => $clear1,
+                  -ciphertext => 'bcb821452e459f10f92019171e7c3b27b87f24b174306667f67704812c07b70b5e7420f74a9d54feb4897df8', 
+                  -alg => 'gost89-cnt',
+                  -name=> 'CNT short text');
+
+crypt_test(-paramset=> "1.2.643.2.2.31.2", -key => $key, -iv => $iv,
+                  -cleartext => $clear1,
+                  -ciphertext => 'bcb821452e459f10f92019171e7c3b27b87f24b174306667f67704812c07b70b5e7420f74a9d54feb4897df8', 
+                  -alg => 'gost89-cnt',
+                  -name=> 'CNT short text, paramset param doesnt affect cnt');
+
+                  
+crypt_test(-paramset=> "1.2.643.2.2.31.1", -key => $key, -iv => $iv,
+                  -cleartext => $clear1,
+                  -ciphertext => 'cf3f5f713b3d10abd0c6f7bafb6aaffe13dfc12ef5c844f84873aeaaf6eb443a9747c9311b86f97ba3cdb5c4',
+                  -alg => 'gost89-cnt-12',
+                  -name=> 'CNT-12 short text');
+
+crypt_test(-paramset=> "1.2.643.2.2.31.2", -key => $key, -iv => $iv,
+                  -cleartext => $clear1,
+                  -ciphertext => 'cf3f5f713b3d10abd0c6f7bafb6aaffe13dfc12ef5c844f84873aeaaf6eb443a9747c9311b86f97ba3cdb5c4',
+                  -alg => 'gost89-cnt-12',
+                  -name=> 'CNT-12 short text, paramset param doesnt affect cnt');
+
+
+crypt_test(-paramset=> "1.2.643.2.2.31.1", -key => $key, -iv => $iv,
+                  -cleartext => $clear1,
+                  -ciphertext => '3a3293e75089376572da44966cd1759c29d2f1e5e1c3fa9674909a63026da3dc51a4266bff37fb74a3a07155c9ca8fcf', 
+                  -alg => 'gost89-cbc',
+                  -name=> 'CBC short text, paramset A');
+
+
+crypt_test(-paramset=> "1.2.643.2.2.31.2", -key => $key, -iv => $iv,
+                  -cleartext => $clear1,
+                  -ciphertext => 'af2a2167b75852378af176ac9950e3c4bffc94d3d4355191707adbb16d6c8e3f3a07868c4702babef18393edfac60a6d', 
+                  -alg => 'gost89-cbc',
+                  -name=> 'CBC short text, paramset B');
+
+crypt_test(-paramset=> "1.2.643.2.2.31.3", -key => $key, -iv => $iv,
+                  -cleartext => $clear1,
+                  -ciphertext => '987c0fb3d84530467a1973791e0a25e33c5d14591976f8c1573bdb9d056eb7b353f66fef3ffe2e3524583b3997123c8a', 
+                  -alg => 'gost89-cbc',
+                  -name=> 'CBC short text, paramset C');
+
+crypt_test(-paramset=> "1.2.643.2.2.31.4", -key => $key, -iv => $iv,
+                  -cleartext => $clear1,
+                  -ciphertext => 'e076b09822d4786a2863125d16594d765d8acd0f360e52df42e9d52c8e6c0e6595b5f6bbecb04a22c8ae5f4f87c1523b', 
+                  -alg => 'gost89-cbc',
+                  -name=> 'CBC short text, paramset D');
+
+unlink "test.cnf";
diff --git a/test/04-pkey.t b/test/04-pkey.t
new file mode 100644 (file)
index 0000000..84ae81e
--- /dev/null
@@ -0,0 +1,163 @@
+#!/usr/bin/perl
+use Test::More tests => 15;
+use Cwd 'abs_path';
+
+#
+# If this variable is set, engine would be loaded via configuration
+# file. Otherwise - via command line
+# 
+$use_config = 1;
+
+# prepare data for 
+
+
+# Set OPENSSL_ENGINES environment variable to just built engine
+if(!defined $ENV{'OPENSSL_ENGINES'}){
+        $ENV{'OPENSSL_ENGINES'} = abs_path("../.libs");
+}
+
+$engine=$ENV{'ENGINE_NAME'}||"gost";
+
+# Reopen STDERR to eliminate extra output
+open STDERR, ">>","tests.err";
+
+
+open F,">","test.cnf";
+if (defined($use_config) && $use_config) {
+       $eng_param = "";
+       open F,">","test.cnf";
+       print F <<EOCFG;
+openssl_conf = openssl_def
+[openssl_def]
+engines = engines
+[engines]
+${engine}=gost_conf
+[gost_conf]
+default_algorithms = ALL
+
+EOCFG
+} else {
+       $eng_param = "-engine $engine"
+}
+close F;
+$ENV{'OPENSSL_CONF'}=abs_path('test.cnf');
+
+
+@keys=(['gost2001','A',"-----BEGIN PRIVATE KEY-----
+MEUCAQAwHAYGKoUDAgITMBIGByqFAwICIwEGByqFAwICHgEEIgIgRhUDJ1WQASIf
+nx+aUM2eagzV9dCt6mQ5wdtenr2ZS/Y=
+-----END PRIVATE KEY-----
+","Private key: 46150327559001221F9F1F9A50CD9E6A0CD5F5D0ADEA6439C1DB5E9EBD994BF6
+","Public key:
+   X:789094AF6386A43AF191210FFED0AEA5D1D9750D8FF8BCD1B584BFAA966850E4
+   Y:25ED63EE42624403D08FC60E5F8130F121ECDC5E297D9E3C7B106C906E0855E9
+Parameter set: id-GostR3410-2001-CryptoPro-A-ParamSet
+","-----BEGIN PUBLIC KEY-----
+MGMwHAYGKoUDAgITMBIGByqFAwICIwEGByqFAwICHgEDQwAEQORQaJaqv4S10bz4
+jw112dGlrtD+DyGR8TqkhmOvlJB46VUIbpBsEHs8nn0pXtzsIfEwgV8Oxo/QA0Ri
+Qu5j7SU=
+-----END PUBLIC KEY-----
+"],
+['gost2001','B'=>'-----BEGIN PRIVATE KEY-----
+MEUCAQAwHAYGKoUDAgITMBIGByqFAwICIwIGByqFAwICHgEEIgIgImwnCcqcfuXK
+MVYg+UWQhiXYKz1yQ8kDSB7Ly515XH4=
+-----END PRIVATE KEY-----
+','Private key: 226C2709CA9C7EE5CA315620F945908625D82B3D7243C903481ECBCB9D795C7E
+','Public key:
+   X:59C15439385CBE790274D6537D318A35B27413D265FFDC5FBE5354DF8C7AC591
+   Y:11B771AC016AA817542184D05F2C7DDD0F9A5A5C9F840A79B5B7A73658F3048A
+Parameter set: id-GostR3410-2001-CryptoPro-B-ParamSet
+','-----BEGIN PUBLIC KEY-----
+MGMwHAYGKoUDAgITMBIGByqFAwICIwIGByqFAwICHgEDQwAEQJHFeozfVFO+X9z/
+ZdITdLI1ijF9U9Z0Anm+XDg5VMFZigTzWDant7V5CoSfXFqaD919LF/QhCFUF6hq
+AaxxtxE=
+-----END PUBLIC KEY-----
+'],
+['gost2001','C'=>'-----BEGIN PRIVATE KEY-----
+MEUCAQAwHAYGKoUDAgITMBIGByqFAwICIwMGByqFAwICHgEEIgIgKKUJVY2xlp24
+mky1F9inWeq3mm0J/uza6HsDvspgSzY=
+-----END PRIVATE KEY-----
+','Private key: 28A509558DB1969DB89A4CB517D8A759EAB79A6D09FEECDAE87B03BECA604B36
+','Public key:
+   X:58154320380CCFD2A101D2B7844516984023CF5A38610C4F98220E017270B2D4
+   Y:14C6977A6E9C0412DF5B53E69CD48DAF2B5805F55F6ACBEB4E01BA7B2BF84FC8
+Parameter set: id-GostR3410-2001-CryptoPro-C-ParamSet
+','-----BEGIN PUBLIC KEY-----
+MGMwHAYGKoUDAgITMBIGByqFAwICIwMGByqFAwICHgEDQwAEQNSycHIBDiKYTwxh
+OFrPI0CYFkWEt9IBodLPDDggQxVYyE/4K3u6AU7ry2pf9QVYK6+N1JzmU1vfEgSc
+bnqXxhQ=
+-----END PUBLIC KEY-----
+'],
+['gost2001','XA'=>,'-----BEGIN PRIVATE KEY-----
+MEUCAQAwHAYGKoUDAgITMBIGByqFAwICJAAGByqFAwICHgEEIgIgOFuMMveKUx/C
+BOSjl9XCepDCHWHv/1bcjdKexKGJkZw=
+-----END PRIVATE KEY-----
+','Private key: 385B8C32F78A531FC204E4A397D5C27A90C21D61EFFF56DC8DD29EC4A189919C
+','Public key:
+   X:FA969CB29310E897978A1C9245107B46499D5C14A3975BF8E10EF5F613BE4EC6
+   Y:17FCFACCB0F838AE730E8B4021E880937824214DFF5365A61576AC5E72F92E35
+Parameter set: id-GostR3410-2001-CryptoPro-XchA-ParamSet
+','-----BEGIN PUBLIC KEY-----
+MGMwHAYGKoUDAgITMBIGByqFAwICJAAGByqFAwICHgEDQwAEQMZOvhP29Q7h+FuX
+oxRcnUlGexBFkhyKl5foEJOynJb6NS75cl6sdhWmZVP/TSEkeJOA6CFAiw5zrjj4
+sMz6/Bc=
+-----END PUBLIC KEY-----
+'],
+['gost2001','XB'=>,'-----BEGIN PRIVATE KEY-----
+MEUCAQAwHAYGKoUDAgITMBIGByqFAwICJAEGByqFAwICHgEEIgIgE7WWqiYWoKLs
+7ezZ8L8Q9JcT73Jf5NYfFnlnoKRIQGg=
+-----END PRIVATE KEY-----
+','Private key: 13B596AA2616A0A2ECEDECD9F0BF10F49713EF725FE4D61F167967A0A4484068
+','Public key:
+   X:1D33A01774E501EFADD6C7A936728AF644749E98FEF5AE77A25E185955ED2E14
+   Y:FAD2D8101A99EDE8FBDF118B70A9894F4E6DE962B68D27E39B057624A51727
+Parameter set: id-GostR3410-2001-CryptoPro-XchB-ParamSet
+','-----BEGIN PUBLIC KEY-----
+MGMwHAYGKoUDAgITMBIGByqFAwICJAEGByqFAwICHgEDQwAEQBQu7VVZGF6id671
+/piedET2inI2qcfWre8B5XQXoDMdJxelJHYFm+MnjbZi6W1OT4mpcIsR3/vo7Zka
+ENjS+gA=
+-----END PUBLIC KEY-----
+']
+);
+for $keyinfo (@keys) {
+       my ($alg,$paramset,$seckey,$sectext,$pubtext,$pubkey) = @$keyinfo;
+       open F,">",'tmp.pem';
+       print F $seckey;
+       close F;
+       #1.  Прочитать секретный ключ и напечатать публичный и секретный ключи
+       is(`openssl pkey -noout -text -in tmp.pem`,$sectext . $pubtext,
+               "Print key pair $alg:$paramset");
+       #2. Прочитать секретный ключ и вывести публичный (все алгоритмы)
+    is(`openssl pkey -pubout -in tmp.pem`,$pubkey,
+               "Compute public key $alg:$paramset");
+       open F,">","tmp.pem";
+       print F $pubkey;
+       close F;
+       #3. Прочитать публичный и напечать его в виде текста
+       is(`openssl pkey -pubin -noout -in tmp.pem -text`,$pubtext,
+               "Read and print public key $alg:paramset");
+
+}
+unlink "tmp.pem";
+#4. Сгенерировать ключ два раза (для всех алгоритов и параметров).
+# Проверить что получились числа требуемой длины и они не совпадают
+
+
+#5. Проверить эталонную подпись
+
+#6. Выработать подпись и проверить её
+
+#7. Выработать подпись, поменять в ней один бит и убедиться что она
+# перестала проверяться
+
+# 8. Выработать подпись, поменять 1 бит в подписываемых данных и
+# убедитсья, что подпись перестала быть корректной.
+
+# 9. Выработать shared ключ по vko
+
+# 10. Разобрать стандартый encrypted key
+
+# 11. Сгенерирвоать encrypted key и его разобрать.
+
+unlink "test.cnf";
+
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644 (file)
index 0000000..2a00f54
--- /dev/null
@@ -0,0 +1,4 @@
+PERL=@PERL@
+
+test: 
+       $(PERL) ./run_tests
diff --git a/test/run_tests b/test/run_tests
new file mode 100644 (file)
index 0000000..3578d0a
--- /dev/null
@@ -0,0 +1,5 @@
+#!/usr/bin/perl
+use TAP::Harness;
+
+my $harness = TAP::Harness->new();
+exit ($harness->runtests(glob("*.t"))->all_passed() ? 0 : 1);
diff --git a/test_grasshopper.c b/test_grasshopper.c
new file mode 100644 (file)
index 0000000..19e18bf
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2018 vt@altlinux.org. All Rights Reserved.
+ *
+ * Contents licensed under the terms of the OpenSSL license
+ * See https://www.openssl.org/source/license.html for details
+ */
+
+#include "gost_grasshopper_cipher.h"
+#include "gost_grasshopper_defines.h"
+#include "gost_grasshopper_math.h"
+#include "gost_grasshopper_core.h"
+#include "e_gost_err.h"
+#include "gost_lcl.h"
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#include <openssl/asn1.h>
+#include <string.h>
+
+#define T(e) if (!(e)) {\
+       ERR_print_errors_fp(stderr);\
+       OpenSSLDie(__FILE__, __LINE__, #e);\
+    }
+
+#define cRED   "\033[1;31m"
+#define cDRED  "\033[0;31m"
+#define cGREEN "\033[1;32m"
+#define cDGREEN        "\033[0;32m"
+#define cNORM  "\033[m"
+#define TEST_ASSERT(e) {if ((test = (e))) \
+                printf(cRED "Test FAILED\n" cNORM); \
+            else \
+                printf(cGREEN "Test passed\n" cNORM);}
+
+/* Test key from both GOST R 34.12-2015 and GOST R 34.13-2015. */
+static const unsigned char K[] = {
+    0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
+    0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
+};
+
+/* Plaintext from GOST R 34.13-2015 A.1.
+ * First 16 bytes is vector (a) from GOST R 34.12-2015 A.1. */
+static const unsigned char P[] = {
+    0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x00,0xff,0xee,0xdd,0xcc,0xbb,0xaa,0x99,0x88,
+    0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xee,0xff,0x0a,
+    0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xee,0xff,0x0a,0x00,
+    0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xee,0xff,0x0a,0x00,0x11,
+};
+static const unsigned char E_ecb[] = {
+    /* ECB test vectors from GOST R 34.13-2015  A.1.1 */
+    /* first 16 bytes is vector (b) from GOST R 34.12-2015 A.1 */
+    0x7f,0x67,0x9d,0x90,0xbe,0xbc,0x24,0x30,0x5a,0x46,0x8d,0x42,0xb9,0xd4,0xed,0xcd,
+    0xb4,0x29,0x91,0x2c,0x6e,0x00,0x32,0xf9,0x28,0x54,0x52,0xd7,0x67,0x18,0xd0,0x8b,
+    0xf0,0xca,0x33,0x54,0x9d,0x24,0x7c,0xee,0xf3,0xf5,0xa5,0x31,0x3b,0xd4,0xb1,0x57,
+    0xd0,0xb0,0x9c,0xcd,0xe8,0x30,0xb9,0xeb,0x3a,0x02,0xc4,0xc5,0xaa,0x8a,0xda,0x98,
+};
+static const unsigned char E_ctr[] = {
+    /* CTR test vectors from GOST R 34.13-2015  A.1.2 */
+    0xf1,0x95,0xd8,0xbe,0xc1,0x0e,0xd1,0xdb,0xd5,0x7b,0x5f,0xa2,0x40,0xbd,0xa1,0xb8,
+    0x85,0xee,0xe7,0x33,0xf6,0xa1,0x3e,0x5d,0xf3,0x3c,0xe4,0xb3,0x3c,0x45,0xde,0xe4,
+    0xa5,0xea,0xe8,0x8b,0xe6,0x35,0x6e,0xd3,0xd5,0xe8,0x77,0xf1,0x35,0x64,0xa3,0xa5,
+    0xcb,0x91,0xfa,0xb1,0xf2,0x0c,0xba,0xb6,0xd1,0xc6,0xd1,0x58,0x20,0xbd,0xba,0x73,
+};
+/*
+ * Other modes (ofb, cbc, cfb) is impossible to test to match GOST R
+ * 34.13-2015 test vectors exactly, due to these vectors having exceeding
+ * IV length value (m) = 256 bits, while openssl have hard-coded limit
+ * of maximum IV length of 128 bits (EVP_MAX_IV_LENGTH).
+ * Also, current grasshopper code having fixed IV length of 128 bits.
+ *
+ * Thus, new test vectors are generated with truncated 128-bit IV using
+ * canonical GOST implementation from TC26.
+ */
+static const unsigned char E_ofb[] = {
+    /* OFB test vector generated from canonical implementation */
+    0x81,0x80,0x0a,0x59,0xb1,0x84,0x2b,0x24,0xff,0x1f,0x79,0x5e,0x89,0x7a,0xbd,0x95,
+    0x77,0x91,0x46,0xdb,0x2d,0x93,0xa9,0x4e,0xd9,0x3c,0xf6,0x8b,0x32,0x39,0x7f,0x19,
+    0xe9,0x3c,0x9e,0x57,0x44,0x1d,0x87,0x05,0x45,0xf2,0x40,0x36,0xa5,0x8c,0xee,0xa3,
+    0xcf,0x3f,0x00,0x61,0xd5,0x64,0x23,0x54,0x5b,0x96,0x0d,0x86,0x4c,0xc8,0x68,0xda,
+};
+static const unsigned char E_cbc[] = {
+    /* CBC test vector generated from canonical implementation */
+    0x68,0x99,0x72,0xd4,0xa0,0x85,0xfa,0x4d,0x90,0xe5,0x2e,0x3d,0x6d,0x7d,0xcc,0x27,
+    0xab,0xf1,0x70,0xb2,0xb2,0x26,0xc3,0x01,0x0c,0xcf,0xa1,0x36,0xd6,0x59,0xcd,0xaa,
+    0xca,0x71,0x92,0x72,0xab,0x1d,0x43,0x8e,0x15,0x50,0x7d,0x52,0x1e,0xcd,0x55,0x22,
+    0xe0,0x11,0x08,0xff,0x8d,0x9d,0x3a,0x6d,0x8c,0xa2,0xa5,0x33,0xfa,0x61,0x4e,0x71,
+};
+static const unsigned char E_cfb[] = {
+    /* CFB test vector generated from canonical implementation */
+    0x81,0x80,0x0a,0x59,0xb1,0x84,0x2b,0x24,0xff,0x1f,0x79,0x5e,0x89,0x7a,0xbd,0x95,
+    0x68,0xc1,0xb9,0x9c,0x4d,0xf5,0x9c,0xc7,0x95,0x1e,0x37,0x39,0xb5,0xb3,0xcd,0xbf,
+    0x07,0x3f,0x4d,0xd2,0xd6,0xde,0xb3,0xcf,0xb0,0x26,0x54,0x5f,0x7a,0xf1,0xd8,0xe8,
+    0xe1,0xc8,0x52,0xe9,0xa8,0x56,0x71,0x62,0xdb,0xb5,0xda,0x7f,0x66,0xde,0xa9,0x26,
+};
+
+static const unsigned char iv_ctr[]    = { 0x12,0x34,0x56,0x78,0x90,0xab,0xce,0xf0, 0,0,0,0,0,0,0,0 };
+/* truncated to 128-bits IV */
+static const unsigned char iv_128bit[] = { 0x12,0x34,0x56,0x78,0x90,0xab,0xce,0xf0,
+                                           0xa1,0xb2,0xc3,0xd4,0xe5,0xf0,0x01,0x12 };
+struct testcase {
+    const char *name;
+    const EVP_CIPHER *(*type)(void);
+    int stream;
+    const unsigned char *plaintext;
+    const unsigned char *expected;
+    size_t size;
+    const unsigned char *iv;
+    size_t iv_size;
+    int acpkm;
+};
+static struct testcase testcases[] = {
+    { "ecb", cipher_gost_grasshopper_ecb, 0, P,  E_ecb,  sizeof(P),  NULL,       0, 0 },
+    { "ctr", cipher_gost_grasshopper_ctr, 1, P,  E_ctr,  sizeof(P),  iv_ctr,     sizeof(iv_ctr), 0 },
+    { "ofb", cipher_gost_grasshopper_ofb, 1, P,  E_ofb,  sizeof(P),  iv_128bit,  sizeof(iv_128bit), 0 },
+    { "cbc", cipher_gost_grasshopper_cbc, 0, P,  E_cbc,  sizeof(P),  iv_128bit,  sizeof(iv_128bit), 0 },
+    { "cfb", cipher_gost_grasshopper_cfb, 0, P,  E_cfb,  sizeof(P),  iv_128bit,  sizeof(iv_128bit), 0 },
+    NULL
+};
+
+static void hexdump(const void *ptr, size_t len)
+{
+    const unsigned char *p = ptr;
+    size_t i, j;
+
+    for (i = 0; i < len; i += j) {
+       for (j = 0; j < 16 && i + j < len; j++)
+           printf("%s%02x", j? "" : " ", p[i + j]);
+    }
+    printf("\n");
+}
+
+static int test_block(const EVP_CIPHER *type, const char *name,
+    const unsigned char *pt, const unsigned char *exp, size_t size,
+    const unsigned char *iv, size_t iv_size, int acpkm)
+{
+    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+    unsigned char c[size];
+    int outlen, tmplen;
+    int ret = 0, test;
+
+    OPENSSL_assert(ctx);
+    printf("Encryption test from GOST R 34.13-2015 [%s] \n", name);
+    /* test with single big chunk */
+    EVP_CIPHER_CTX_init(ctx);
+    T(EVP_CipherInit_ex(ctx, type, NULL, K, iv, 1));
+    T(EVP_CIPHER_CTX_set_padding(ctx, 0));
+    memset(c, 0, sizeof(c));
+    if (acpkm)
+       T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, 256 / 8, NULL));
+    T(EVP_CipherUpdate(ctx, c, &outlen, pt, size));
+    T(EVP_CipherFinal_ex(ctx, c + outlen, &tmplen));
+    EVP_CIPHER_CTX_cleanup(ctx);
+    printf("  c[%d] = ", outlen);
+    hexdump(c, outlen);
+
+    TEST_ASSERT(outlen != size || memcmp(c, exp, size));
+    ret |= test;
+
+    /* test with small chunks of block size */
+    printf("Chunked encryption test from GOST R 34.13-2015 [%s] \n", name);
+    int blocks = size / GRASSHOPPER_BLOCK_SIZE;
+    int z;
+    EVP_CIPHER_CTX_init(ctx);
+    T(EVP_CipherInit_ex(ctx, type, NULL, K, iv, 1));
+    T(EVP_CIPHER_CTX_set_padding(ctx, 0));
+    memset(c, 0, sizeof(c));
+    if (acpkm)
+       T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, 256 / 8, NULL));
+    for (z = 0; z < blocks; z++) {
+       int offset = z * GRASSHOPPER_BLOCK_SIZE;
+       int sz = GRASSHOPPER_BLOCK_SIZE;
+
+       T(EVP_CipherUpdate(ctx, c + offset, &outlen, pt + offset, sz));
+    }
+    outlen = z * GRASSHOPPER_BLOCK_SIZE;
+    T(EVP_CipherFinal_ex(ctx, c + outlen, &tmplen));
+    EVP_CIPHER_CTX_cleanup(ctx);
+    printf("  c[%d] = ", outlen);
+    hexdump(c, outlen);
+
+    TEST_ASSERT(outlen != size || memcmp(c, exp, size));
+    ret |= test;
+
+    /* test with single big chunk */
+    printf("Decryption test from GOST R 34.13-2015 [%s] \n", name);
+    EVP_CIPHER_CTX_init(ctx);
+    T(EVP_CipherInit_ex(ctx, type, NULL, K, iv, 0));
+    T(EVP_CIPHER_CTX_set_padding(ctx, 0));
+    memset(c, 0, sizeof(c));
+    if (acpkm)
+       T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, 256 / 8, NULL));
+    T(EVP_CipherUpdate(ctx, c, &outlen, exp, size));
+    T(EVP_CipherFinal_ex(ctx, c + outlen, &tmplen));
+    EVP_CIPHER_CTX_cleanup(ctx);
+    EVP_CIPHER_CTX_free(ctx);
+    printf("  d[%d] = ", outlen);
+    hexdump(c, outlen);
+
+    TEST_ASSERT(outlen != size || memcmp(c, pt, size));
+    ret |= test;
+
+    return ret;
+}
+
+static int test_stream(const EVP_CIPHER *type, const char *name,
+    const unsigned char *pt, const unsigned char *exp, size_t size,
+    const unsigned char *iv, size_t iv_size, int acpkm)
+{
+    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+    int ret = 0, test;
+    int z;
+
+    OPENSSL_assert(ctx);
+    /* Cycle through all lengths from 1 upto maximum size */
+    printf("Stream encryption test from GOST R 34.13-2015 [%s] \n", name);
+    for (z = 1; z <= size; z++) {
+       unsigned char c[size];
+       int outlen, tmplen;
+       int sz = 0;
+       int i;
+
+       EVP_CIPHER_CTX_init(ctx);
+       EVP_CipherInit_ex(ctx, type, NULL, K, iv, 1);
+       EVP_CIPHER_CTX_set_padding(ctx, 0);
+       memset(c, 0xff, sizeof(c));
+       if (acpkm)
+           T(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_KEY_MESH, 256 / 8, NULL));
+       for (i = 0; i < size; i += z) {
+           if (i + z > size)
+               sz = size - i;
+           else
+               sz = z;
+           EVP_CipherUpdate(ctx, c + i, &outlen, pt + i, sz);
+           OPENSSL_assert(outlen == sz);
+       }
+       outlen = i - z + sz;
+       EVP_CipherFinal_ex(ctx, c + outlen, &tmplen);
+       EVP_CIPHER_CTX_cleanup(ctx);
+
+       test = outlen != size || memcmp(c, exp, size);
+       printf("%c", test ? 'E' : '+');
+       ret |= test;
+    }
+    printf("\n");
+    TEST_ASSERT(ret);
+    EVP_CIPHER_CTX_free(ctx);
+
+    return ret;
+}
+
+int main(int argc, char **argv)
+{
+    int ret = 0;
+    const struct testcase *t;
+
+    for (t = testcases; t->name; t++) {
+       ret |= test_block(t->type(), t->name,
+           t->plaintext, t->expected, t->size,
+           t->iv, t->iv_size, t->acpkm);
+       if (t->stream)
+           ret |= test_stream(t->type(), t->name,
+               t->plaintext, t->expected, t->size,
+               t->iv, t->iv_size, t->acpkm);
+    }
+
+    if (ret)
+       printf(cDRED "= Some tests FAILED!\n" cNORM);
+    else
+       printf(cDGREEN "= All tests passed!\n" cNORM);
+    return ret;
+}