Skip to content

Testing

Karel Kubicek edited this page Apr 12, 2018 · 5 revisions

Our testsuite uses googletest library for testing. Crypto-functions are tested with test vectors. For each function type (hash functions, block ciphers etc.) we have a special class called *_test_case which extends test_case. From reading test vectors to preparing tested streams and underlying functions to test. Test case is constructed by a name of the function (which needs to agree with the name of the function in particular stream factory), and a number of function's rounds.

Testing procedure

Currently, we test hash functions, block ciphers and stream ciphers. General procedure is following with little differences for specific function types. The place where is testing process defined is operator() function, here is example how it is called for Abacus hash function:

testsuite::hash_test_case("Abacus", 135)(); 

What happens next is reading test vector from testsuite/test-resources/hash/Abacus/test_vectors_135.txt.

"hash" is hardcoded in hash_test_case 
"Abacus" is name of function - argument of constructor 
"135" is number of rounds - argument of constructor 

For each test vector, we test at least two different scenarios:

  • Implementation of raw hash function with read data
    • function test() which each *test_case implements itself as it calls tested function type specific factory.
  • Our structure built on a raw hash function which takes care of reading json configuration and returning wished data
    • function test(std::unique_ptr<stream>& s) which is present in abstract parent class test_case. It is same for each function type as our stream structure unifies interface for each of them.
    • stream s is created in function prepare_stream().

Testing of hash functions

Test vectors are loaded from testsuite/test_resources/hash and two test cases are tested:

  1. Underlying raw hash function for the match with test vectors.
  2. Stream structure for the match with test vectors.

Test vectors structure:

STRUCTURE OF TEST VECTORS (All present in testsuite/test_resources/hash/{function-name}/test_vectors_{round-number}.txt) 
{bitsize-of-plaintext} {plaintext in hex} 
{ciphertext in hex} 
{bitsize-of-plaintext2} {plaintext2 in hex} 
{ciphertext2 in hex} 

Example:

0 00 
8740006A59E57CE233E5445C3DD8B5D17ED6C8DBEB76DD32358BC5ABFF819C62
1 00
52BE81BDA27A5660205DA2ECA85CEED2D5F1BCAC65646FBD92B50EFE0A773A62 

Testing of block ciphers

Test vectors are loaded from testsuite/test_resources/block and three test cases are tested:

  1. Underlying raw hash function for the match with test vector.
  2. Stream structure for the match with test vectors.
  3. Plaintext is encrypted with stream structure and ciphertext decrypted by raw function plaintext equality is checked.

Test vectors structure:

STRUCTURE OF TEST VECTORS (All present in testsuite/test_resources/block/{function-name}/test_vectors_{round-number}.txt) 
{key in hex} 
{plaintext in hex} 
{ciphertext in hex} 
{initialization-vector in hex} # Only in case we want to set it it is possible to avoid using iv 
{newline} 
{key in hex} 
{plaintext in hex} 
{ciphertext in hex} 
{initialization-vector in hex} # Only in case we want to set it it is possible to avoid using iv

Example:

00000000000000000000000000000000 
f34481ec3cc627bacd5dc3fb08f273e6 
0336763e966d92595a567cc9ce537f5e 

00000000000000000000000000000000 
9798c4640bad75c7c3227db910174e72 
a9a1631bf4996954ebc093957b234589 

Testing of stream ciphers

Test vectors are loaded from testsuite/test_resources/stream_cipher and three test cases are tested:

  1. Underlying raw hash function for the match with test vector.
  2. Stream structure for the match with test vectors.
  3. Plaintext is encrypted with stream structure and ciphertext decrypted by raw function plaintext equality is checked.

Test vectors structure:

STRUCTURE OF TEST VECTORS (All present in test_resources/stream_cipher/{function-name}/test_vectors_{round-number}.txt) 
{plaintext in hex} 
{key in hex} 
{initialization vector or keyword empty} 
{ciphertext} 
{plaintext2 in hex} 
{key2 in hex} 
{initialization vector2 or keyword empty} 
{ciphertext2} 

STRUCTURE OF CIPHERTEXT two options: 
- whole plaintext 
- tuples (index where ciphertext begins) (ciphretext)
	for example "0 FF 5 EE" means that first byte is FF and sixth byte is EE 

Example:

0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 
80000000000000000000 
00000000 
0 F8609452055CC9E97D64DC217F50679EEAD6FD0DDFC471BB94948FE9F1913C2CFFFBAEE715B0D104DC3EDE9C8A4D93B1FDCA46E8ECA9A4D729E8EC1C6EC6B544 192 C10D5DF62FA26CD3580ACD8E54ACA655F0FB35F7D53873BF02D566EB5EFC97E0BCB05A3D5301783487D38FE87F0EFC733B4EE7492355D6B6F5C515ACB1C67F1E 256 676E719000AB6C9F7D9CF3C0D3B6B726C07934593DF792DC7D01EC1E36469A1F3BDCAC9AD11145FFA47242BEC457467B46D2FECCB1B32C3C5B1B4C4E405441B0 448 2695F3CF5BD094FFE511CE612F23B970A8511F0FA1B9AE2D95413AE6E97F6FA5558E82CD07B89D39CB3CC85EC216042E3B72E5BA6291EB2AA3A09AF8F5DDC65F 256 676E719000AB6C9F7D9CF3C0D3B6B726C07934593DF792DC7D01EC1E36469A1F3BDCAC9AD11145FFA47242BEC457467B46D2FECCB1B32C3C5B1B4C4E405441B0 448 2695F3CF5BD094FFE511CE612F23B970A8511F0FA1B9AE2D95413AE6E97F6FA5558E82CD07B89D39CB3CC85EC216042E3B72E5BA6291EB2AA3A09AF8F5DDC65F 
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 
00000000000000000000000000000000 
0000000000000000 
e1047ba9476bf8ff312c01b4345a7d8ca5792b0ad467313f1dc412b5fdce32410dea8b68bd774c36a920f092a04d3f95274fbeff97bc8491fcef37f85970b4501d43b61a8f7e19fceddef368ae6bfb11101bd9fd3e4d127de30db2db1b472e76426803a45e15b962751986ef1d9d50f598a5dcdc9fa529a28357991e784ea20f 

Adding new tests

Adding new tests with existing test_case should be very easy. Here are steps for adding tests for AES function:

  1. Find out AES function string identifier. Open block_factory and you can see the name used is "AES".
  2. Safe the test vectors to file testsuite/test_resources/block/AES/text_vectors_X.txt, where X stands for a number of rounds you have test vectors for.
  3. Tests are called from following code in testsuite/block_streams_tests.cc:
TEST(aes, test_vectors) { 
	testsuite::block_test_case("AES", 10)(); 
}