Skip to content

Commit

Permalink
fipsoracle: Add cavp_tdes_test (KAT mode only).
Browse files Browse the repository at this point in the history
Change-Id: I560051d554760feab8b432de429ccbef7bc19c0a
Reviewed-on: https://boringssl-review.googlesource.com/15684
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
  • Loading branch information
kreichgauer authored and CQ bot account: commit-bot@chromium.org committed May 1, 2017
1 parent 5c38c05 commit 2b2676f
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 13 deletions.
15 changes: 11 additions & 4 deletions crypto/test/file_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ FileTest::ReadResult FileTest::ReadNext() {
std::unique_ptr<char[]> buf(new char[kBufLen]);

bool in_instruction_block = false;
is_at_new_instruction_block_ = false;

while (true) {
// Read the next line.
Expand Down Expand Up @@ -137,6 +138,7 @@ FileTest::ReadResult FileTest::ReadNext() {
// comment because the FIPS lab's request files are hopelessly
// inconsistent.
} else if (buf[0] == '[') { // Inside an instruction block.
is_at_new_instruction_block_ = true;
if (start_line_ != 0) {
// Instructions should be separate blocks.
fprintf(stderr, "Line %u is an instruction in a test case.\n", line_);
Expand Down Expand Up @@ -170,11 +172,12 @@ FileTest::ReadResult FileTest::ReadNext() {
kv = kv.substr(idx + 1);
}
} else {
// Parsing a test case.
if (in_instruction_block) {
// Test cases should be separate blocks.
fprintf(stderr, "Line %u is a test case attribute in an instruction block.\n",
line_);
return kReadError;
// Some NIST CAVP test files (TDES) have a test case immediately
// following an instruction block, without a separate blank line, some
// of the time.
in_instruction_block = false;
}

current_test_ += std::string(buf.get(), len);
Expand Down Expand Up @@ -360,6 +363,10 @@ void FileTest::OnInstructionUsed(const std::string &key) {
unused_instructions_.erase(key);
}

bool FileTest::IsAtNewInstructionBlock() const {
return is_at_new_instruction_block_;
}

void FileTest::SetIgnoreUnusedAttributes(bool ignore) {
ignore_unused_attributes_ = ignore;
}
Expand Down
6 changes: 6 additions & 0 deletions crypto/test/file_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ class FileTest {
bool ExpectBytesEqual(const uint8_t *expected, size_t expected_len,
const uint8_t *actual, size_t actual_len);

// AtNewInstructionBlock returns true if the current test was immediately
// preceded by an instruction block.
bool IsAtNewInstructionBlock() const;

// HasInstruction returns true if the current test has an instruction.
bool HasInstruction(const std::string &key);

Expand Down Expand Up @@ -185,6 +189,8 @@ class FileTest {

std::string current_test_;

bool is_at_new_instruction_block_ = false;

bool ignore_unused_attributes_ = false;

FileTest(const FileTest &) = delete;
Expand Down
18 changes: 10 additions & 8 deletions fipsoracle/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,14 @@ if (FIPS)
cavp_hmac_test

cavp_hmac_test.cc
cavp_test_util.h
cavp_test_util.cc
$<TARGET_OBJECTS:test_support>
)

add_executable(
cavp_tdes_test

cavp_tdes_test.cc
cavp_test_util.cc
$<TARGET_OBJECTS:test_support>
)
Expand All @@ -62,7 +69,6 @@ if (FIPS)
cavp_sha_test

cavp_sha_test.cc
cavp_test_util.h
cavp_test_util.cc
$<TARGET_OBJECTS:test_support>
)
Expand All @@ -71,7 +77,6 @@ if (FIPS)
cavp_sha_monte_test

cavp_sha_monte_test.cc
cavp_test_util.h
cavp_test_util.cc
$<TARGET_OBJECTS:test_support>
)
Expand All @@ -87,16 +92,13 @@ if (FIPS)

target_link_libraries(cavp_aes_test crypto)
target_link_libraries(cavp_aes_gcm_test crypto)

target_link_libraries(cavp_ctr_drbg_test crypto)
target_link_libraries(cavp_ecdsa2_keypair_test crypto)
target_link_libraries(cavp_ecdsa2_pkv_test crypto)
target_link_libraries(cavp_ecdsa2_siggen_test crypto)
target_link_libraries(cavp_ecdsa2_sigver_test crypto)

target_link_libraries(cavp_hmac_test crypto)

target_link_libraries(cavp_sha_test crypto)
target_link_libraries(cavp_sha_monte_test crypto)

target_link_libraries(cavp_ctr_drbg_test crypto)
target_link_libraries(cavp_tdes_test crypto)
endif()
164 changes: 164 additions & 0 deletions fipsoracle/cavp_tdes_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/* Copyright (c) 2017, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */

// cavp_tdes_test processes a NIST TMOVS test vector request file and emits the
// corresponding response. An optional sample vector file can be passed to
// verify the result.

#include <stdlib.h>

#include <openssl/cipher.h>
#include <openssl/crypto.h>
#include <openssl/err.h>

#include "../crypto/test/file_test.h"
#include "cavp_test_util.h"


struct TestCtx {
const EVP_CIPHER *cipher;
std::unique_ptr<FileTest> response_sample;
enum Mode {
kKAT, // Known Answer Test
kMCT, // Monte Carlo Test
kMMT, // Multi Message Test
};
bool has_iv;
Mode mode;
};

static bool TestKAT(FileTest *t, void *arg) {
TestCtx *ctx = reinterpret_cast<TestCtx *>(arg);

if (t->HasInstruction("ENCRYPT") == t->HasInstruction("DECRYPT")) {
t->PrintLine("Want either ENCRYPT or DECRYPT");
return false;
}
enum {
kEncrypt,
kDecrypt,
} operation = t->HasInstruction("ENCRYPT") ? kEncrypt : kDecrypt;

std::string count;
std::vector<uint8_t> key, iv, in, result;
const std::string op_label = operation == kEncrypt ? "PLAINTEXT" : "CIPHERTEXT";
if (!t->GetAttribute(&count, "COUNT") ||
!t->GetBytes(&key, "KEYs") ||
(ctx->has_iv && !t->GetBytes(&iv, "IV")) ||
!t->GetBytes(&in, op_label)) {
return false;
}
std::vector<uint8_t> triple_key(key);
triple_key.insert(triple_key.end(), key.begin(), key.end());
triple_key.insert(triple_key.end(), key.begin(), key.end());

const EVP_CIPHER *cipher = ctx->cipher;

if (!CipherOperation(cipher, &result, operation == kEncrypt, triple_key, iv,
in)) {
return false;
}
const std::string result_label =
operation == kEncrypt ? "CIPHERTEXT" : "PLAINTEXT";

// TDES fax files output format differs from its input format, so we
// construct it manually rather than printing CurrentTestToString().
if (t->IsAtNewInstructionBlock()) {
std::string header = operation == kEncrypt ? "[ENCRYPT]" : "[DECRYPT]";
printf("%s\r\n", header.c_str());
}
printf("COUNT = %s\r\nKEYs = %s\r\n", count.c_str(),
EncodeHex(key.data(), key.size()).c_str());
if (ctx->has_iv) {
printf("IV = %s\r\n", EncodeHex(iv.data(), iv.size()).c_str());
}
printf("%s = %s\r\n%s = %s\r\n\r\n", op_label.c_str(),
EncodeHex(in.data(), in.size()).c_str(), result_label.c_str(),
EncodeHex(result.data(), result.size()).c_str());

// Check if sample response file matches.
if (ctx->response_sample) {
if (ctx->response_sample->ReadNext() != FileTest::kReadSuccess) {
t->PrintLine("invalid sample file");
return false;
}
std::string expected_count;
std::vector<uint8_t> expected_result;
if (!ctx->response_sample->GetAttribute(&expected_count, "COUNT") ||
count != expected_count ||
(!ctx->response_sample->GetBytes(&expected_result, result_label)) ||
!t->ExpectBytesEqual(expected_result.data(), expected_result.size(),
result.data(), result.size())) {
t->PrintLine("result doesn't match");
return false;
}
}

return true;
}

static int usage(char *arg) {
fprintf(
stderr,
"usage: %s (kat|mct|mmt) <cipher> <test file> [<sample response file>]\n",
arg);
return 1;
}

int main(int argc, char **argv) {
CRYPTO_library_init();

if (argc < 4 || argc > 5) {
return usage(argv[0]);
}

const std::string tm(argv[1]);
enum TestCtx::Mode test_mode;
if (tm == "kat") {
test_mode = TestCtx::kKAT;
} else if (tm == "mmt") {
test_mode = TestCtx::kMMT;
} else if (tm == "mct") {
test_mode = TestCtx::kMCT;
} else {
fprintf(stderr, "invalid test_mode: %s\n", tm.c_str());
return usage(argv[0]);
}

const std::string cipher_name(argv[2]);
const EVP_CIPHER *cipher = GetCipher(argv[2]);
if (cipher == nullptr) {
fprintf(stderr, "invalid cipher: %s\n", argv[2]);
return 1;
}
bool has_iv = cipher_name != "des-ede3";
TestCtx ctx = {cipher, nullptr, has_iv, test_mode};

if (argc == 5) {
ctx.response_sample.reset(new FileTest(argv[4]));
if (!ctx.response_sample->is_open()) {
return 1;
}
ctx.response_sample->SetIgnoreUnusedAttributes(true);
}

printf("# Generated by");
for (int i = 0; i < argc; i++) {
printf(" %s", argv[i]);
}
printf("\r\n\r\n");

// TODO(martinkr): Add MMT, MCT.
return FileTestMainSilent(TestKAT, &ctx, argv[3]);
}
28 changes: 27 additions & 1 deletion fipsoracle/run_cavp.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,31 @@ var ctrDRBGTests = testSuite{
[]test{{"CTR_DRBG", nil, false}},
}

var tdesTests = testSuite{
"TDES",
"cavp_tdes_test",
[]test{
// {"TCBCMMT2", []string{"mmt"}, false},
// {"TCBCMMT3", []string{"mmt"}, false},
// {"TCBCMonte2", []string{"mct"}, false},
// {"TCBCMonte3", []string{"mct"}, false},
{"TCBCinvperm", []string{"kat", "des-ede3-cbc"}, false},
{"TCBCpermop", []string{"kat", "des-ede3-cbc"}, false},
{"TCBCsubtab", []string{"kat", "des-ede3-cbc"}, false},
{"TCBCvarkey", []string{"kat", "des-ede3-cbc"}, false},
{"TCBCvartext", []string{"kat", "des-ede3-cbc"}, false},
// {"TECBMMT2", []string{"mmt"}, false},
// {"TECBMMT3", []string{"mmt"}, false},
// {"TECBMonte2", []string{"mct"}, false},
// {"TECBMonte3", []string{"mct"}, false},
{"TECBinvperm", []string{"kat", "des-ede3"}, false},
{"TECBpermop", []string{"kat", "des-ede3"}, false},
{"TECBsubtab", []string{"kat", "des-ede3"}, false},
{"TECBvarkey", []string{"kat", "des-ede3"}, false},
{"TECBvartext", []string{"kat", "des-ede3"}, false},
},
}

var allTestSuites = []*testSuite{
&aesGCMTests,
&aesTests,
Expand All @@ -178,6 +203,7 @@ var allTestSuites = []*testSuite{
&hmacTests,
&shaTests,
&shaMonteTests,
&tdesTests,
}

func main() {
Expand Down Expand Up @@ -224,7 +250,7 @@ func doTest(suite *testSuite, test test) error {
cmd.Stderr = os.Stderr

if err := cmd.Run(); err != nil {
return fmt.Errorf("cannot run command for %q %q: %s", suite.getDirectory(), test.inFile, err)
return fmt.Errorf("cannot run command for %q %q (%s): %s", suite.getDirectory(), test.inFile, strings.Join(append([]string{binary}, args...), " "), err)
}

return nil
Expand Down

0 comments on commit 2b2676f

Please sign in to comment.