Note that the test application uses the embedded implementations of some libzrtp interfaces, and others are not used at all. Therefore while installing libzrtp the following flags should be used: -DBUILD_WITH_CFUNC, -DBUILD_EMPTY_CACHE, -DBUILD_DEFAULT_TIMER, -DZRTP_ENABLE_TEST, -DZRTP_USE_EXTERN_SRTP. For more detailed information see 1.4 libZRTP setup and building.
To install the test application on Windows there are project files libzrtp_test.dsp and libzrtp_test.vcproj for MS Visual Studio v6,v7 and v8..
To install the test application on Unix you should configure the library using the above-mentioned flags and execute the command: "make check". This will compile, link, and run all possible tests.
The cipher test is based on well known test vectors for different key sizes (128 and 256 bit) and different modes ( CTR and CFB).
The test will succeed if and only if the resulting encrypted text matches the predetermined ciphertext, and the resulting decrypted text matches the predetermined plaintext.
The expected output for a successful run of the cipher tests is:
------- Cipher tests -------
128 bit AES CFB
1st test...
encryption...OK
decryption...OK
2nd test...
encryption...OK
decryption...OK
128 bit AES CTR
1st test...
encryption...OK
decryption...OK
256 bit AES CFB
1st test...
encryption...OK
decryption...OK
2nd test...
encryption...OK
decryption...OK
256 bit AES CTR
1st test...
encryption...OK
decryption...OK
If the cipher tests fail, see 5. Possible problems and how to solve them.
To test the hash function, the hash of the given block is computed and bytewise-compared with the predetermined hash value. We use well-known test vectors for different lengths (1 to 2096 bytes).
The HMAC computation is tested in exactly the same way, using well-known test vectors for lengths of 8 to 73 bytes. During testing we use keys of length 20 and 80 bytes.
The expected output for a successful run of the hash/HMAC tests is:
-------- Hash tests -------- SHA-1 testing 8-bit test...OK 128-bit test...OK 512-bit test...OK 2096-bit test...OK HMAC SHA-1 testing 1 case test...OK 2 case test...OK 3 case test...OK 4 case test...OK 5 case test...OK 6 case test...OK 7 case test...OK SHA-256 testing 8-bit test...OK 128-bit test...OK 512-bit test...OK 2096-bit test...OK HMAC SHA-256 testing 1 case test...OK 2 case test...OK 3 case test...OK 4 case test...OK 5 case test...OK 6 case test...OK 7 case test...OK 8 case test...OK 9 case test...OK 10 case test...OK
If the hash/HMAC tests fail, see 5. Possible problems and how to solve them.
The expected output for a successful run of the derive key tests is:
----- Derive keys test ----- cipher key check...OK cipher salt check...OK auth key check...OK
If the derive key tests fail, see 5. Possible problems and how to solve them.
The first stage of the test simulates packet loss by generating a packet sequence with gaps. In the second stage, more packet sequences are generated, some of which have sequence numbers that were either omitted, or were already received in the first stage.
The test unit stores two bit strings, test map and res map. Each bit represents a sequence number. Each bit set in test map represents an attempt to send the packet with the corresponding sequence number. Each bit set in res map indicates that the packet with the corresponding sequence number has passed replay protection and is therefore safe to send..
The test generates test map to represent a sequence of packets. It then runs the replay protection algorithm, which acts as a filter. The filter is applied as a sliding window. If the filter allows a sequence number to pass, then res map is updated to have a "1" in the position corresponding to the packet's sequence number.
The test uses the following sizes of bit-strings:
Since the packet sequence generated in the first stage of the test is always increasing, after the first stage of the test, test map and res map must be identical.
Here is an example of the sequence of intervals in res map relative to the replay protection window after the first stage is completed.
A B C
Res map: 0000000000000000000000000000000000000000010001101111001011111110
Window : 1000110111100101
<---window sliding direction---
In the second stage of the test, test map is repopulated, but the window will retain information about the original packet sequence.
After the second stage of the test, res map must have the following properties:
An example of output for a successful run of the replay protection tests is:
--- Replay protection test --- 1st test. Wnd[16]... after wnd: (7;0] inside wnd: [22;7] before wnd: [63;22) Test map: 0000000000000000000000000000000000000000010001101111001011111110 Res map: 0000000000000000000000000000000000000000010001101111001011111110 Window : 1000110111100101 2nd test. Wnd[16]... Test map: 0010001010101110010111100110000010010110101000111010100001011101 Res map: 0010001010101110010111100110000010010110101000010000100000000000 Window : 1000101010111001 Test passed successfully
If the replay protection tests fail, see 5. Possible problems and how to solve them.
The first stage tests the implementation of the minimal set of system interfaces. Since the library is configured to use the embedded implementations of platform-dependent functions during the build, there are only a couple of callbacks, the RTP packages, and a sending function left to be implemented.
In order to emulate calls, we use a structure that encapsulates the concepts of media session and media stream. A call is then emulated by two media sessions represented by zrtp_test_connection_t objects, one for each side. Each object can then participate in RTP traffic exchanges.
Each session has a maximum number of streams, ZRTP_MAX_STREAMS_PER_SESSION. Streams are represented by zrtp_test_stream_t objects. Both sessions in the frame of a call share a collection of media streams, which is stored in a linked list.
The test unit has an interface of commands to operate on the call such that all streams of a session are affected by a given command.
Two kinds of threads are created during initalization to perform packet exchanges. Threads of the first type are used for generating RTP and RTCP packets for random sessions and encrypting them using libztrp, and for sending new packets to the other side through the shared queue. Threads of the second type are responsible for receiving packets from the shared queue and decrypting them.
As mentioned above, the test unit used in the build uses embedded implementations when available (see 1.4 libZRTP setup and building), so only the following functions need testing:
zrtp_queue.h, zrtp_queue.c).Each test connection, zrtp_test_connection, models one side of the ZRTP point-to-point channel. For this purpose, a zrtp_test_connection contains two test media streams zrtp_test_stream_t (one for video and one for voice). These zrtp_test_stream_t objects encapsulate the ZRTP stream context. The exchange process between threads is shown in the figure 1 "Scheme of test application thread interaction". As one connection represents only one side of the call, we need to have a corresponding connection with the same id. When a thread responsible for receiving traffic gets a packet from the queue, it has to find the appropriate connection and stream to send it to. This is done by checking the remote ssrc of the media streams of each connection in the linked list.
Figure 1.1 "Linked list of zrtp connections"
Incoming processing threads read packets from the global queue and process them using the library. If the packet is a protocol packet, the library will generate a reply and will send the packet through the zrtp_send_rtp() interface. If the packet is a data packet it will be decrypted and returned to the processing loop.
The outgoing stream starts RTP media generation right after running. Endpoints exchange plaintext packets while switching to the secure state, after which RTP traffic gets encrypted.
Figure 1.2 "Scheme of test application thread interaction"
Here are the steps of the command handling mechanism:
Libzrtp_test understands these commands:
For example. -------------------------------------------------------------------------------- Lets create one session. > c You'll see next: ### libzrtp_test: (ZRTP_STATE_ACTIVE) [093e23d4] OUTPUT. aardvark ### libzrtp_test: (ZRTP_STATE_ACTIVE) [093e3bd4] INPUT. aardvark ### libzrtp_test: (ZRTP_STATE_ACTIVE) [093e3bd4] OUTPUT. adroitness ### libzrtp_test: (ZRTP_STATE_ACTIVE) [093e23d4] INPUT. adroitness (ZRTP_STATE_xxxxx) - indicates the current ZRTP stream state; [address] - physical address of the ZRTP stream for debugging needs; -------------------------------------------------------------------------------- Now lets start zrtp streams. > z ### libzrtp_test: (ZRTP_STATE_SECURE) [093e23d4] OUTPUT. standard ### libzrtp_test: (ZRTP_STATE_SECURE) [093e3bd4] INPUT. standard The session is protected now. If an error occurs, the ZRTP stream switches to ZRTP_STATE_ERROR state. -------------------------------------------------------------------------------- Lets switch off packet encryption. > r ### libzrtp_test: (ZRTP_STATE_CLEAR) [093e23d4] OUTPUT. classroom ### libzrtp_test: (ZRTP_STATE_CLEAR) [093e3bd4] INPUT. classroom Traffic is unprotected now. -------------------------------------------------------------------------------- To secure the session again press > s ### libzrtp_test: (ZRTP_STATE_SECURE) [093e23d4] OUTPUT. lockup ### libzrtp_test: (ZRTP_STATE_SECURE) [093e3bd4] INPUT. lockup --------------------------------------------------------------------------------
The test unit for Windows CE resides in the ./projects folder and is named libzrtp_wince_vc8.sln
The implementation for Symbian differs from the preceding first and foremost by the presence of classes.
Control of the test unit is through the back button:
Logs whose level does not match the level of ZRTP_LOG_DEBUG are written to the ListBox, and all logs are also written to "c:/zfone.log"
To build the test unit on Symbian follow these recommendations:
To build, type:
bldmake bldfiles ABLD build gcce urel