(Cryptix Application Note #5 --November 1997, updated February 1998.)
Table of Contents
Return to the Application Notes Index or the FAQ.
Assessing the correctness of a cipher or message digest algorithm implementation involves running the algorithm with a known set of parameter values and checking the results against pre-computed values obtained either manually or with another correct implementation.
The process of writing the test class is a time-consuming one and, most of the time, requires the programmer to use repetitive tasks slightly adapted to the specifics of the algorithm being tested.
The abstract nature of the Java implementations of such algorithms and test procedures, inherent to the language being an object-oriented one, implies a more abstract method of testing that can save time and resources for Quality Assurance people, as well as programmers.
This dissociation between the algorithms and the data for their most common test protocols is emphasised by the Sun JCE API and Cryptix's clean-room implementation known as the IJCE (International JCE).
The cryptix.util.test.Maker class is a simple interpreter for a basic data definition language that can be used to test the correctness of cipher algorithm and message digest implementations. In essence instead of having a Test class for each implementation, incorporating the code and the test data, the user invokes Maker with as many test data files as needed or required. The syntax of such data files is simple enough that non-programmers can create them and indeed conduct the tests.
For more complicated situtations where specialised test code must be written, Maker files can include a Java class, allowing a single framework to be used to test all parts of Cryptix.
A simple example of a test data input file for Maker follows:
// // MD2 test data // md MD2 data "" <8350E5A3E24C153DF2275C9F80692773> "a" <32EC01EC4A6DAC72C0AB96FB34C0B5D1> "abc" <DA853B0D3F88D99B30283A69E6DED6BB> "message digest" <AB4F496BFB2A530B219FF33031FE06B0> "abcdefghijklmnopqrstuvwxyz" <4E8DDFF3650292AB5A4108C3AA47940B> |
The first three lines are comments. A comment starts with the two characters // and runs until an end-of-line is encountered. Maker ignores all comments. They are defined to allow an additional level of meta-information for use by the users.
A comment need not start at the beginning of a line.
The md keyword tells Maker that the subsequent information is to be used with a java.security.MessageDigest subclass. It is followed by an Identifier that has to match a JCE standard message digest name, or alias. Aliases are defined in the security provider properties, which for the Cryptix strong cryptographic library are stored in the Cryptix.properties file, found in the cryptix-lib directory.
The data keyword tells Maker that the subsequent information is to be interpreted as test data for the algorithm last defined.
The structure of data elements differ depending on whether the algorithm is a MessageDigest (indicated with the md keyword) or a Cipher (indicated with the cipher keyword).
For message digest test data are defined as either single-iteration or multi-iteration.
A single iteration is a pair of data formed by a input string or hexadecimal literal, and an output hexadecimal literal, separated by white space (one or more space, tab, new line or carriage return characters).
The semantics of the single-iteration statement is that Maker has to digest the input data (expressed either in hex or as an ASCII string) and check if the result matches the given output data.
A multi-iteration test data consists of:
Maker will update the message digest object n times using the input data, and finally check the result against the designated output data.
Here is an example of a Maker input file using the multi-iteration test data syntax:
// // RIPEMD128 test data // md RIPEMD128 data "" <CDF26213A150DC3ECB610F18F6B38B46> "a" <86BE7AFA339D0FC7CFC785E72F578D33> ... 1000000 * "a" <4A7F5723F954EBA1216C9D8F6320431F> |
A simple Maker input file for testing a cipher implementation follows:
// // CAST5 test data // cipher CAST5 // test #1 data // key input output <0123456712345678234567893456789A> <0123456789ABCDEF> <238B4FE5847E44B2> <01234567123456782345> <0123456789ABCDEF> <EB6A711A2C02271B> <0123456712> <0123456789ABCDEF> <7AC816D16E9B302E> // test #2 data <0123456712> <0123456789ABCDEF> speed |
Similar to md, the cipher keyword tells Maker that the subsequent information is to be used with a java.security.Cipher subclass. It is always followed by an Identifier that has to match a JCE standard cipher name or alias.
For a cipher object, the data elements can be: two-way test data, symmetric test data or speed test data.
A two-way test data is formed by a triplet of literals to be interpreted as the key, an input value and the certified output value respectively. The input value (plaintext) can be expressed either as hexadecimal or an ASCII string; the other values must be expressed in hexadecimal. When Maker recognises a two-way test data statement, it:
The speed keyword indicates a speed test data to be conducted on a cipher implementation. It is the last element of a triplet where the first two are similar to those found in a two-way test data; i.e.: key and input.
When Maker parses the speed keyword, it runs the cipher 100,000 times updating the same input value and printing both the start and finish date/times. It then decrypts the so far obtained result the same number of times and check if the final result matches the given input, printing along the timing information.
A symmetric test data is a triplet consisting of two literals corresponding to the plaintext and ciphertext, and the keyword auto. Here is an example:
// // RC2 test data // cipher RC2 data <0123456789abcdef> < 7595C3E6 114A0978 0C4AD452 338E1FFD 9A1BE949 8F813D76 533449B6 778DCAD8 C78A8D2B A9AC6608 5D0E53D5 9C26C2D1 C490C1EB BE0CE66D 1B6B1B13 B6B919B8 47C25A91 447A95E7 5E4EF167 79CDE8BF 0A95850E 32AF9689 444FD377 108F98FD CBD4E726 56750099 0BCC7E0C A3C4AAA3 04A387D2 0F3B8FBB CD42A1BD 311D7A43 03DDA5AB 078896AE 80C18B0A F66DFF31 9616EB78 4E495AD2 CE90D7F7 72A81747 B65F6209 3B1E0DB9 E5BA532F AFEC4750 8323E671 327DF944 4432CB73 67CEC82F 5D44C0D0 0B67D650 A075CD4B 70DEDD77 EB9B1023 1B6B5B74 1347396D 62897421 D43DF9B4 2E446E35 8E9C11A9 B2184ECB EF0CD8E7 A877EF96 8F1390EC 9B3D35A5 585CB009 290E2FCD E7B5EC66 D9084BE4 4055A619 D9DD7FC3 166F9487 F7CB2729 12426445 998514C1 5D53A18C 864CE3A2 B7555793 98812652 0EACF2E3 066E230C 91BEE4DD 5304F5FD 0405B35B D99C7313 5D3D9BC3 35EE049E F69B3867 BF2D7BD1 EAA595D8 BFC0066F F8D31509 EB0C6CAA 006C807A 623EF84C 3D33C195 D23EE320 C40DE055 8157C822 D4B8C569 D849AED5 9D4E0FD7 F379586B 4B7FF684 ED6A189F 7486D49B 9C4BAD9B A24B96AB F924372C 8A8FFFB1 0D553549 00A77A3D B5F205E1 B99FCD86 60863A15 9AD4ABE4 0FA48934 163DDDE5 42A65855 40FD683C BFD8C00F 12129A28 4DEACC4C DEFE58BE 7137541C 047126C8 D49E2755 AB181AB7 E940B0C0 > auto |
When Maker recognises the auto keyword, it encrypts the input value, then decrypts and check if the final result matches the given input.
Symmetric ciphers can be run in different modes of operations, with or without padding. Some modes require initialisation data known as Initialisation Vector or IV. In addition certain algorithms are designed to run with a variable number of rounds and a varying degree of cryptographic strength.
Maker allows the user to set specific values for these parameters with the properties keyword. Here is a fragment from the SAFER test data file (SAFER.mtest):
properties mode CBC padding NONE iv <74536EBDC211484A> variant = "K-128" rounds = 10 data // key <42431BA40D291F81D66083C605D3A4D6> // input < 00000000 00000000 01020304 05060708 00000000 00000000 01020304 05060708 00010203 04050607 08090A0B 0C0D0E0F 10111213 14151617 18191A1B 1C1D1E1F 20212223 24252627 28292A2B 2C2D2E2F 30313233 34353637 38393A3B 3C3D3E3F |
As you can see, the properties block has to appear before the data block.
Some properties have their own keywords, while algorithm-specific ones don't. Algorithm-specific properties are defined using the following syntax:
property-name = property-value
Where property-name is the name of a property known to the cipher implementation and property-value is either a numeric, string, or hexadecimal literal. When Maker encounters a statement of this sort, it calls the cipher object with the setParameter() method defined in the cipher object's superclass; i.e. java.security.Cipher.
If the value is invalid or is of the wrong type, the cipher object itself will reject it by throwing an exception, and Maker will treat this as an error.
In the example above, the data implies that the SAFER implementation knows how to handle two properties named: rounds and variant, with the first being a numeric while the last is a string.
The Java types that can be passed as algorithm-specific parameters by Maker are java.lang.Integer (for numeric values), java.lang.String (for values expressed as a string), and byte[] (for binary data).
The mode keyword should be followed by the JCE standard name or alias for a java.security.Mode subclass. It indicates the mode in which the cipher object will be run.
The padding keyword should be followed by the JCE standard name or alias for a java.security.PaddingScheme subclass. It indicates the padding method to apply for the cipher data.
The iv keyword should be followed by a hexadecimal literal. This literal will be used to set the initialisation vector for the cipher being tested.
The include keyword should be followed by either the name of another Maker source file (as a string literal), or a fully qualified class name.
If the name of a file is used, a new copy of Maker is created, and run on that input file. Here is an example:
// // test include statement of Maker language // include "MDx.mtest" include "RIPEMD1xx.mtest" |
Starting from Cryptix 3.0.4, included files are looked for relative to the directory of the parent file. For example, if the above source was in the file "Foo.mtest", and was run using:
the include statements would look for "some_directory/MDx.mtest" and "some_directory/RIPEMD1xx.mtest". This makes it easier to keep several source files together, that refer to each other using relative paths.java cryptix.util.test.Maker some_directory/Foo.mtest
In place of a filename, the name of a Java class can also be specified, without any enclosing quotes. The class must be public, have a public constructor that takes no arguments, and extend cryptix.util.test.BaseTest (a full description of the BaseTest API is beyond the scope of this document; see the source or the Javadoc comments for that class). This feature was also added in Cryptix 3.0.4.
A hexadecimal literal is a sequence of hexadecimal characters enclosed within a pair of angle brackets: <>. Maker removes all white space characters from the enclosed sequence before converting it to a byte array.
Maker is written in JavaCC, the Java equivalent to lex/yacc. The source code is defined in Maker.jj. You can use the already generated Java classes or you can recreate them. Here is how:
javacc Maker.jj
Maker can be run either from the command line or programmatically.
In Cryptix 3.0.4 and later, Maker will not display complete output unless one or more tests fail. The -verbose option can be used to override this behaviour. Cryptix 3.0.3 and earlier act as if -verbose is always set.java cryptix.util.test.Maker inputfile [> output] [options...] java cryptix.util.test.Maker [< input] [> output] [options...] Options: -verbose: print output even if all tests pass.
Alternatively, more control can be obtained by using the following method:import cryptix.util.test.Maker; InputStream is = getInputFileStream(); Maker maker = new Maker(is); maker.run();
/** * Runs an instance of Maker. * * @param options an array of string options. * @param name a name for this test. * @param includeDir the directory that filenames of include files * are considered relative to. This may be null, * indicating the current directory. * @param out a PrintWriter to direct output to. * @exception cryptix.util.test.TestException if the test fails. * @since Cryptix 3.0.4 */ public void run(String[] options, String name, File includeDir, PrintWriter out) throws TestException { ... }
The formal syntax of Maker in extended Backus-Naur form, as generated by jjDoc (a utility included in the JavaCC package), is available. (This is the Cryptix 3.0.4 version.)
Copyright © 1996-1997 Systemics Ltd
on behalf of the Cryptix Development Team.
All rights reserved.
Cryptix is a trademark of Systemics Ltd.