Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  srtp_driver.c

  Sprache: C
 

/*
 * srtp_driver.c
 *
 * a test driver for libSRTP
 *
 * David A. McGrew
 * Cisco Systems, Inc.
 */

/*
 *
 * Copyright (c) 2001-2017, Cisco Systems, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 *   Redistributions in binary form must reproduce the above
 *   copyright notice, this list of conditions and the following
 *   disclaimer in the documentation and/or other materials provided
 *   with the distribution.
 *
 *   Neither the name of the Cisco Systems, Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */


#include <string.h>   /* for memcpy()          */
#include <time.h>     /* for clock()           */
#include <stdlib.h>   /* for malloc(), free()  */
#include <stdio.h>    /* for print(), fflush() */
#include "getopt_s.h" /* for local getopt()    */

#include "srtp_priv.h"
#include "stream_list_priv.h"
#include "util.h"

#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#elif defined HAVE_WINSOCK2_H
#include <winsock2.h>
#endif

#define PRINT_REFERENCE_PACKET 1

srtp_err_status_t srtp_validate(void);

srtp_err_status_t srtp_validate_null_sha1_80(void);

srtp_err_status_t srtp_validate_null_null(void);

srtp_err_status_t srtp_validate_cryptex(void);

#ifdef GCM
srtp_err_status_t srtp_validate_gcm(void);

srtp_err_status_t srtp_validate_gcm_cryptex(void);
#endif
srtp_err_status_t srtp_validate_encrypted_extensions_headers(void);

#ifdef GCM
srtp_err_status_t srtp_validate_encrypted_extensions_headers_gcm(void);
#endif

srtp_err_status_t srtp_validate_aes_256(void);

#ifdef GCM
srtp_err_status_t srtp_validate_aes_192(void);
#endif

srtp_err_status_t srtp_create_big_policy(srtp_policy_t **list);

srtp_err_status_t srtp_dealloc_big_policy(srtp_policy_t *list);

srtp_err_status_t srtp_test_empty_payload(void);

#ifdef GCM
srtp_err_status_t srtp_test_empty_payload_gcm(void);
#endif

srtp_err_status_t srtp_test_remove_stream(void);

srtp_err_status_t srtp_test_update(void);

srtp_err_status_t srtp_test_protect_trailer_length(void);

srtp_err_status_t srtp_test_protect_rtcp_trailer_length(void);

srtp_err_status_t srtp_test_out_of_order_after_rollover(void);

srtp_err_status_t srtp_test_get_roc(void);

srtp_err_status_t srtp_test_set_receiver_roc(void);

srtp_err_status_t srtp_test_set_sender_roc(void);

srtp_err_status_t srtp_test_cryptex_csrc_but_no_extension_header(void);

srtp_err_status_t srtp_test_cryptex_disable(void);

double srtp_bits_per_second(int msg_len_octets, const srtp_policy_t *policy);

double srtp_rejections_per_second(int msg_len_octets,
                                  const srtp_policy_t *policy);

void srtp_do_timing(const srtp_policy_t *policy);

void srtp_do_rejection_timing(const srtp_policy_t *policy);

srtp_err_status_t srtp_test(const srtp_policy_t *policy,
                            int extension_header,
                            int mki_index);

srtp_err_status_t srtcp_test(const srtp_policy_t *policy, int mki_index);

srtp_err_status_t srtp_session_print_policy(srtp_t srtp);

srtp_err_status_t srtp_print_policy(const srtp_policy_t *policy);

char *srtp_packet_to_string(srtp_hdr_t *hdr, int packet_len);
char *srtp_rtcp_packet_to_string(srtcp_hdr_t *hdr, int pkt_octet_len);

double mips_estimate(int num_trials, int *ignore);

srtp_err_status_t srtp_stream_list_test(void);

#define TEST_MKI_ID_SIZE 4

typedef struct test_vectors_t {
    const char *name;
    char *plaintext;
    char *ciphertext;
} test_vectors_t;

extern uint8_t test_key[46];
extern uint8_t test_key_2[46];
extern uint8_t test_mki_id[TEST_MKI_ID_SIZE];
extern uint8_t test_mki_id_2[TEST_MKI_ID_SIZE];
extern uint8_t test_key_gcm[28];

// clang-format off
srtp_master_key_t master_key_1 = {
    test_key,
    test_mki_id,
    TEST_MKI_ID_SIZE
};

srtp_master_key_t master_key_2 = {
    test_key_2,
    test_mki_id_2,
    TEST_MKI_ID_SIZE
};

srtp_master_key_t *test_keys[2] = {
    &master_key_1,
    &master_key_2
};
// clang-format on

void usage(char *prog_name)
{
    printf(
        "usage: %s [ -t ][ -c ][ -v ][ -s ][ -o ][-d <debug_module> ]* [ -l ]\n"
        "  -t         run timing test\n"
        "  -r         run rejection timing test\n"
        "  -c         run codec timing test\n"
        "  -v         run validation tests\n"
        "  -s         run stream list tests only\n"
        "  -o         output logging to stdout\n"
        "  -d <mod>   turn on debugging module <mod>\n"
        "  -l         list debugging modules\n",
        prog_name);
    exit(1);
}

void log_handler(srtp_log_level_t level, const char *msg, void *data)
{
    char level_char = '?';
    (void)data;
    switch (level) {
    case srtp_log_level_error:
        level_char = 'e';
        break;
    case srtp_log_level_warning:
        level_char = 'w';
        break;
    case srtp_log_level_info:
        level_char = 'i';
        break;
    case srtp_log_level_debug:
        level_char = 'd';
        break;
    }
    printf("SRTP-LOG [%c]: %s\n", level_char, msg);
}

/*
 * The policy_array and invalid_policy_array are null-terminated arrays of
 * policy structs. They is declared at the end of this file.
 */


extern const srtp_policy_t *policy_array[];
extern const srtp_policy_t *invalid_policy_array[];

/* the wildcard_policy is declared below; it has a wildcard ssrc */

extern const srtp_policy_t wildcard_policy;

/*
 * mod_driver debug module - debugging module for this test driver
 *
 * we use the crypto_kernel debugging system in this driver, which
 * makes the interface uniform and increases portability
 */


srtp_debug_module_t mod_driver = {
    0,       /* debugging is off by default */
    "driver" /* printable name for module   */
};

int main(int argc, char *argv[])
{
    int q;
    unsigned do_timing_test = 0;
    unsigned do_rejection_test = 0;
    unsigned do_codec_timing = 0;
    unsigned do_validation = 0;
    unsigned do_stream_list = 0;
    unsigned do_list_mods = 0;
    unsigned do_log_stdout = 0;
    srtp_err_status_t status;
    const size_t hdr_size = 12;

    /*
     * verify that the compiler has interpreted the header data
     * structure srtp_hdr_t correctly
     */

    if (sizeof(srtp_hdr_t) != hdr_size) {
        printf("error: srtp_hdr_t has incorrect size"
               "(size is %ld bytes, expected %ld)\n",
               (long)sizeof(srtp_hdr_t), (long)hdr_size);
        exit(1);
    }

    /* initialize srtp library */
    status = srtp_init();
    if (status) {
        printf("error: srtp init failed with error code %d\n", status);
        exit(1);
    }

    /*  load srtp_driver debug module */
    status = srtp_crypto_kernel_load_debug_module(&mod_driver);
    if (status) {
        printf("error: load of srtp_driver debug module failed "
               "with error code %d\n",
               status);
        exit(1);
    }

    /* process input arguments */
    while (1) {
        q = getopt_s(argc, argv, "trcvsold:");
        if (q == -1) {
            break;
        }
        switch (q) {
        case 't':
            do_timing_test = 1;
            break;
        case 'r':
            do_rejection_test = 1;
            break;
        case 'c':
            do_codec_timing = 1;
            break;
        case 'v':
            do_validation = 1;
            do_stream_list = 1;
            break;
        case 's':
            do_stream_list = 1;
            break;
        case 'o':
            do_log_stdout = 1;
            break;
        case 'l':
            do_list_mods = 1;
            break;
        case 'd':
            status = srtp_set_debug_module(optarg_s, 1);
            if (status) {
                printf("error: set debug module (%s) failed\n", optarg_s);
                exit(1);
            }
            break;
        default:
            usage(argv[0]);
        }
    }

    if (!do_validation && !do_timing_test && !do_codec_timing &&
        !do_list_mods && !do_rejection_test && !do_stream_list) {
        usage(argv[0]);
    }

    if (do_log_stdout) {
        status = srtp_install_log_handler(log_handler, NULL);
        if (status) {
            printf("error: install log handler failed\n");
            exit(1);
        }
    }

    if (do_list_mods) {
        status = srtp_list_debug_modules();
        if (status) {
            printf("error: list of debug modules failed\n");
            exit(1);
        }
    }

    if (do_validation) {
        const srtp_policy_t **policy = policy_array;
        srtp_policy_t *big_policy;
        srtp_t srtp_sender;

        /* loop over policy array, testing srtp and srtcp for each policy */
        while (*policy != NULL) {
            printf("testing srtp_protect and srtp_unprotect\n");
            if (srtp_test(*policy, 0, -1) == srtp_err_status_ok) {
                printf("passed\n\n");
            } else {
                printf("failed\n");
                exit(1);
            }

            printf("testing srtp_protect and srtp_unprotect with encrypted "
                   "extensions headers\n");
            if (srtp_test(*policy, 1, -1) == srtp_err_status_ok) {
                printf("passed\n\n");
            } else {
                printf("failed\n");
                exit(1);
            }
            printf("testing srtp_protect_rtcp and srtp_unprotect_rtcp\n");
            if (srtcp_test(*policy, -1) == srtp_err_status_ok) {
                printf("passed\n\n");
            } else {
                printf("failed\n");
                exit(1);
            }
            printf("testing srtp_protect_rtp and srtp_unprotect_rtp with MKI "
                   "index set to 0\n");
            if (srtp_test(*policy, 00) == srtp_err_status_ok) {
                printf("passed\n\n");
            } else {
                printf("failed\n");
                exit(1);
            }
            printf("testing srtp_protect_rtp and srtp_unprotect_rtp with MKI "
                   "index set to 1\n");
            if (srtp_test(*policy, 01) == srtp_err_status_ok) {
                printf("passed\n\n");
            } else {
                printf("failed\n");
                exit(1);
            }

            printf("testing srtp_protect_rtcp and srtp_unprotect_rtcp with MKI "
                   "index set to 0\n");
            if (srtcp_test(*policy, 0) == srtp_err_status_ok) {
                printf("passed\n\n");
            } else {
                printf("failed\n");
                exit(1);
            }
            printf("testing srtp_protect_rtcp and srtp_unprotect_rtcp with MKI "
                   "index set to 1\n");
            if (srtcp_test(*policy, 1) == srtp_err_status_ok) {
                printf("passed\n\n");
            } else {
                printf("failed\n");
                exit(1);
            }
            policy++;
        }

        /* loop over invalid policy array, testing that an SRTP context cannot
         * be created with the policy */

        policy = invalid_policy_array;
        while (*policy != NULL) {
            printf("testing srtp_create fails with invalid policy\n");
            if (srtp_create(&srtp_sender, *policy) != srtp_err_status_ok) {
                printf("passed\n\n");
            } else {
                printf("failed\n");
                exit(1);
            }

            policy++;
        }

        /* create a big policy list and run tests on it */
        status = srtp_create_big_policy(&big_policy);
        if (status) {
            printf("unexpected failure with error code %d\n", status);
            exit(1);
        }
        printf("testing srtp_protect and srtp_unprotect with big policy\n");
        if (srtp_test(big_policy, 0, -1) == srtp_err_status_ok) {
            printf("passed\n\n");
        } else {
            printf("failed\n");
            exit(1);
        }
        printf("testing srtp_protect and srtp_unprotect with big policy and "
               "encrypted extensions headers\n");
        if (srtp_test(big_policy, 1, -1) == srtp_err_status_ok) {
            printf("passed\n\n");
        } else {
            printf("failed\n");
            exit(1);
        }
        status = srtp_dealloc_big_policy(big_policy);
        if (status) {
            printf("unexpected failure with error code %d\n", status);
            exit(1);
        }

        /* run test on wildcard policy */
        printf("testing srtp_protect and srtp_unprotect on "
               "wildcard ssrc policy\n");
        if (srtp_test(&wildcard_policy, 0, -1) == srtp_err_status_ok) {
            printf("passed\n\n");
        } else {
            printf("failed\n");
            exit(1);
        }
        printf("testing srtp_protect and srtp_unprotect on "
               "wildcard ssrc policy and encrypted extensions headers\n");
        if (srtp_test(&wildcard_policy, 1, -1) == srtp_err_status_ok) {
            printf("passed\n\n");
        } else {
            printf("failed\n");
            exit(1);
        }

        /*
         * run validation test against the reference packets - note
         * that this test only covers the default policy
         */

        printf("testing srtp_protect and srtp_unprotect against "
               "reference packet\n");
        if (srtp_validate() == srtp_err_status_ok) {
            printf("passed\n\n");
        } else {
            printf("failed\n");
            exit(1);
        }

        printf("testing srtp_protect and srtp_unprotect against "
               "reference packet using null cipher and SHA1-80 HMAC\n");
        if (srtp_validate_null_sha1_80() == srtp_err_status_ok) {
            printf("passed\n\n");
        } else {
            printf("failed\n");
            exit(1);
        }

        printf("testing srtp_protect and srtp_unprotect against "
               "reference packet using null cipher and null HMAC\n");
        if (srtp_validate_null_null() == srtp_err_status_ok) {
            printf("passed\n\n");
        } else {
            printf("failed\n");
            exit(1);
        }

        printf("testing srtp_protect and srtp_unprotect against "
               "reference cryptex packet\n");
        if (srtp_validate_cryptex() == srtp_err_status_ok) {
            printf("passed\n\n");
        } else {
            printf("failed\n");
            exit(1);
        }

#ifdef GCM
        printf("testing srtp_protect and srtp_unprotect against "
               "reference packet using GCM\n");
        if (srtp_validate_gcm() == srtp_err_status_ok) {
            printf("passed\n\n");
        } else {
            printf("failed\n");
            exit(1);
        }

        printf("testing srtp_protect and srtp_unprotect against "
               "reference cryptex packet using GCM\n");
        if (srtp_validate_gcm_cryptex() == srtp_err_status_ok) {
            printf("passed\n\n");
        } else {
            printf("failed\n");
            exit(1);
        }
#endif

        printf("testing srtp_protect and srtp_unprotect against "
               "reference packet with encrypted extensions headers\n");
        if (srtp_validate_encrypted_extensions_headers() == srtp_err_status_ok)
            printf("passed\n\n");
        else {
            printf("failed\n");
            exit(1);
        }

#ifdef GCM
        printf("testing srtp_protect and srtp_unprotect against "
               "reference packet with encrypted extension headers (GCM)\n");
        if (srtp_validate_encrypted_extensions_headers_gcm() ==
            srtp_err_status_ok) {
            printf("passed\n\n");
        } else {
            printf("failed\n");
            exit(1);
        }
#endif

#ifdef GCM
        /*
         * run validation test against the reference packets for
         * AES-192
         */

        printf("testing srtp_protect and srtp_unprotect against "
               "reference packet (AES-192)\n");
        if (srtp_validate_aes_192() == srtp_err_status_ok) {
            printf("passed\n\n");
        } else {
            printf("failed\n");
            exit(1);
        }
#endif

        /*
         * run validation test against the reference packets for
         * AES-256
         */

        printf("testing srtp_protect and srtp_unprotect against "
               "reference packet (AES-256)\n");
        if (srtp_validate_aes_256() == srtp_err_status_ok) {
            printf("passed\n\n");
        } else {
            printf("failed\n");
            exit(1);
        }

        /*
         * test packets with empty payload
         */

        printf("testing srtp_protect and srtp_unprotect against "
               "packet with empty payload\n");
        if (srtp_test_empty_payload() == srtp_err_status_ok) {
            printf("passed\n");
        } else {
            printf("failed\n");
            exit(1);
        }
#ifdef GCM
        printf("testing srtp_protect and srtp_unprotect against "
               "packet with empty payload (GCM)\n");
        if (srtp_test_empty_payload_gcm() == srtp_err_status_ok) {
            printf("passed\n");
        } else {
            printf("failed\n");
            exit(1);
        }
#endif

        /*
         * test the function srtp_remove_stream()
         */

        printf("testing srtp_remove_stream()...");
        if (srtp_test_remove_stream() == srtp_err_status_ok) {
            printf("passed\n");
        } else {
            printf("failed\n");
            exit(1);
        }

        /*
         * test the function srtp_update()
         */

        printf("testing srtp_update()...");
        if (srtp_test_update() == srtp_err_status_ok) {
            printf("passed\n");
        } else {
            printf("failed\n");
            exit(1);
        }

        /*
         * test the functions srtp_get_protect_trailer_length
         * and srtp_get_protect_rtcp_trailer_length
         */

        printf("testing srtp_get_protect_trailer_length()...");
        if (srtp_test_protect_trailer_length() == srtp_err_status_ok) {
            printf("passed\n");
        } else {
            printf("failed\n");
            exit(1);
        }

        printf("testing srtp_get_protect_rtcp_trailer_length()...");
        if (srtp_test_protect_rtcp_trailer_length() == srtp_err_status_ok) {
            printf("passed\n");
        } else {
            printf("failed\n");
            exit(1);
        }

        printf("testing srtp_test_out_of_order_after_rollover()...");
        if (srtp_test_out_of_order_after_rollover() == srtp_err_status_ok) {
            printf("passed\n");
        } else {
            printf("failed\n");
            exit(1);
        }

        printf("testing srtp_test_get_roc()...");
        if (srtp_test_get_roc() == srtp_err_status_ok) {
            printf("passed\n");
        } else {
            printf("failed\n");
            exit(1);
        }

        printf("testing srtp_test_set_receiver_roc()...");
        if (srtp_test_set_receiver_roc() == srtp_err_status_ok) {
            printf("passed\n");
        } else {
            printf("failed\n");
            exit(1);
        }

        printf("testing srtp_test_set_sender_roc()...");
        if (srtp_test_set_sender_roc() == srtp_err_status_ok) {
            printf("passed\n");
        } else {
            printf("failed\n");
            exit(1);
        }

        printf("testing cryptex_csrc_but_no_extension_header()...");
        if (srtp_test_cryptex_csrc_but_no_extension_header() ==
            srtp_err_status_ok) {
            printf("passed\n");
        } else {
            printf("failed\n");
            exit(1);
        }

        printf("testing cryptex_disable()...");
        if (srtp_test_cryptex_disable() == srtp_err_status_ok) {
            printf("passed\n");
        } else {
            printf("failed\n");
            exit(1);
        }
    }

    if (do_stream_list) {
        printf("testing srtp_stream_list...");
        if (srtp_stream_list_test() == srtp_err_status_ok) {
            printf("passed\n");
        } else {
            printf("failed\n");
            exit(1);
        }
    }

    if (do_timing_test) {
        const srtp_policy_t **policy = policy_array;

        /* loop over policies, run timing test for each */
        while (*policy != NULL) {
            srtp_print_policy(*policy);
            srtp_do_timing(*policy);
            policy++;
        }
    }

    if (do_rejection_test) {
        const srtp_policy_t **policy = policy_array;

        /* loop over policies, run rejection timing test for each */
        while (*policy != NULL) {
            srtp_print_policy(*policy);
            srtp_do_rejection_timing(*policy);
            policy++;
        }
    }

    if (do_codec_timing) {
        srtp_policy_t policy;
        int ignore;
        double mips_value = mips_estimate(1000000000, &ignore);

        memset(&policy, 0sizeof(policy));
        srtp_crypto_policy_set_rtp_default(&policy.rtp);
        srtp_crypto_policy_set_rtcp_default(&policy.rtcp);
        policy.ssrc.type = ssrc_specific;
        policy.ssrc.value = 0xdecafbad;
        policy.key = test_key;
        policy.deprecated_ekt = NULL;
        policy.window_size = 128;
        policy.allow_repeat_tx = 0;
        policy.next = NULL;

        printf("mips estimate: %e\n", mips_value);

        printf("testing srtp processing time for voice codecs:\n");
        printf("codec\t\tlength (octets)\t\tsrtp instructions/second\n");
        printf("G.711\t\t%d\t\t\t%e\n"80,
               (double)mips_value * (80 * 8) /
                   srtp_bits_per_second(80, &policy) / .01);
        printf("G.711\t\t%d\t\t\t%e\n"160,
               (double)mips_value * (160 * 8) /
                   srtp_bits_per_second(160, &policy) / .02);
        printf("G.726-32\t%d\t\t\t%e\n"40,
               (double)mips_value * (40 * 8) /
                   srtp_bits_per_second(40, &policy) / .01);
        printf("G.726-32\t%d\t\t\t%e\n"80,
               (double)mips_value * (80 * 8) /
                   srtp_bits_per_second(80, &policy) / .02);
        printf("G.729\t\t%d\t\t\t%e\n"10,
               (double)mips_value * (10 * 8) /
                   srtp_bits_per_second(10, &policy) / .01);
        printf("G.729\t\t%d\t\t\t%e\n"20,
               (double)mips_value * (20 * 8) /
                   srtp_bits_per_second(20, &policy) / .02);
        printf("Wideband\t%d\t\t\t%e\n"320,
               (double)mips_value * (320 * 8) /
                   srtp_bits_per_second(320, &policy) / .01);
        printf("Wideband\t%d\t\t\t%e\n"640,
               (double)mips_value * (640 * 8) /
                   srtp_bits_per_second(640, &policy) / .02);
    }

    status = srtp_shutdown();
    if (status) {
        printf("error: srtp shutdown failed with error code %d\n", status);
        exit(1);
    }

    return 0;
}

/*
 * srtp_create_test_packet(len, ssrc) returns a pointer to a
 * (malloced) example RTP packet whose data field has the length given
 * by pkt_octet_len and the SSRC value ssrc.  The total length of the
 * packet is twelve octets longer, since the header is at the
 * beginning.  There is room at the end of the packet for a trailer,
 * and the four octets following the packet are filled with 0xff
 * values to enable testing for overwrites.
 *
 * note that the location of the test packet can (and should) be
 * deallocated with the free() call once it is no longer needed.
 */


srtp_hdr_t *srtp_create_test_packet(int pkt_octet_len,
                                    uint32_t ssrc,
                                    int *pkt_len)
{
    int i;
    uint8_t *buffer;
    srtp_hdr_t *hdr;
    int bytes_in_hdr = 12;

    /* allocate memory for test packet */
    hdr = (srtp_hdr_t *)malloc(pkt_octet_len + bytes_in_hdr +
                               SRTP_MAX_TRAILER_LEN + 4);
    if (!hdr) {
        return NULL;
    }

    hdr->version = 2;            /* RTP version two     */
    hdr->p = 0;                  /* no padding needed   */
    hdr->x = 0;                  /* no header extension */
    hdr->cc = 0;                 /* no CSRCs            */
    hdr->m = 0;                  /* marker bit          */
    hdr->pt = 0xf;               /* payload type        */
    hdr->seq = htons(0x1234);    /* sequence number     */
    hdr->ts = htonl(0xdecafbad); /* timestamp           */
    hdr->ssrc = htonl(ssrc);     /* synch. source       */

    buffer = (uint8_t *)hdr;
    buffer += bytes_in_hdr;

    /* set RTP data to 0xab */
    for (i = 0; i < pkt_octet_len; i++) {
        *buffer++ = 0xab;
    }

    /* set post-data value to 0xffff to enable overrun checking */
    for (i = 0; i < SRTP_MAX_TRAILER_LEN + 4; i++) {
        *buffer++ = 0xff;
    }

    *pkt_len = bytes_in_hdr + pkt_octet_len;

    return hdr;
}

srtcp_hdr_t *srtp_create_rtcp_test_packet(int pkt_octet_len,
                                          uint32_t ssrc,
                                          int *pkt_len)
{
    int i;
    uint8_t *buffer;
    srtcp_hdr_t *hdr;
    int bytes_in_hdr = 8;

    /* allocate memory for test packet */
    hdr = (srtcp_hdr_t *)malloc(pkt_octet_len + bytes_in_hdr +
                                SRTP_MAX_SRTCP_TRAILER_LEN + 4);
    if (!hdr) {
        return NULL;
    }

    hdr->version = 2/* RTP version two     */
    hdr->p = 0;       /* no padding needed   */
    hdr->rc = 0;      /* no reports          */
    hdr->pt = 0xc8;   /* sender report (200) */
    hdr->len = ((bytes_in_hdr + pkt_octet_len) % 4) - 1;
    hdr->ssrc = htonl(ssrc); /* synch. source       */

    buffer = (uint8_t *)hdr;
    buffer += bytes_in_hdr;

    /* set data to 0xab */
    for (i = 0; i < pkt_octet_len; i++) {
        *buffer++ = 0xab;
    }

    /* set post-data value to 0xffff to enable overrun checking */
    for (i = 0; i < SRTP_MAX_SRTCP_TRAILER_LEN + 4; i++) {
        *buffer++ = 0xff;
    }

    *pkt_len = bytes_in_hdr + pkt_octet_len;

    return hdr;
}

static srtp_hdr_t *srtp_create_test_packet_extended(int pkt_octet_len,
                                                    uint32_t ssrc,
                                                    uint16_t seq,
                                                    uint32_t ts,
                                                    int *pkt_len)
{
    srtp_hdr_t *hdr;

    hdr = srtp_create_test_packet(pkt_octet_len, ssrc, pkt_len);
    if (hdr == NULL)
        return hdr;

    hdr->seq = htons(seq);
    hdr->ts = htonl(ts);
    return hdr;
}

srtp_hdr_t *srtp_create_test_packet_ext_hdr(int pkt_octet_len,
                                            uint32_t ssrc,
                                            int *pkt_len)
{
    int i;
    uint8_t *buffer;
    srtp_hdr_t *hdr;
    int bytes_in_hdr = 12;
    uint8_t extension_header[12] = { /* one-byte header */
                                     0xbe, 0xde,
                                     /* size */
                                     0x00, 0x02,
                                     /* id 1, length 1 (i.e. 2 bytes) */
                                     0x11,
                                     /* payload */
                                     0xca, 0xfe,
                                     /* padding */
                                     0x00,
                                     /* id 2, length 0 (i.e. 1 byte) */
                                     0x20,
                                     /* payload */
                                     0xba,
                                     /* padding */
                                     0x00, 0x00
    };

    /* allocate memory for test packet */
    hdr = (srtp_hdr_t *)malloc(pkt_octet_len + bytes_in_hdr +
                               sizeof(extension_header) + SRTP_MAX_TRAILER_LEN +
                               4);
    if (!hdr)
        return NULL;

    hdr->version = 2;            /* RTP version two     */
    hdr->p = 0;                  /* no padding needed   */
    hdr->x = 1;                  /* no header extension */
    hdr->cc = 0;                 /* no CSRCs            */
    hdr->m = 0;                  /* marker bit          */
    hdr->pt = 0xf;               /* payload type        */
    hdr->seq = htons(0x1234);    /* sequence number     */
    hdr->ts = htonl(0xdecafbad); /* timestamp           */
    hdr->ssrc = htonl(ssrc);     /* synch. source       */

    buffer = (uint8_t *)hdr;
    buffer += bytes_in_hdr;

    memcpy(buffer, extension_header, sizeof(extension_header));
    buffer += sizeof(extension_header);

    /* set RTP data to 0xab */
    for (i = 0; i < pkt_octet_len; i++)
        *buffer++ = 0xab;

    /* set post-data value to 0xffff to enable overrun checking */
    for (i = 0; i < SRTP_MAX_TRAILER_LEN + 4; i++)
        *buffer++ = 0xff;

    *pkt_len = bytes_in_hdr + sizeof(extension_header) + pkt_octet_len;

    return hdr;
}

static uint16_t srtp_get_xtn_profile(const uint8_t *packet)
{
    const srtp_hdr_t *hdr = (const srtp_hdr_t *)packet;
    const srtp_hdr_xtnd_t *xtn_hdr;

    if (!hdr->x) {
        return 0;
    }

    xtn_hdr = (const srtp_hdr_xtnd_t *)(packet + sizeof(srtp_hdr_t) +
                                        (hdr->cc * sizeof(uint32_t)));
    return ntohs(xtn_hdr->profile_specific);
}

void srtp_do_timing(const srtp_policy_t *policy)
{
    int len;

    /*
     * note: the output of this function is formatted so that it
     * can be used in gnuplot.  '#' indicates a comment, and "\r\n"
     * terminates a record
     */


    printf("# testing srtp throughput:\r\n");
    printf("# mesg length (octets)\tthroughput (megabits per second)\r\n");

    for (len = 16; len <= 2048; len *= 2) {
        printf("%d\t\t\t%f\r\n", len,
               srtp_bits_per_second(len, policy) / 1.0E6);
    }

    /* these extra linefeeds let gnuplot know that a dataset is done */
    printf("\r\n\r\n");
}

void srtp_do_rejection_timing(const srtp_policy_t *policy)
{
    int len;

    /*
     * note: the output of this function is formatted so that it
     * can be used in gnuplot.  '#' indicates a comment, and "\r\n"
     * terminates a record
     */


    printf("# testing srtp rejection throughput:\r\n");
    printf("# mesg length (octets)\trejections per second\r\n");

    for (len = 8; len <= 2048; len *= 2) {
        printf("%d\t\t\t%e\r\n", len, srtp_rejections_per_second(len, policy));
    }

    /* these extra linefeeds let gnuplot know that a dataset is done */
    printf("\r\n\r\n");
}

#define MAX_MSG_LEN 1024

double srtp_bits_per_second(int msg_len_octets, const srtp_policy_t *policy)
{
    srtp_t srtp;
    srtp_hdr_t *mesg;
    int i;
    clock_t timer;
    int num_trials = 100000;
    int input_len, len;
    uint32_t ssrc;
    srtp_err_status_t status;

    /*
     * allocate and initialize an srtp session
     */

    status = srtp_create(&srtp, policy);
    if (status) {
        printf("error: srtp_create() failed with error code %d\n", status);
        exit(1);
    }

    /*
     * if the ssrc is unspecified, use a predetermined one
     */

    if (policy->ssrc.type != ssrc_specific) {
        ssrc = 0xdeadbeef;
    } else {
        ssrc = policy->ssrc.value;
    }

    /*
     * create a test packet
     */

    mesg = srtp_create_test_packet(msg_len_octets, ssrc, &input_len);
    if (mesg == NULL) {
        return 0.0/* indicate failure by returning zero */
    }
    timer = clock();
    for (i = 0; i < num_trials; i++) {
        len = input_len;
        /* srtp protect message */
        status = srtp_protect(srtp, mesg, &len);
        if (status) {
            printf("error: srtp_protect() failed with error code %d\n", status);
            exit(1);
        }

        /* increment message number */
        {
            /* hack sequence to avoid problems with macros for htons/ntohs on
             * some systems */

            short new_seq = ntohs(mesg->seq) + 1;
            mesg->seq = htons(new_seq);
        }
    }
    timer = clock() - timer;

    free(mesg);

    status = srtp_dealloc(srtp);
    if (status) {
        printf("error: srtp_dealloc() failed with error code %d\n", status);
        exit(1);
    }

    return (double)(msg_len_octets)*8 * num_trials * CLOCKS_PER_SEC / timer;
}

double srtp_rejections_per_second(int msg_len_octets,
                                  const srtp_policy_t *policy)
{
    srtp_ctx_t *srtp;
    srtp_hdr_t *mesg;
    int i;
    int len;
    clock_t timer;
    int num_trials = 1000000;
    uint32_t ssrc = policy->ssrc.value;
    srtp_err_status_t status;

    /*
     * allocate and initialize an srtp session
     */

    status = srtp_create(&srtp, policy);
    if (status) {
        printf("error: srtp_create() failed with error code %d\n", status);
        exit(1);
    }

    mesg = srtp_create_test_packet(msg_len_octets, ssrc, &len);
    if (mesg == NULL) {
        return 0.0/* indicate failure by returning zero */
    }
    srtp_protect(srtp, (srtp_hdr_t *)mesg, &len);

    timer = clock();
    for (i = 0; i < num_trials; i++) {
        len = msg_len_octets;
        srtp_unprotect(srtp, (srtp_hdr_t *)mesg, &len);
    }
    timer = clock() - timer;

    free(mesg);

    status = srtp_dealloc(srtp);
    if (status) {
        printf("error: srtp_dealloc() failed with error code %d\n", status);
        exit(1);
    }

    return (double)num_trials * CLOCKS_PER_SEC / timer;
}

void err_check(srtp_err_status_t s)
{
    if (s != srtp_err_status_ok) {
        fprintf(stderr, "error: unexpected srtp failure (code %d)\n", s);
        exit(1);
    }
}

srtp_err_status_t srtp_test_call_protect(srtp_t srtp_sender,
                                         srtp_hdr_t *hdr,
                                         int *len,
                                         int mki_index)
{
    if (mki_index == -1) {
        return srtp_protect(srtp_sender, hdr, len);
    } else {
        return srtp_protect_mki(srtp_sender, hdr, len, 1, mki_index);
    }
}

srtp_err_status_t srtp_test_call_protect_rtcp(srtp_t srtp_sender,
                                              srtcp_hdr_t *hdr,
                                              int *len,
                                              int mki_index)
{
    if (mki_index == -1) {
        return srtp_protect_rtcp(srtp_sender, hdr, len);
    } else {
        return srtp_protect_rtcp_mki(srtp_sender, hdr, len, 1, mki_index);
    }
}

srtp_err_status_t srtp_test_call_unprotect(srtp_t srtp_sender,
                                           srtp_hdr_t *hdr,
                                           int *len,
                                           int use_mki)
{
    if (use_mki == -1) {
        return srtp_unprotect(srtp_sender, hdr, len);
    } else {
        return srtp_unprotect_mki(srtp_sender, hdr, len, use_mki);
    }
}

srtp_err_status_t srtp_test_call_unprotect_rtcp(srtp_t srtp_sender,
                                                srtcp_hdr_t *hdr,
                                                int *len,
                                                int use_mki)
{
    if (use_mki == -1) {
        return srtp_unprotect_rtcp(srtp_sender, hdr, len);
    } else {
        return srtp_unprotect_rtcp_mki(srtp_sender, hdr, len, use_mki);
    }
}

srtp_err_status_t srtp_test(const srtp_policy_t *policy,
                            int extension_header,
                            int mki_index)
{
    int i;
    srtp_t srtp_sender;
    srtp_t srtp_rcvr;
    srtp_err_status_t status = srtp_err_status_ok;
    srtp_hdr_t *hdr, *hdr2;
    uint8_t hdr_enc[64];
    uint8_t *pkt_end;
    int msg_len_octets, msg_len_enc, msg_len;
    int len, len2;
    uint32_t tag_length;
    uint32_t ssrc;
    srtp_policy_t *rcvr_policy;
    srtp_policy_t tmp_policy;
    int header = 1;
    int use_mki = 0;

    if (mki_index >= 0)
        use_mki = 1;

    if (extension_header) {
        memcpy(&tmp_policy, policy, sizeof(srtp_policy_t));
        tmp_policy.enc_xtn_hdr = &header;
        tmp_policy.enc_xtn_hdr_count = 1;
        err_check(srtp_create(&srtp_sender, &tmp_policy));
    } else {
        err_check(srtp_create(&srtp_sender, policy));
    }

    /* print out policy */
    err_check(srtp_session_print_policy(srtp_sender));

    /*
     * initialize data buffer, using the ssrc in the policy unless that
     * value is a wildcard, in which case we'll just use an arbitrary
     * one
     */

    if (policy->ssrc.type != ssrc_specific) {
        ssrc = 0xdecafbad;
    } else {
        ssrc = policy->ssrc.value;
    }
    msg_len_octets = 28;
    if (extension_header) {
        hdr = srtp_create_test_packet_ext_hdr(msg_len_octets, ssrc, &len);
        hdr2 = srtp_create_test_packet_ext_hdr(msg_len_octets, ssrc, &len2);
    } else {
        hdr = srtp_create_test_packet(msg_len_octets, ssrc, &len);
        hdr2 = srtp_create_test_packet(msg_len_octets, ssrc, &len2);
    }

    /* save original msg len */
    msg_len = len;

    if (hdr == NULL) {
        free(hdr2);
        return srtp_err_status_alloc_fail;
    }
    if (hdr2 == NULL) {
        free(hdr);
        return srtp_err_status_alloc_fail;
    }

    debug_print(mod_driver, "before protection:\n%s",
                srtp_packet_to_string(hdr, len));

#if PRINT_REFERENCE_PACKET
    debug_print(mod_driver, "reference packet before protection:\n%s",
                octet_string_hex_string((uint8_t *)hdr, len));
#endif
    err_check(srtp_test_call_protect(srtp_sender, hdr, &len, mki_index));

    debug_print(mod_driver, "after protection:\n%s",
                srtp_packet_to_string(hdr, len));
#if PRINT_REFERENCE_PACKET
    debug_print(mod_driver, "after protection:\n%s",
                octet_string_hex_string((uint8_t *)hdr, len));
#endif

    /* save protected message and length */
    memcpy(hdr_enc, hdr, len);
    msg_len_enc = len;

    /*
     * check for overrun of the srtp_protect() function
     *
     * The packet is followed by a value of 0xfffff; if the value of the
     * data following the packet is different, then we know that the
     * protect function is overwriting the end of the packet.
     */

    err_check(srtp_get_protect_trailer_length(srtp_sender, use_mki, mki_index,
                                              &tag_length));
    pkt_end = (uint8_t *)hdr + msg_len + tag_length;
    for (i = 0; i < 4; i++) {
        if (pkt_end[i] != 0xff) {
            fprintf(stdout,
                    "overwrite in srtp_protect() function "
                    "(expected %x, found %x in trailing octet %d)\n",
                    0xff, ((uint8_t *)hdr)[i], i);
            free(hdr);
            free(hdr2);
            return srtp_err_status_algo_fail;
        }
    }

    /*
     * if the policy includes confidentiality, check that ciphertext is
     * different than plaintext
     *
     * Note that this check will give false negatives, with some small
     * probability, especially if the packets are short.  For that
     * reason, we skip this check if the plaintext is less than four
     * octets long.
     */

    if ((policy->rtp.sec_serv & sec_serv_conf) && (msg_len_octets >= 4)) {
        printf("testing that ciphertext is distinct from plaintext...");
        status = srtp_err_status_algo_fail;
        for (i = 12; i < msg_len_octets + 12; i++) {
            if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
                status = srtp_err_status_ok;
            }
        }
        if (status) {
            printf("failed\n");
            free(hdr);
            free(hdr2);
            return status;
        }
        printf("passed\n");
    }

    /*
     * if the policy uses a 'wildcard' ssrc, then we need to make a copy
     * of the policy that changes the direction to inbound
     *
     * we always copy the policy into the rcvr_policy, since otherwise
     * the compiler would fret about the constness of the policy
     */

    rcvr_policy = (srtp_policy_t *)malloc(sizeof(srtp_policy_t));
    if (rcvr_policy == NULL) {
        free(hdr);
        free(hdr2);
        return srtp_err_status_alloc_fail;
    }
    if (extension_header) {
        memcpy(rcvr_policy, &tmp_policy, sizeof(srtp_policy_t));
        if (tmp_policy.ssrc.type == ssrc_any_outbound) {
            rcvr_policy->ssrc.type = ssrc_any_inbound;
        }
    } else {
        memcpy(rcvr_policy, policy, sizeof(srtp_policy_t));
        if (policy->ssrc.type == ssrc_any_outbound) {
            rcvr_policy->ssrc.type = ssrc_any_inbound;
        }
    }

    err_check(srtp_create(&srtp_rcvr, rcvr_policy));

    err_check(srtp_test_call_unprotect(srtp_rcvr, hdr, &len, use_mki));

    debug_print(mod_driver, "after unprotection:\n%s",
                srtp_packet_to_string(hdr, len));

    /* verify that the unprotected packet matches the origial one */
    for (i = 0; i < len; i++) {
        if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
            fprintf(stdout, "mismatch at octet %d\n", i);
            status = srtp_err_status_algo_fail;
        }
    }
    if (status) {
        free(hdr);
        free(hdr2);
        free(rcvr_policy);
        return status;
    }

    /*
     * if the policy includes authentication, then test for false positives
     */

    if (policy->rtp.sec_serv & sec_serv_auth) {
        char *data = ((char *)hdr) + (extension_header ? 24 : 12);

        printf("testing for false positives in replay check...");

        /* unprotect a second time - should fail with a replay error */
        status =
            srtp_test_call_unprotect(srtp_rcvr, hdr, &msg_len_enc, use_mki);
        if (status != srtp_err_status_replay_fail) {
            printf("failed with error code %d\n", status);
            free(hdr);
            free(hdr2);
            free(rcvr_policy);
            return srtp_err_status_algo_fail;
        } else {
            printf("passed\n");
        }

        printf("testing for false positives in auth check...");

        /* increment sequence number in header */
        hdr->seq++;

        /* apply protection */
        err_check(srtp_test_call_protect(srtp_sender, hdr, &len, mki_index));

        /* flip bits in packet */
        data[0] ^= 0xff;

        /* unprotect, and check for authentication failure */
        status = srtp_test_call_unprotect(srtp_rcvr, hdr, &len, use_mki);
        if (status != srtp_err_status_auth_fail) {
            printf("failed with error code %d\n", status);
            printf("failed\n");
            free(hdr);
            free(hdr2);
            free(rcvr_policy);
            return srtp_err_status_algo_fail;
        } else {
            printf("passed\n");
        }
    }

    err_check(srtp_dealloc(srtp_sender));
    err_check(srtp_dealloc(srtp_rcvr));

    free(hdr);
    free(hdr2);
    free(rcvr_policy);
    return srtp_err_status_ok;
}

srtp_err_status_t srtcp_test(const srtp_policy_t *policy, int mki_index)
{
    int i;
    srtp_t srtcp_sender;
    srtp_t srtcp_rcvr;
    srtp_err_status_t status = srtp_err_status_ok;
    srtcp_hdr_t *hdr, *hdr2;
    uint8_t hdr_enc[64];
    uint8_t *pkt_end;
    int msg_len_octets, msg_len_enc, msg_len;
    int len, len2;
    uint32_t tag_length;
    uint32_t ssrc;
    srtp_policy_t *rcvr_policy;
    int use_mki = 0;

    if (mki_index >= 0)
        use_mki = 1;

    err_check(srtp_create(&srtcp_sender, policy));

    /* print out policy */
    err_check(srtp_session_print_policy(srtcp_sender));

    /*
     * initialize data buffer, using the ssrc in the policy unless that
     * value is a wildcard, in which case we'll just use an arbitrary
     * one
     */

    if (policy->ssrc.type != ssrc_specific) {
        ssrc = 0xdecafbad;
    } else {
        ssrc = policy->ssrc.value;
    }
    msg_len_octets = 28;
    hdr = srtp_create_rtcp_test_packet(msg_len_octets, ssrc, &len);
    /* save message len */
    msg_len = len;

    if (hdr == NULL) {
        return srtp_err_status_alloc_fail;
    }
    hdr2 = srtp_create_rtcp_test_packet(msg_len_octets, ssrc, &len2);
    if (hdr2 == NULL) {
        free(hdr);
        return srtp_err_status_alloc_fail;
    }

    debug_print(mod_driver, "before protection:\n%s",
                srtp_rtcp_packet_to_string(hdr, len));

#if PRINT_REFERENCE_PACKET
    debug_print(mod_driver, "reference packet before protection:\n%s",
                octet_string_hex_string((uint8_t *)hdr, len));
#endif
    err_check(srtp_test_call_protect_rtcp(srtcp_sender, hdr, &len, mki_index));

    debug_print(mod_driver, "after protection:\n%s",
                srtp_rtcp_packet_to_string(hdr, len));
#if PRINT_REFERENCE_PACKET
    debug_print(mod_driver, "after protection:\n%s",
                octet_string_hex_string((uint8_t *)hdr, len));
#endif

    /* save protected message and length */
    memcpy(hdr_enc, hdr, len);
    msg_len_enc = len;

    /*
     * check for overrun of the srtp_protect_rtcp() function
     *
     * The packet is followed by a value of 0xfffff; if the value of the
     * data following the packet is different, then we know that the
     * protect function is overwriting the end of the packet.
     */

    srtp_get_protect_rtcp_trailer_length(srtcp_sender, use_mki, mki_index,
                                         &tag_length);
    pkt_end = (uint8_t *)hdr + msg_len + tag_length;
    for (i = 0; i < 4; i++) {
        if (pkt_end[i] != 0xff) {
            fprintf(stdout,
                    "overwrite in srtp_protect_rtcp() function "
                    "(expected %x, found %x in trailing octet %d)\n",
                    0xff, ((uint8_t *)hdr)[i], i);
            free(hdr);
            free(hdr2);
            return srtp_err_status_algo_fail;
        }
    }

    /*
     * if the policy includes confidentiality, check that ciphertext is
     * different than plaintext
     *
     * Note that this check will give false negatives, with some small
     * probability, especially if the packets are short.  For that
     * reason, we skip this check if the plaintext is less than four
     * octets long.
     */

    if ((policy->rtcp.sec_serv & sec_serv_conf) && (msg_len_octets >= 4)) {
        printf("testing that ciphertext is distinct from plaintext...");
        status = srtp_err_status_algo_fail;
        for (i = 12; i < msg_len_octets + 12; i++) {
            if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
                status = srtp_err_status_ok;
            }
        }
        if (status) {
            printf("failed\n");
            free(hdr);
            free(hdr2);
            return status;
        }
        printf("passed\n");
    }

    /*
     * if the policy uses a 'wildcard' ssrc, then we need to make a copy
     * of the policy that changes the direction to inbound
     *
     * we always copy the policy into the rcvr_policy, since otherwise
     * the compiler would fret about the constness of the policy
     */

    rcvr_policy = (srtp_policy_t *)malloc(sizeof(srtp_policy_t));
    if (rcvr_policy == NULL) {
        free(hdr);
        free(hdr2);
        return srtp_err_status_alloc_fail;
    }
    memcpy(rcvr_policy, policy, sizeof(srtp_policy_t));
    if (policy->ssrc.type == ssrc_any_outbound) {
        rcvr_policy->ssrc.type = ssrc_any_inbound;
    }

    err_check(srtp_create(&srtcp_rcvr, rcvr_policy));

    err_check(srtp_test_call_unprotect_rtcp(srtcp_rcvr, hdr, &len, use_mki));

    debug_print(mod_driver, "after unprotection:\n%s",
                srtp_rtcp_packet_to_string(hdr, len));

    /* verify that the unprotected packet matches the original one */
    for (i = 0; i < len; i++) {
        if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
            fprintf(stdout, "mismatch at octet %d\n", i);
            status = srtp_err_status_algo_fail;
        }
    }
    if (status) {
        free(hdr);
        free(hdr2);
        free(rcvr_policy);
        return status;
    }

    /*
     * if the policy includes authentication, then test for false positives
     */

    if (policy->rtp.sec_serv & sec_serv_auth) {
        char *data = ((char *)hdr) + 12;

        printf("testing for false positives in replay check...");

        /* unprotect a second time - should fail with a replay error */
        status = srtp_test_call_unprotect_rtcp(srtcp_rcvr, hdr, &msg_len_enc,
                                               use_mki);
        if (status != srtp_err_status_replay_fail) {
            printf("failed with error code %d\n", status);
            free(hdr);
            free(hdr2);
            free(rcvr_policy);
            return srtp_err_status_algo_fail;
        } else {
            printf("passed\n");
        }

        printf("testing for false positives in auth check...");

        /* apply protection */
        err_check(
            srtp_test_call_protect_rtcp(srtcp_sender, hdr, &len, mki_index));

        /* flip bits in packet */
        data[0] ^= 0xff;

        /* unprotect, and check for authentication failure */
        status = srtp_test_call_unprotect_rtcp(srtcp_rcvr, hdr, &len, use_mki);
        if (status != srtp_err_status_auth_fail) {
            printf("failed with error code %d\n", status);
            printf("failed\n");
            free(hdr);
            free(hdr2);
            free(rcvr_policy);
            return srtp_err_status_algo_fail;
        } else {
            printf("passed\n");
        }
    }

    err_check(srtp_dealloc(srtcp_sender));
    err_check(srtp_dealloc(srtcp_rcvr));

    free(hdr);
    free(hdr2);
    free(rcvr_policy);
    return srtp_err_status_ok;
}

struct srtp_session_print_stream_data {
    // set by callback to indicate failure
    srtp_err_status_t status;
    // indicates if it is the template stream or a regular stream
    int is_template;
};

int srtp_session_print_stream(srtp_stream_t stream, void *raw_data)
{
    static const char *serv_descr[4] = { "none""confidentiality",
                                         "authentication",
                                         "confidentiality and authentication" };
    static const char *direction[3] = { "unknown""outbound""inbound" };

    struct srtp_session_print_stream_data *data =
        (struct srtp_session_print_stream_data *)raw_data;
    srtp_session_keys_t *session_keys = &stream->session_keys[0];
    char ssrc_text[32];

    if (!data->is_template && stream->rtp_services > sec_serv_conf_and_auth) {
        data->status = srtp_err_status_bad_param;
        return 1;
    }

    if (data->is_template) {
        snprintf(ssrc_text, sizeof(ssrc_text), "any %s",
                 direction[stream->direction]);
    } else {
        snprintf(ssrc_text, sizeof(ssrc_text), "0x%08x", stream->ssrc);
    }

    printf("# SSRC:          %s\r\n"
           "# rtp cipher:    %s\r\n"
           "# rtp auth:      %s\r\n"
           "# rtp services:  %s\r\n"
           "# rtcp cipher:   %s\r\n"
           "# rtcp auth:     %s\r\n"
           "# rtcp services: %s\r\n"
           "# window size:   %lu\r\n"
           "# tx rtx allowed:%s\r\n",
           ssrc_text, session_keys->rtp_cipher->type->description,
           session_keys->rtp_auth->type->description,
           serv_descr[stream->rtp_services],
           session_keys->rtcp_cipher->type->description,
           session_keys->rtcp_auth->type->description,
           serv_descr[stream->rtcp_services],
           srtp_rdbx_get_window_size(&stream->rtp_rdbx),
           stream->allow_repeat_tx ? "true" : "false");

    printf("# Encrypted extension headers: ");
    if (stream->enc_xtn_hdr && stream->enc_xtn_hdr_count > 0) {
        int *enc_xtn_hdr = stream->enc_xtn_hdr;
        int count = stream->enc_xtn_hdr_count;
        while (count > 0) {
            printf("%d ", *enc_xtn_hdr);
            enc_xtn_hdr++;
            count--;
        }
        printf("\n");
    } else {
        printf("none\n");
    }

    return 0;
}

srtp_err_status_t srtp_session_print_policy(srtp_t srtp)
{
    struct srtp_session_print_stream_data data = { srtp_err_status_ok, 0 };

    /* sanity checking */
    if (srtp == NULL) {
        return srtp_err_status_fail;
    }

    /* if there's a template stream, print it out */
    if (srtp->stream_template != NULL) {
        data.is_template = 1;
        srtp_session_print_stream(srtp->stream_template, &data);
    }

    /* loop over streams in session, printing the policy of each */
    data.is_template = 0;
    srtp_stream_list_for_each(srtp->stream_list, srtp_session_print_stream,
                              &data);

    return data.status;
}

srtp_err_status_t srtp_print_policy(const srtp_policy_t *policy)
{
    srtp_err_status_t status;
    srtp_t session;

    status = srtp_create(&session, policy);
    if (status) {
        return status;
    }
    status = srtp_session_print_policy(session);
    if (status) {
        return status;
    }
    status = srtp_dealloc(session);
    if (status) {
        return status;
    }
    return srtp_err_status_ok;
}

/*
 * srtp_print_packet(...) is for debugging only
 * it prints an RTP packet to the stdout
 *
 * note that this function is *not* threadsafe
 */


#include <stdio.h>

#define MTU 2048

char packet_string[MTU];

char *srtp_packet_to_string(srtp_hdr_t *hdr, int pkt_octet_len)
{
    int octets_in_rtp_header = 12;
    uint8_t *data = ((uint8_t *)hdr) + octets_in_rtp_header;
    int hex_len = pkt_octet_len - octets_in_rtp_header;

    /* sanity checking */
    if ((hdr == NULL) || (pkt_octet_len > MTU)) {
        return NULL;
    }

    /* write packet into string */
    snprintf(packet_string, sizeof(packet_string),
             "(s)rtp packet: {\n"
             "   version:\t%d\n"
             "   p:\t\t%d\n"
             "   x:\t\t%d\n"
             "   cc:\t\t%d\n"
             "   m:\t\t%d\n"
             "   pt:\t\t%x\n"
             "   seq:\t\t%x\n"
             "   ts:\t\t%x\n"
             "   ssrc:\t%x\n"
             "   data:\t%s\n"
             "} (%d octets in total)\n",
             hdr->version, hdr->p, hdr->x, hdr->cc, hdr->m, hdr->pt, hdr->seq,
             hdr->ts, hdr->ssrc, octet_string_hex_string(data, hex_len),
             pkt_octet_len);

    return packet_string;
}

char *srtp_rtcp_packet_to_string(srtcp_hdr_t *hdr, int pkt_octet_len)
{
    int octets_in_rtcp_header = 8;
    uint8_t *data = ((uint8_t *)hdr) + octets_in_rtcp_header;
    int hex_len = pkt_octet_len - octets_in_rtcp_header;

    /* sanity checking */
    if ((hdr == NULL) || (pkt_octet_len > MTU)) {
        return NULL;
    }

    /* write packet into string */
    snprintf(packet_string, sizeof(packet_string),
             "(s)rtcp packet: {\n"
             "   version:\t%d\n"
             "   p:\t\t%d\n"
             "   rc:\t\t%d\n"
             "   pt:\t\t%x\n"
             "   len:\t\t%x\n"
             "   ssrc:\t%x\n"
             "   data:\t%s\n"
             "} (%d octets in total)\n",
             hdr->version, hdr->p, hdr->rc, hdr->pt, hdr->len, hdr->ssrc,
             octet_string_hex_string(data, hex_len), pkt_octet_len);

    return packet_string;
}

/*
 * mips_estimate() is a simple function to estimate the number of
 * instructions per second that the host can perform.  note that this
 * function can be grossly wrong; you may want to have a manual sanity
 * check of its output!
 *
 * the 'ignore' pointer is there to convince the compiler to not just
 * optimize away the function
 */


double mips_estimate(int num_trials, int *ignore)
{
    clock_t t;
    volatile int i, sum;

    sum = 0;
    t = clock();
    for (i = 0; i < num_trials; i++) {
        sum += i;
    }
    t = clock() - t;
    if (t < 1) {
        t = 1;
    }

    /*   printf("%d\n", sum); */
    *ignore = sum;

    return (double)num_trials * CLOCKS_PER_SEC / t;
}

/*
 * srtp_validate() verifies the correctness of libsrtp by comparing
 * some computed packets against some pre-computed reference values.
 * These packets were made with the default SRTP policy.
 */


srtp_err_status_t srtp_validate(void)
{
    // clang-format off
    uint8_t srtp_plaintext_ref[28] = {
        0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab
    };
    uint8_t srtp_plaintext[38] = {
        0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };
    uint8_t srtp_ciphertext[38] = {
        0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0x4e, 0x55, 0xdc, 0x4c,
        0xe7, 0x99, 0x78, 0xd8, 0x8c, 0xa4, 0xd2, 0x15,
        0x94, 0x9d, 0x24, 0x02, 0xb7, 0x8d, 0x6a, 0xcc,
        0x99, 0xea, 0x17, 0x9b, 0x8d, 0xbb
    };
    uint8_t rtcp_plaintext_ref[24] = {
        0x81, 0xc8, 0x00, 0x0b, 0xca, 0xfe, 0xba, 0xbe,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
    };
    uint8_t rtcp_plaintext[38] = {
        0x81, 0xc8, 0x00, 0x0b, 0xca, 0xfe, 0xba, 0xbe,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };
    uint8_t srtcp_ciphertext[38] = {
        0x81, 0xc8, 0x00, 0x0b, 0xca, 0xfe, 0xba, 0xbe,
        0x71, 0x28, 0x03, 0x5b, 0xe4, 0x87, 0xb9, 0xbd,
        0xbe, 0xf8, 0x90, 0x41, 0xf9, 0x77, 0xa5, 0xa8,
        0x80, 0x00, 0x00, 0x01, 0x99, 0x3e, 0x08, 0xcd,
        0x54, 0xd6, 0xc1, 0x23, 0x07, 0x98
    };
    // clang-format on

    srtp_t srtp_snd, srtp_recv;
    srtp_err_status_t status;
    int len;
    srtp_policy_t policy;

    /*
     * create a session with a single stream using the default srtp
     * policy and with the SSRC value 0xcafebabe
     */

    memset(&policy, 0sizeof(policy));
    srtp_crypto_policy_set_rtp_default(&policy.rtp);
    srtp_crypto_policy_set_rtcp_default(&policy.rtcp);
    policy.ssrc.type = ssrc_specific;
    policy.ssrc.value = 0xcafebabe;
    policy.key = test_key;
    policy.deprecated_ekt = NULL;
    policy.window_size = 128;
    policy.allow_repeat_tx = 0;
    policy.next = NULL;

    status = srtp_create(&srtp_snd, &policy);
    if (status) {
        return status;
    }

    /*
     * protect plaintext, then compare with ciphertext
     */

    len = 28;
    status = srtp_protect(srtp_snd, srtp_plaintext, &len);
    if (status || (len != 38)) {
        return srtp_err_status_fail;
    }

    debug_print(mod_driver, "ciphertext:\n  %s",
                octet_string_hex_string(srtp_plaintext, len));
    debug_print(mod_driver, "ciphertext reference:\n  %s",
                octet_string_hex_string(srtp_ciphertext, len));

    if (srtp_octet_string_is_eq(srtp_plaintext, srtp_ciphertext, len)) {
        return srtp_err_status_fail;
    }

    /*
     * protect plaintext rtcp, then compare with srtcp ciphertext
     */

    len = 24;
    status = srtp_protect_rtcp(srtp_snd, rtcp_plaintext, &len);
    if (status || (len != 38)) {
        return srtp_err_status_fail;
    }

    debug_print(mod_driver, "srtcp ciphertext:\n  %s",
                octet_string_hex_string(rtcp_plaintext, len));
    debug_print(mod_driver, "srtcp ciphertext reference:\n  %s",
                octet_string_hex_string(srtcp_ciphertext, len));

    if (srtp_octet_string_is_eq(rtcp_plaintext, srtcp_ciphertext, len)) {
        return srtp_err_status_fail;
    }

    /*
     * create a receiver session context comparable to the one created
     * above - we need to do this so that the replay checking doesn't
     * complain
     */

    status = srtp_create(&srtp_recv, &policy);
    if (status) {
        return status;
    }

    /*
     * unprotect ciphertext, then compare with plaintext
     */

    status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len);
    if (status || (len != 28)) {
        return status;
    }

    if (srtp_octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len)) {
        return srtp_err_status_fail;
    }

    /*
     * unprotect srtcp ciphertext, then compare with rtcp plaintext
     */

    len = 38;
    status = srtp_unprotect_rtcp(srtp_recv, srtcp_ciphertext, &len);
    if (status || (len != 24)) {
        return status;
    }

    if (srtp_octet_string_is_eq(srtcp_ciphertext, rtcp_plaintext_ref, len)) {
        return srtp_err_status_fail;
    }

    status = srtp_dealloc(srtp_snd);
    if (status) {
        return status;
    }

    status = srtp_dealloc(srtp_recv);
    if (status) {
        return status;
    }

    return srtp_err_status_ok;
}

/*
 * srtp_validate_null_sha1_80() verifies the correctness of libsrtp by comparing
 * some computed packets against some pre-computed reference values.
 * These packets were made with a policy that applies null encryption
 * and HMAC authentication.
 */


srtp_err_status_t srtp_validate_null_sha1_80(void)
{
    // clang-format off
    uint8_t srtp_plaintext_ref[28] = {
        0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab
    };
    uint8_t srtp_plaintext[38] = {
        0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };
    uint8_t srtp_ciphertext[38] = {
        0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xa1, 0x36, 0x27,
        0x0b, 0x67, 0x91, 0x34, 0xce, 0x9b
    };
    uint8_t rtcp_plaintext_ref[24] = {
        0x81, 0xc8, 0x00, 0x0b, 0xca, 0xfe, 0xba, 0xbe,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
    };
    uint8_t rtcp_plaintext[38] = {
        0x81, 0xc8, 0x00, 0x0b, 0xca, 0xfe, 0xba, 0xbe,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };
    uint8_t srtcp_ciphertext[38] = {
        0x81, 0xc8, 0x00, 0x0b, 0xca, 0xfe, 0xba, 0xbe,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0x00, 0x00, 0x00, 0x01, 0xfe, 0x88, 0xc7, 0xfd,
        0xfd, 0x37, 0xeb, 0xce, 0x61, 0x5d,
    };
    // clang-format on

    srtp_t srtp_snd, srtp_recv;
    srtp_err_status_t status;
    int len;
    srtp_policy_t policy;

    /*
     * create a session with a single stream using the null cipher
     * and sha1_80 policy and with the SSRC value 0xcafebabe
     */

    memset(&policy, 0sizeof(policy));
    srtp_crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtp);
    srtp_crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtcp);
    policy.ssrc.type = ssrc_specific;
    policy.ssrc.value = 0xcafebabe;
    policy.key = test_key;
    policy.deprecated_ekt = NULL;
    policy.window_size = 128;
    policy.allow_repeat_tx = 0;
    policy.next = NULL;

    status = srtp_create(&srtp_snd, &policy);
    if (status) {
        return status;
    }

    /*
     * protect plaintext, then compare with ciphertext
     */

    len = 28;
    status = srtp_protect(srtp_snd, srtp_plaintext, &len);
    if (status || (len != 38)) {
        return srtp_err_status_fail;
    }

    debug_print(mod_driver, "ciphertext:\n  %s",
                octet_string_hex_string(srtp_plaintext, len));
    debug_print(mod_driver, "ciphertext reference:\n  %s",
                octet_string_hex_string(srtp_ciphertext, len));

    if (srtp_octet_string_is_eq(srtp_plaintext, srtp_ciphertext, len)) {
        return srtp_err_status_fail;
    }

    /*
     * protect plaintext rtcp, then compare with srtcp ciphertext
     */

    len = 24;
    status = srtp_protect_rtcp(srtp_snd, rtcp_plaintext, &len);
    if (status || (len != 38)) {
        return srtp_err_status_fail;
    }

    debug_print(mod_driver, "srtcp ciphertext:\n  %s",
                octet_string_hex_string(rtcp_plaintext, len));
    debug_print(mod_driver, "srtcp ciphertext reference:\n  %s",
                octet_string_hex_string(srtcp_ciphertext, len));

    if (srtp_octet_string_is_eq(rtcp_plaintext, srtcp_ciphertext, len)) {
        return srtp_err_status_fail;
    }

    /*
     * create a receiver session context comparable to the one created
     * above - we need to do this so that the replay checking doesn't
     * complain
     */

    status = srtp_create(&srtp_recv, &policy);
    if (status) {
        return status;
    }

    /*
     * unprotect ciphertext, then compare with plaintext
     */

    status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len);
    if (status || (len != 28)) {
        return status;
    }

    if (srtp_octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len)) {
        return srtp_err_status_fail;
    }

    /*
     * unprotect srtcp ciphertext, then compare with rtcp plaintext
     */

    len = 38;
    status = srtp_unprotect_rtcp(srtp_recv, srtcp_ciphertext, &len);
    if (status || (len != 24)) {
        return status;
    }

    if (srtp_octet_string_is_eq(srtcp_ciphertext, rtcp_plaintext_ref, len)) {
        return srtp_err_status_fail;
    }

    status = srtp_dealloc(srtp_snd);
    if (status) {
        return status;
    }

    status = srtp_dealloc(srtp_recv);
    if (status) {
        return status;
    }

    return srtp_err_status_ok;
}

/*
 * srtp_validate_null_null() verifies the correctness of libsrtp by comparing
 * some computed packets against some pre-computed reference values.
 * These packets were made with a policy that applies null encryption
 * and null authentication.
 */


srtp_err_status_t srtp_validate_null_null(void)
{
    // clang-format off
    uint8_t srtp_plaintext_ref[28] = {
        0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab
    };
    uint8_t srtp_plaintext[28] = {
        0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab,
    };
    uint8_t srtp_ciphertext[28] = {
        0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab,
    };
    uint8_t rtcp_plaintext_ref[24] = {
        0x81, 0xc8, 0x00, 0x0b, 0xca, 0xfe, 0xba, 0xbe,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
    };
    uint8_t rtcp_plaintext[28] = {
        0x81, 0xc8, 0x00, 0x0b, 0xca, 0xfe, 0xba, 0xbe,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0x00, 0x00, 0x00, 0x00,
    };
    uint8_t srtcp_ciphertext[28] = {
        0x81, 0xc8, 0x00, 0x0b, 0xca, 0xfe, 0xba, 0xbe,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0x00, 0x00, 0x00, 0x01,
    };
    // clang-format on

    srtp_t srtp_snd, srtp_recv;
    srtp_err_status_t status;
    int len;
    srtp_policy_t policy;

    /*
     * create a session with a single stream using the null cipher
     * and null hmac policy and with the SSRC value 0xcafebabe
     */

    memset(&policy, 0sizeof(policy));
    srtp_crypto_policy_set_null_cipher_hmac_null(&policy.rtp);
    srtp_crypto_policy_set_null_cipher_hmac_null(&policy.rtcp);
    policy.ssrc.type = ssrc_specific;
    policy.ssrc.value = 0xcafebabe;
    /*
     * We need some non-zero value set here
     */

    policy.key = (void *)(uintptr_t)-1;
    policy.window_size = 128;
    policy.allow_repeat_tx = 0;
    policy.next = NULL;

    status = srtp_create(&srtp_snd, &policy);
    if (status) {
        return status;
    }

    /*
     * protect plaintext, then compare with ciphertext
     */

    len = 28;
    status = srtp_protect(srtp_snd, srtp_plaintext, &len);
    if (status || (len != 28)) {
        return srtp_err_status_fail;
    }
    if (status) {
        return status;
    }

    debug_print(mod_driver, "ciphertext:\n  %s",
                octet_string_hex_string(srtp_plaintext, len));
    debug_print(mod_driver, "ciphertext reference:\n  %s",
                octet_string_hex_string(srtp_ciphertext, len));

    if (srtp_octet_string_is_eq(srtp_plaintext, srtp_ciphertext, len)) {
        return srtp_err_status_fail;
    }

    /*
     * protect plaintext rtcp, then compare with srtcp ciphertext
     */

    len = 24;
    status = srtp_protect_rtcp(srtp_snd, rtcp_plaintext, &len);
    if (!status && (len != 28)) {
        status = srtp_err_status_fail;
    }
    if (status) {
        return status;
    }

    debug_print(mod_driver, "srtcp ciphertext:\n  %s",
                octet_string_hex_string(rtcp_plaintext, len));
    debug_print(mod_driver, "srtcp ciphertext reference:\n  %s",
                octet_string_hex_string(srtcp_ciphertext, len));

    if (srtp_octet_string_is_eq(rtcp_plaintext, srtcp_ciphertext, len)) {
        return srtp_err_status_fail;
    }

    /*
     * create a receiver session context comparable to the one created
     * above - we need to do this so that the replay checking doesn't
     * complain
     */

    status = srtp_create(&srtp_recv, &policy);
    if (status) {
        return status;
    }

    /*
     * unprotect ciphertext, then compare with plaintext
     */

    status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len);
    if (!status && (len != 28)) {
        status = srtp_err_status_fail;
    }
    if (status) {
        return status;
    }

    if (srtp_octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len)) {
        return srtp_err_status_fail;
    }

    /*
     * unprotect srtcp ciphertext, then compare with rtcp plaintext
     */

    len = 28;
    status = srtp_unprotect_rtcp(srtp_recv, srtcp_ciphertext, &len);
    if (!status && (len != 24)) {
        status = srtp_err_status_fail;
    }
    if (status) {
        return status;
    }

    if (srtp_octet_string_is_eq(srtcp_ciphertext, rtcp_plaintext_ref, len)) {
        return srtp_err_status_fail;
    }

    status = srtp_dealloc(srtp_snd);
    if (status) {
        return status;
    }

    status = srtp_dealloc(srtp_recv);
    if (status) {
        return status;
    }

    return srtp_err_status_ok;
}

/*
 * srtp_validate_cryptex() verifies the correctness of libsrtp by comparing
 * some computed packets against some pre-computed reference values.
 * These packets were made with the default SRTP policy.
 */

srtp_err_status_t srtp_validate_cryptex(void)
{
    // clang-format off
    /* Plaintext packet with 1-byte header extension */
    char *srtp_1bytehdrext_ref =
        "900f1235"
        "decafbad"
        "cafebabe"
        "bede0001"
        "51000200"
        "abababab"
        "abababab"
        "abababab"
        "abababab";

    /* AES-CTR/HMAC-SHA1 Ciphertext packet with 1-byte header extension */
    char *srtp_1bytehdrext_cryptex =
        "900f1235"
        "decafbad"
        "cafebabe"
        "c0de0001"
        "eb923652"
        "51c3e036"
        "f8de27e9"
        "c27ee3e0"
        "b4651d9f"
        "bc4218a7"
        "0244522f"
        "34a5";

    /* Plaintext packet with 2-byte header extension */
    char *srtp_2bytehdrext_ref =
        "900f1236"
        "decafbad"
        "cafebabe"
        "10000001"
        "05020002"
        "abababab"
        "abababab"
        "abababab"
        "abababab";

    /* AES-CTR/HMAC-SHA1 Ciphertext packet with 2-byte header extension */
    char *srtp_2bytehdrext_cryptex =
        "900f1236"
        "decafbad"
        "cafebabe"
        "c2de0001"
        "4ed9cc4e"
        "6a712b30"
        "96c5ca77"
        "339d4204"
        "ce0d7739"
        "6cab6958"
        "5fbce381"
        "94a5";

    /* Plaintext packet with 1-byte header extension and CSRC fields. */
    char *srtp_1bytehdrext_cc_ref =
        "920f1238"
        "decafbad"
        "cafebabe"
        "0001e240"
        "0000b26e"
        "bede0001"
        "51000200"
        "abababab"
        "abababab"
        "abababab"
        "abababab";

    char *srtp_1bytehdrext_cc_cryptex =
        "920f1238"
        "decafbad"
        "cafebabe"
        "8bb6e12b"
        "5cff16dd"
        "c0de0001"
        "92838c8c"
        "09e58393"
        "e1de3a9a"
        "74734d67"
        "45671338"
        "c3acf11d"
        "a2df8423"
        "bee0";

    /* Plaintext packet with 2-byte header extension and CSRC fields. */
    char *srtp_2bytehdrext_cc_ref =
        "920f1239"
        "decafbad"
        "cafebabe"
        "0001e240"
        "0000b26e"
        "10000001"
        "05020002"
        "abababab"
        "abababab"
        "abababab"
        "abababab";

    char *srtp_2bytehdrext_cc_cryptex =
        "920f1239"
        "decafbad"
        "cafebabe"
        "f70e513e"
        "b90b9b25"
        "c2de0001"
        "bbed4848"
        "faa64466"
        "5f3d7f34"
        "125914e9"
        "f4d0ae92"
        "3c6f479b"
        "95a0f7b5"
        "3133";

    /* Plaintext packet with empty 1-byte header extension and CSRC fields. */
    char *srtp_1byte_empty_hdrext_cc_ref =
        "920f123a"
        "decafbad"
        "cafebabe"
        "0001e240"
        "0000b26e"
        "bede0000"
        "abababab"
        "abababab"
        "abababab"
        "abababab";

    char *srtp_1byte_empty_hdrext_cc_cryptex =
        "920f123a"
        "decafbad"
        "cafebabe"
        "7130b6ab"
        "fe2ab0e3"
        "c0de0000"
        "e3d9f64b"
        "25c9e74c"
        "b4cf8e43"
        "fb92e378"
        "1c2c0cea"
        "b6b3a499"
        "a14c";

    /* Plaintext packet with empty 2-byte header extension and CSRC fields. */
    char *srtp_2byte_empty_hdrext_cc_ref =
        "920f123b"
        "decafbad"
        "cafebabe"
        "0001e240"
        "0000b26e"
        "10000000"
        "abababab"
        "abababab"
        "abababab"
        "abababab";

    char *srtp_2byte_empty_hdrext_cc_cryptex =
        "920f123b"
        "decafbad"
        "cafebabe"
        "cbf24c12"
        "4330e1c8"
        "c2de0000"
        "599dd45b"
        "c9d687b6"
        "03e8b59d"
        "771fd38e"
        "88b170e0"
        "cd31e125"
        "eabe";

    // clang-format on

    const struct test_vectors_t vectors[6] = {
        { "Plaintext packet with 1-byte header extension", srtp_1bytehdrext_ref,
          srtp_1bytehdrext_cryptex },
        { "Plaintext packet with 2-byte header extension", srtp_2bytehdrext_ref,
          srtp_2bytehdrext_cryptex },
        { "Plaintext packet with 1-byte header extension and CSRC fields",
          srtp_1bytehdrext_cc_ref, srtp_1bytehdrext_cc_cryptex },
        { "Plaintext packet with 2-byte header extension and CSRC fields",
          srtp_2bytehdrext_cc_ref, srtp_2bytehdrext_cc_cryptex },
        { "Plaintext packet with empty 1-byte header extension and CSRC fields",
          srtp_1byte_empty_hdrext_cc_ref, srtp_1byte_empty_hdrext_cc_cryptex },
        { "Plaintext packet with empty 2-byte header extension and CSRC fields",
          srtp_2byte_empty_hdrext_cc_ref, srtp_2byte_empty_hdrext_cc_cryptex },
    };
    const size_t num_vectors = sizeof(vectors) / sizeof(vectors[0]);

    srtp_t srtp_snd, srtp_recv;
    int len, ref_len, enc_len;
    srtp_policy_t policy;

    /*
     * create a session with a single stream using the default srtp
     * policy and with the SSRC value 0xcafebabe
     */

    memset(&policy, 0sizeof(policy));
    srtp_crypto_policy_set_rtp_default(&policy.rtp);
    srtp_crypto_policy_set_rtcp_default(&policy.rtcp);
    policy.ssrc.type = ssrc_specific;
    policy.ssrc.value = 0xcafebabe;
    policy.key = test_key;
    policy.window_size = 128;
    policy.allow_repeat_tx = 0;
    policy.next = NULL;

    for (size_t i = 0; i < num_vectors; ++i) {
        char packet[1400];
        char reference[1400];
        char ciphertext[1400];

        /* Initialize reference test vectors */
        ref_len = hex_string_to_octet_string(reference, vectors[i].plaintext,
                                             sizeof(reference)) /
                  2;
        enc_len = hex_string_to_octet_string(ciphertext, vectors[i].ciphertext,
                                             sizeof(ciphertext)) /
                  2;

        /* Initialize test packet */
        len = ref_len;
        memcpy(packet, reference, len);
        printf("%s\n", vectors[i].name);
        /*
         * protect plaintext, then compare with ciphertext
         */

        debug_print(mod_driver, "test vector: %s\n", vectors[i].name);

        CHECK_OK(srtp_create(&srtp_snd, &policy));
        CHECK_OK(srtp_set_stream_use_cryptex(srtp_snd, &policy.ssrc, 1));

        CHECK_OK(srtp_protect(srtp_snd, packet, &len));
        CHECK(len == enc_len);

        debug_print(mod_driver, "ciphertext:\n  %s",
                    octet_string_hex_string(packet, len));
        debug_print(mod_driver, "ciphertext reference:\n  %s",
                    octet_string_hex_string(ciphertext, len));

        CHECK_BUFFER_EQUAL(packet, ciphertext, len);

        CHECK_OK(srtp_dealloc(srtp_snd));

        CHECK_OK(srtp_create(&srtp_recv, &policy));
        CHECK_OK(srtp_set_stream_use_cryptex(srtp_recv, &policy.ssrc, 1));

        /*
         * unprotect ciphertext, then compare with plaintext
         */

        CHECK_OK(srtp_unprotect(srtp_recv, packet, &len));
        CHECK(len == ref_len);

        CHECK_BUFFER_EQUAL(packet, reference, len);

        CHECK_OK(srtp_dealloc(srtp_recv));
    }

    return srtp_err_status_ok;
}

srtp_err_status_t srtp_test_cryptex_csrc_but_no_extension_header(void)
{
    // clang-format off
    /* Plaintext packet with no header extension but CSRC fields. */
    char *srtp_cc_ref =
        "820f1238"
        "decafbad"
        "cafebabe"
        "0001e240"
        "0000b26e"
        "abababab"
        "abababab"
        "abababab"
        "abababab";
    // clang-format on

    /*
     * create a session with a single stream using the default srtp
     * policy and with the SSRC value 0xcafebabe
     */

    srtp_policy_t policy;
    memset(&policy, 0sizeof(policy));
    srtp_crypto_policy_set_rtp_default(&policy.rtp);
    srtp_crypto_policy_set_rtcp_default(&policy.rtcp);
    policy.ssrc.type = ssrc_specific;
    policy.ssrc.value = 0xcafebabe;
    policy.key = test_key;
    policy.window_size = 128;
    policy.allow_repeat_tx = 0;
    policy.next = NULL;

    srtp_t srtp_snd;
    CHECK_OK(srtp_create(&srtp_snd, &policy));
    CHECK_OK(srtp_set_stream_use_cryptex(srtp_snd, &policy.ssrc, 1));

    char packet[1400];
    int packet_len =
        hex_string_to_octet_string(packet, srtp_cc_ref, sizeof(packet)) / 2;

    CHECK_RETURN(srtp_protect(srtp_snd, packet, &packet_len),
                 srtp_err_status_cryptex_err);

    CHECK_OK(srtp_dealloc(srtp_snd));

    return srtp_err_status_ok;
}

srtp_err_status_t srtp_test_cryptex_disable(void)
{
    srtp_policy_t policy;
    memset(&policy, 0sizeof(policy));
    srtp_crypto_policy_set_rtp_default(&policy.rtp);
    srtp_crypto_policy_set_rtcp_default(&policy.rtcp);
    policy.ssrc.type = ssrc_specific;
    policy.ssrc.value = 0xcafebabe;
    policy.key = test_key;
    policy.window_size = 128;
    policy.allow_repeat_tx = 0;
    policy.next = NULL;

    srtp_t srtp_snd, srtp_recv;
    CHECK_OK(srtp_create(&srtp_snd, &policy));
    CHECK_OK(srtp_set_stream_use_cryptex(srtp_snd, &policy.ssrc, 1));
    CHECK_OK(srtp_create(&srtp_recv, &policy));
    CHECK_OK(srtp_set_stream_use_cryptex(srtp_recv, &policy.ssrc, 1));

    int packet_len;
    srtp_hdr_t *packet =
        srtp_create_test_packet_ext_hdr(100, policy.ssrc.value, &packet_len);
    uint8_t clear_text[1400];
    memcpy(clear_text, packet, packet_len);
    int clear_text_len = packet_len;

    CHECK_OK(srtp_protect(srtp_snd, packet, &packet_len));
    CHECK(packet_len > clear_text_len);
    CHECK(srtp_octet_string_is_eq((uint8_t *)packet, clear_text,
                                  clear_text_len) != 0);

    // clear text uses original one byte header extension profile
    CHECK(srtp_get_xtn_profile(clear_text) == 0xbede);
    // packet uses cryptex one byte header extension profile
    CHECK(srtp_get_xtn_profile((uint8_t *)packet) == 0xc0de);

    CHECK_OK(srtp_unprotect(srtp_recv, packet, &packet_len));
    CHECK(packet_len == clear_text_len);
    CHECK_BUFFER_EQUAL((char *)packet, (char *)clear_text, clear_text_len);

    // update squence number for next packet
    srtp_hdr_t *hdr = (srtp_hdr_t *)packet;
    hdr->seq = htons(ntohs(hdr->seq) + 1);
    memcpy(clear_text, packet, packet_len);

    // disbale cryptex at sender only
    CHECK_OK(srtp_set_stream_use_cryptex(srtp_snd, &policy.ssrc, 0));

    CHECK_OK(srtp_protect(srtp_snd, packet, &packet_len));
    CHECK(packet_len > clear_text_len);
    CHECK(srtp_octet_string_is_eq((uint8_t *)packet, clear_text,
                                  clear_text_len) != 0);

    // both use original one byte header extension profile as cryptex is
    // disabled
    CHECK(srtp_get_xtn_profile(clear_text) == 0xbede);
    CHECK(srtp_get_xtn_profile((uint8_t *)packet) == 0xbede);

    // unprotect should work as cryptex is detected dynamically
    CHECK_OK(srtp_unprotect(srtp_recv, packet, &packet_len));
    CHECK(packet_len == clear_text_len);
    CHECK_BUFFER_EQUAL((char *)packet, (char *)clear_text, clear_text_len);

    free(packet);
    CHECK_OK(srtp_dealloc(srtp_snd));
    CHECK_OK(srtp_dealloc(srtp_recv));

    return srtp_err_status_ok;
}

#ifdef GCM
/*
 * srtp_validate_gcm() verifies the correctness of libsrtp by comparing
 * an computed packet against the known ciphertext for the plaintext.
 */

srtp_err_status_t srtp_validate_gcm(void)
{
    // clang-format off
    uint8_t rtp_plaintext_ref[28] = {
        0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab
    };
    uint8_t rtp_plaintext[44] = {
        0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00
    };
    uint8_t srtp_ciphertext[44] = {
        0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xc5, 0x00, 0x2e, 0xde,
        0x04, 0xcf, 0xdd, 0x2e, 0xb9, 0x11, 0x59, 0xe0,
        0x88, 0x0a, 0xa0, 0x6e, 0xd2, 0x97, 0x68, 0x26,
        0xf7, 0x96, 0xb2, 0x01, 0xdf, 0x31, 0x31, 0xa1,
        0x27, 0xe8, 0xa3, 0x92
    };
    uint8_t rtcp_plaintext_ref[24] = {
        0x81, 0xc8, 0x00, 0x0b, 0xca, 0xfe, 0xba, 0xbe,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
    };
    uint8_t rtcp_plaintext[44] = {
        0x81, 0xc8, 0x00, 0x0b, 0xca, 0xfe, 0xba, 0xbe,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00
    };
    uint8_t srtcp_ciphertext[44] = {
        0x81, 0xc8, 0x00, 0x0b, 0xca, 0xfe, 0xba, 0xbe,
        0xc9, 0x8b, 0x8b, 0x5d, 0xf0, 0x39, 0x2a, 0x55,
        0x85, 0x2b, 0x6c, 0x21, 0xac, 0x8e, 0x70, 0x25,
        0xc5, 0x2c, 0x6f, 0xbe, 0xa2, 0xb3, 0xb4, 0x46,
        0xea, 0x31, 0x12, 0x3b, 0xa8, 0x8c, 0xe6, 0x1e,
        0x80, 0x00, 0x00, 0x01
    };
    // clang-format on

    srtp_t srtp_snd, srtp_recv;
    srtp_err_status_t status;
    int len;
    srtp_policy_t policy;

    /*
     * create a session with a single stream using the default srtp
     * policy and with the SSRC value 0xcafebabe
     */

    memset(&policy, 0sizeof(policy));
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtp);
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtcp);
    policy.ssrc.type = ssrc_specific;
    policy.ssrc.value = 0xcafebabe;
    policy.key = test_key_gcm;
    policy.deprecated_ekt = NULL;
    policy.window_size = 128;
    policy.allow_repeat_tx = 0;
    policy.next = NULL;

    status = srtp_create(&srtp_snd, &policy);
    if (status) {
        return status;
    }

    /*
     * protect plaintext rtp, then compare with srtp ciphertext
     */

    len = 28;
    status = srtp_protect(srtp_snd, rtp_plaintext, &len);
    if (status || (len != 44)) {
        return srtp_err_status_fail;
    }

    debug_print(mod_driver, "srtp ciphertext:\n  %s",
                octet_string_hex_string(rtp_plaintext, len));
    debug_print(mod_driver, "srtp ciphertext reference:\n  %s",
                octet_string_hex_string(srtp_ciphertext, len));

    if (srtp_octet_string_is_eq(rtp_plaintext, srtp_ciphertext, len)) {
        return srtp_err_status_fail;
    }

    /*
     * protect plaintext rtcp, then compare with srtcp ciphertext
     */
    len = 24;
    status = srtp_protect_rtcp(srtp_snd, rtcp_plaintext, &len);
    if (status || (len != 44)) {
        return srtp_err_status_fail;
    }

    debug_print(mod_driver, "srtcp ciphertext:\n  %s",
                octet_string_hex_string(rtcp_plaintext, len));
    debug_print(mod_driver, "srtcp ciphertext reference:\n  %s",
                octet_string_hex_string(srtcp_ciphertext, len));

    if (srtp_octet_string_is_eq(rtcp_plaintext, srtcp_ciphertext, len)) {
        return srtp_err_status_fail;
    }

    /*
     * create a receiver session context comparable to the one created
     * above - we need to do this so that the replay checking doesn't
     * complain
     */

    status = srtp_create(&srtp_recv, &policy);
    if (status) {
        return status;
    }

    /*
     * unprotect srtp ciphertext, then compare with rtp plaintext
     */

    len = 44;
    status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len);
    if (status || (len != 28)) {
        return status;
    }

    if (srtp_octet_string_is_eq(srtp_ciphertext, rtp_plaintext_ref, len)) {
        return srtp_err_status_fail;
    }

    /*
     * unprotect srtcp ciphertext, then compare with rtcp plaintext
     */

    len = 44;
    status = srtp_unprotect_rtcp(srtp_recv, srtcp_ciphertext, &len);
    if (status || (len != 24)) {
        return status;
    }

    debug_print(mod_driver, "srtcp plain:\n  %s",
                octet_string_hex_string(srtcp_ciphertext, len));
    debug_print(mod_driver, "srtcp plain reference:\n  %s",
                octet_string_hex_string(rtcp_plaintext_ref,
                                        sizeof(rtcp_plaintext_ref)));

    if (srtp_octet_string_is_eq(srtcp_ciphertext, rtcp_plaintext_ref, len)) {
        return srtp_err_status_fail;
    }

    status = srtp_dealloc(srtp_snd);
    if (status) {
        return status;
    }

    status = srtp_dealloc(srtp_recv);
    if (status) {
        return status;
    }

    return srtp_err_status_ok;
}

/*
 * srtp_validate_gcm() verifies the correctness of libsrtp by comparing
 * an computed packet against the known ciphertext for the plaintext.
 */

srtp_err_status_t srtp_validate_gcm_cryptex(void)
{
    // clang-format off
    unsigned char test_key_gcm_cryptex[28] = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
        0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
        0xa8, 0xa9, 0xaa, 0xab
    };

    /* Plaintext packet with 1-byte header extension */
    char *srtp_1bytehdrext_ref =
        "900f1235"
        "decafbad"
        "cafebabe"
        "bede0001"
        "51000200"
        "abababab"
        "abababab"
        "abababab"
        "abababab";

    /* GCM Ciphertext packet with 1-byte header extension */
    char *srtp_1bytehdrext_cryptex_gcm =
        "900f1235"
        "decafbad"
        "cafebabe"
        "c0de0001"
        "39972dc9"
        "572c4d99"
        "e8fc355d"
        "e743fb2e"
        "94f9d8ff"
        "54e72f41"
        "93bbc5c7"
        "4ffab0fa"
        "9fa0fbeb";

    /* Plaintext packet with 2-byte header extension */
    char *srtp_2bytehdrext_ref =
        "900f1236"
        "decafbad"
        "cafebabe"
        "10000001"
        "05020002"
        "abababab"
        "abababab"
        "abababab"
        "abababab";

    /* GCM Ciphertext packet with 2-byte header extension */
    char *srtp_2bytehdrext_cryptex_gcm =
        "900f1236"
        "decafbad"
        "cafebabe"
        "c2de0001"
        "bb75a4c5"
        "45cd1f41"
        "3bdb7daa"
        "2b1e3263"
        "de313667"
        "c9632490"
        "81b35a65"
        "f5cb6c88"
        "b394235f";

    /* Plaintext packet with 1-byte header extension and CSRC fields. */
    char *srtp_1bytehdrext_cc_ref =
        "920f1238"
        "decafbad"
        "cafebabe"
        "0001e240"
        "0000b26e"
        "bede0001"
        "51000200"
        "abababab"
        "abababab"
        "abababab"
        "abababab";

    char *srtp_1bytehdrext_cc_cryptex_gcm =
        "920f1238"
        "decafbad"
        "cafebabe"
        "63bbccc4"
        "a7f695c4"
        "c0de0001"
        "8ad7c71f"
        "ac70a80c"
        "92866b4c"
        "6ba98546"
        "ef913586"
        "e95ffaaf"
        "fe956885"
        "bb0647a8"
        "bc094ac8";


    /* Plaintext packet with 2-byte header extension and CSRC fields. */
    char *srtp_2bytehdrext_cc_ref =
        "920f1239"
        "decafbad"
        "cafebabe"
        "0001e240"
        "0000b26e"
        "10000001"
        "05020002"
        "abababab"
        "abababab"
        "abababab"
        "abababab";

    char *srtp_2bytehdrext_cc_cryptex_gcm =
        "920f1239"
        "decafbad"
        "cafebabe"
        "3680524f"
        "8d312b00"
        "c2de0001"
        "c78d1200"
        "38422bc1"
        "11a7187a"
        "18246f98"
        "0c059cc6"
        "bc9df8b6"
        "26394eca"
        "344e4b05"
        "d80fea83";

    /* Plaintext packet with empty 1-byte header extension and CSRC fields. */
    char *srtp_1byte_empty_hdrext_cc_ref =
        "920f123a"
        "decafbad"
        "cafebabe"
        "0001e240"
        "0000b26e"
        "bede0000"
        "abababab"
        "abababab"
        "abababab"
        "abababab";

    char *srtp_1byte_empty_hdrext_cc_cryptex_gcm =
        "920f123a"
        "decafbad"
        "cafebabe"
        "15b6bb43"
        "37906fff"
        "c0de0000"
        "b7b96453"
        "7a2b03ab"
        "7ba5389c"
        "e9331712"
        "6b5d974d"
        "f30c6884"
        "dcb651c5"
        "e120c1da";

    /* Plaintext packet with empty 2-byte header extension and CSRC fields. */
    char *srtp_2byte_empty_hdrext_cc_ref =
        "920f123b"
        "decafbad"
        "cafebabe"
        "0001e240"
        "0000b26e"
        "10000000"
        "abababab"
        "abababab"
        "abababab"
        "abababab";

    char *srtp_2byte_empty_hdrext_cc_cryptex_gcm =
        "920f123b"
        "decafbad"
        "cafebabe"
        "dcb38c9e"
        "48bf95f4"
        "c2de0000"
        "61ee432c"
        "f9203170"
        "76613258"
        "d3ce4236"
        "c06ac429"
        "681ad084"
        "13512dc9"
        "8b5207d8";
    // clang-format on

    const struct test_vectors_t vectors[6] = {
        { "Plaintext packet with 1-byte header extension", srtp_1bytehdrext_ref,
          srtp_1bytehdrext_cryptex_gcm },
        { "Plaintext packet with 2-byte header extension", srtp_2bytehdrext_ref,
          srtp_2bytehdrext_cryptex_gcm },
        { "Plaintext packet with 1-byte header extension and CSRC fields",
          srtp_1bytehdrext_cc_ref, srtp_1bytehdrext_cc_cryptex_gcm },
        { "Plaintext packet with 2-byte header extension and CSRC fields",
          srtp_2bytehdrext_cc_ref, srtp_2bytehdrext_cc_cryptex_gcm },
        { "Plaintext packet with empty 1-byte header extension and CSRC fields",
          srtp_1byte_empty_hdrext_cc_ref,
          srtp_1byte_empty_hdrext_cc_cryptex_gcm },
        { "Plaintext packet with empty 2-byte header extension and CSRC fields",
          srtp_2byte_empty_hdrext_cc_ref,
          srtp_2byte_empty_hdrext_cc_cryptex_gcm },
    };
    const size_t num_vectors = sizeof(vectors) / sizeof(vectors[0]);

    srtp_t srtp_snd, srtp_recv;
    int len, ref_len, enc_len;
    srtp_policy_t policy;

    /*
     * create a session with a single stream using the default srtp
     * policy and with the SSRC value 0xcafebabe
     */

    memset(&policy, 0sizeof(policy));
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtp);
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtcp);
    policy.ssrc.type = ssrc_specific;
    policy.ssrc.value = 0xcafebabe;
    policy.key = test_key_gcm_cryptex;
    policy.window_size = 128;
    policy.allow_repeat_tx = 0;
    policy.next = NULL;

    CHECK_OK(srtp_create(&srtp_snd, &policy));
    CHECK_OK(srtp_set_stream_use_cryptex(srtp_snd, &policy.ssrc, 1));

    for (size_t i = 0; i < num_vectors; ++i) {
        char packet[1400];
        char reference[1400];
        char ciphertext[1400];

        /* Initialize reference test vectors */
        ref_len = hex_string_to_octet_string(reference, vectors[i].plaintext,
                                             sizeof(reference)) /
                  2;
        enc_len = hex_string_to_octet_string(ciphertext, vectors[i].ciphertext,
                                             sizeof(ciphertext)) /
                  2;

        /* Initialize test packet */
        len = ref_len;
        memcpy(packet, reference, len);
        printf("%s\n", vectors[i].name);
        /*
         * protect plaintext, then compare with ciphertext
         */

        debug_print(mod_driver, "test vector: %s\n", vectors[i].name);

        CHECK_OK(srtp_protect(srtp_snd, packet, &len));
        CHECK(len == enc_len);

        debug_print(mod_driver, "ciphertext:\n  %s",
                    octet_string_hex_string(packet, len));
        debug_print(mod_driver, "ciphertext reference:\n  %s",
                    octet_string_hex_string(ciphertext, len));

        CHECK_BUFFER_EQUAL(packet, ciphertext, len);

        /*
         * create a receiver session context comparable to the one created
         * above - we need to do this so that the replay checking doesn't
         * complain
         */

        CHECK_OK(srtp_create(&srtp_recv, &policy));
        CHECK_OK(srtp_set_stream_use_cryptex(srtp_recv, &policy.ssrc, 1));

        /*
         * unprotect ciphertext, then compare with plaintext
         */

        CHECK_OK(srtp_unprotect(srtp_recv, packet, &len));
        CHECK(len == ref_len);

        CHECK_BUFFER_EQUAL(packet, reference, len);

        CHECK_OK(srtp_dealloc(srtp_recv));
    }

    CHECK_OK(srtp_dealloc(srtp_snd));

    return srtp_err_status_ok;
}

#endif

/*
 * Test vectors taken from RFC 6904, Appendix A
 */

srtp_err_status_t srtp_validate_encrypted_extensions_headers(void)
{
    // clang-format off
    unsigned char test_key_ext_headers[30] = {
        0xe1, 0xf9, 0x7a, 0x0d, 0x3e, 0x01, 0x8b, 0xe0,
        0xd6, 0x4f, 0xa3, 0x2c, 0x06, 0xde, 0x41, 0x39,
        0x0e, 0xc6, 0x75, 0xad, 0x49, 0x8a, 0xfe, 0xeb,
        0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6
    };
    uint8_t srtp_plaintext_ref[56] = {
        0x90, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xBE, 0xDE, 0x00, 0x06,
        0x17, 0x41, 0x42, 0x73, 0xA4, 0x75, 0x26, 0x27,
        0x48, 0x22, 0x00, 0x00, 0xC8, 0x30, 0x8E, 0x46,
        0x55, 0x99, 0x63, 0x86, 0xB3, 0x95, 0xFB, 0x00,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab
    };
    uint8_t srtp_plaintext[66] = {
        0x90, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xBE, 0xDE, 0x00, 0x06,
        0x17, 0x41, 0x42, 0x73, 0xA4, 0x75, 0x26, 0x27,
        0x48, 0x22, 0x00, 0x00, 0xC8, 0x30, 0x8E, 0x46,
        0x55, 0x99, 0x63, 0x86, 0xB3, 0x95, 0xFB, 0x00,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00
    };
    uint8_t srtp_ciphertext[66] = {
        0x90, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xBE, 0xDE, 0x00, 0x06,
        0x17, 0x58, 0x8A, 0x92, 0x70, 0xF4, 0xE1, 0x5E,
        0x1C, 0x22, 0x00, 0x00, 0xC8, 0x30, 0x95, 0x46,
        0xA9, 0x94, 0xF0, 0xBC, 0x54, 0x78, 0x97, 0x00,
        0x4e, 0x55, 0xdc, 0x4c, 0xe7, 0x99, 0x78, 0xd8,
        0x8c, 0xa4, 0xd2, 0x15, 0x94, 0x9d, 0x24, 0x02,
        0x5a, 0x46, 0xb3, 0xca, 0x35, 0xc5, 0x35, 0xa8,
        0x91, 0xc7
    };
    // clang-format on

    srtp_t srtp_snd, srtp_recv;
    srtp_err_status_t status;
    int len;
    srtp_policy_t policy;
    int headers[3] = { 134 };

    /*
     * create a session with a single stream using the default srtp
     * policy and with the SSRC value 0xcafebabe
     */

    memset(&policy, 0sizeof(policy));
    srtp_crypto_policy_set_rtp_default(&policy.rtp);
    srtp_crypto_policy_set_rtcp_default(&policy.rtcp);
    policy.ssrc.type = ssrc_specific;
    policy.ssrc.value = 0xcafebabe;
    policy.key = test_key_ext_headers;
    policy.deprecated_ekt = NULL;
    policy.window_size = 128;
    policy.allow_repeat_tx = 0;
    policy.enc_xtn_hdr = headers;
    policy.enc_xtn_hdr_count = sizeof(headers) / sizeof(headers[0]);
    policy.next = NULL;

    status = srtp_create(&srtp_snd, &policy);
    if (status)
        return status;

    /*
     * protect plaintext, then compare with ciphertext
     */

    len = sizeof(srtp_plaintext_ref);
    status = srtp_protect(srtp_snd, srtp_plaintext, &len);
    if (status || (len != sizeof(srtp_plaintext)))
        return srtp_err_status_fail;

    debug_print(mod_driver, "ciphertext:\n  %s",
                srtp_octet_string_hex_string(srtp_plaintext, len));
    debug_print(mod_driver, "ciphertext reference:\n  %s",
                srtp_octet_string_hex_string(srtp_ciphertext, len));

    if (srtp_octet_string_is_eq(srtp_plaintext, srtp_ciphertext, len))
        return srtp_err_status_fail;

    /*
     * create a receiver session context comparable to the one created
     * above - we need to do this so that the replay checking doesn't
     * complain
     */

    status = srtp_create(&srtp_recv, &policy);
    if (status)
        return status;

    /*
     * unprotect ciphertext, then compare with plaintext
     */

    status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len);
    if (status) {
        return status;
    } else if (len != sizeof(srtp_plaintext_ref)) {
        return srtp_err_status_fail;
    }

    if (srtp_octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len))
        return srtp_err_status_fail;

    status = srtp_dealloc(srtp_snd);
    if (status)
        return status;

    status = srtp_dealloc(srtp_recv);
    if (status)
        return status;

    return srtp_err_status_ok;
}

#ifdef GCM

/*
 * Headers of test vectors taken from RFC 6904, Appendix A
 */

srtp_err_status_t srtp_validate_encrypted_extensions_headers_gcm(void)
{
    // clang-format off
    unsigned char test_key_ext_headers[30] = {
        0xe1, 0xf9, 0x7a, 0x0d, 0x3e, 0x01, 0x8b, 0xe0,
        0xd6, 0x4f, 0xa3, 0x2c, 0x06, 0xde, 0x41, 0x39,
        0x0e, 0xc6, 0x75, 0xad, 0x49, 0x8a, 0xfe, 0xeb,
        0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6
    };
    uint8_t srtp_plaintext_ref[56] = {
        0x90, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xBE, 0xDE, 0x00, 0x06,
        0x17, 0x41, 0x42, 0x73, 0xA4, 0x75, 0x26, 0x27,
        0x48, 0x22, 0x00, 0x00, 0xC8, 0x30, 0x8E, 0x46,
        0x55, 0x99, 0x63, 0x86, 0xB3, 0x95, 0xFB, 0x00,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab
    };
    uint8_t srtp_plaintext[64] = {
        0x90, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xBE, 0xDE, 0x00, 0x06,
        0x17, 0x41, 0x42, 0x73, 0xA4, 0x75, 0x26, 0x27,
        0x48, 0x22, 0x00, 0x00, 0xC8, 0x30, 0x8E, 0x46,
        0x55, 0x99, 0x63, 0x86, 0xB3, 0x95, 0xFB, 0x00,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };
    uint8_t srtp_ciphertext[64] = {
        0x90, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xBE, 0xDE, 0x00, 0x06,
        0x17, 0x12, 0xe0, 0x20, 0x5b, 0xfa, 0x94, 0x9b,
        0x1C, 0x22, 0x00, 0x00, 0xC8, 0x30, 0xbb, 0x46,
        0x73, 0x27, 0x78, 0xd9, 0x92, 0x9a, 0xab, 0x00,
        0x0e, 0xca, 0x0c, 0xf9, 0x5e, 0xe9, 0x55, 0xb2,
        0x6c, 0xd3, 0xd2, 0x88, 0xb4, 0x9f, 0x6c, 0xa9,
        0xf4, 0xb1, 0xb7, 0x59, 0x71, 0x9e, 0xb5, 0xbc
    };
    // clang-format on

    srtp_t srtp_snd, srtp_recv;
    srtp_err_status_t status;
    int len;
    srtp_policy_t policy;
    int headers[3] = { 134 };

    /*
     * create a session with a single stream using the default srtp
     * policy and with the SSRC value 0xcafebabe
     */

    memset(&policy, 0sizeof(policy));
    srtp_crypto_policy_set_aes_gcm_128_8_auth(&policy.rtp);
    srtp_crypto_policy_set_aes_gcm_128_8_auth(&policy.rtcp);
    policy.ssrc.type = ssrc_specific;
    policy.ssrc.value = 0xcafebabe;
    policy.key = test_key_ext_headers;
    policy.deprecated_ekt = NULL;
    policy.window_size = 128;
    policy.allow_repeat_tx = 0;
    policy.enc_xtn_hdr = headers;
    policy.enc_xtn_hdr_count = sizeof(headers) / sizeof(headers[0]);
    policy.next = NULL;

    status = srtp_create(&srtp_snd, &policy);
    if (status)
        return status;

    /*
     * protect plaintext, then compare with ciphertext
     */

    len = sizeof(srtp_plaintext_ref);
    status = srtp_protect(srtp_snd, srtp_plaintext, &len);
    if (status || (len != sizeof(srtp_plaintext)))
        return srtp_err_status_fail;

    debug_print(mod_driver, "ciphertext:\n  %s",
                srtp_octet_string_hex_string(srtp_plaintext, len));
    debug_print(mod_driver, "ciphertext reference:\n  %s",
                srtp_octet_string_hex_string(srtp_ciphertext, len));

    if (srtp_octet_string_is_eq(srtp_plaintext, srtp_ciphertext, len))
        return srtp_err_status_fail;

    /*
     * create a receiver session context comparable to the one created
     * above - we need to do this so that the replay checking doesn't
     * complain
     */

    status = srtp_create(&srtp_recv, &policy);
    if (status)
        return status;

    /*
     * unprotect ciphertext, then compare with plaintext
     */

    status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len);
    if (status) {
        return status;
    } else if (len != sizeof(srtp_plaintext_ref)) {
        return srtp_err_status_fail;
    }

    if (srtp_octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len))
        return srtp_err_status_fail;

    status = srtp_dealloc(srtp_snd);
    if (status)
        return status;

    status = srtp_dealloc(srtp_recv);
    if (status)
        return status;

    return srtp_err_status_ok;
}

/*
 * srtp_validate_aes_192() verifies the correctness of libsrtp by comparing
 * some computed packets against some pre-computed reference values.
 * These packets were made with the AES-CM-192/HMAC-SHA-1-80 policy.
 *
 * The master key and master salt come from RFC 6188 section 7.4 .
 * The test vectors where generated using the cipher key and cipher salt
 * in section 7.4 with cipher_driver with the nonce and plaintext in the
 * srtp_plaintext_ref.
 */


srtp_err_status_t srtp_validate_aes_192(void)
{
    // clang-format off
    uint8_t aes_192_test_key[38] = {
        0x73, 0xed, 0xc6, 0x6c, 0x4f, 0xa1, 0x57, 0x76,
        0xfb, 0x57, 0xf9, 0x50, 0x5c, 0x17, 0x13, 0x65,
        0x50, 0xff, 0xda, 0x71, 0xf3, 0xe8, 0xe5, 0xf1,

        0xc8, 0x52, 0x2f, 0x3a, 0xcd, 0x4c, 0xe8, 0x6d,
        0x5a, 0xdd, 0x78, 0xed, 0xbb, 0x11
    };
    uint8_t srtp_plaintext_ref[28] = {
        0x80, 0x0f, 0x00, 0x00, 0xde, 0xca, 0xfb, 0xad,
        0x00, 0x00, 0x00, 0x00, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab
    };
    uint8_t srtp_plaintext[38] = {
        0x80, 0x0f, 0x00, 0x00, 0xde, 0xca, 0xfb, 0xad,
        0x00, 0x00, 0x00, 0x00, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };
    uint8_t srtp_ciphertext[38] = {
        0x80, 0x0f, 0x00, 0x00, 0xde, 0xca, 0xfb, 0xad,
        0x00, 0x00, 0x00, 0x00, 0xd9, 0x88, 0x65, 0x55,
        0x2f, 0x27, 0x62, 0xc3, 0xef, 0x37, 0xf8, 0x37,
        0xac, 0xfd, 0xb7, 0x12, 0x2d, 0x6b, 0xc4, 0xdc,
        0x84, 0xc7, 0x6f, 0x74, 0xae, 0xa5
    };
    // clang-format on

    srtp_t srtp_snd, srtp_recv;
    srtp_err_status_t status;
    int len;
    srtp_policy_t policy;

    /*
     * create a session with a single stream using the default srtp
     * policy and with the SSRC value 0xcafebabe
     */

    memset(&policy, 0sizeof(policy));
    srtp_crypto_policy_set_aes_cm_192_hmac_sha1_80(&policy.rtp);
    srtp_crypto_policy_set_aes_cm_192_hmac_sha1_80(&policy.rtcp);
    policy.ssrc.type = ssrc_specific;
    policy.ssrc.value = 0x00000000;
    policy.key = aes_192_test_key;
    policy.window_size = 128;
    policy.allow_repeat_tx = 0;
    policy.next = NULL;

    status = srtp_create(&srtp_snd, &policy);
    if (status)
        return status;

    /*
     * protect plaintext, then compare with ciphertext
     */

    len = 28;
    status = srtp_protect(srtp_snd, srtp_plaintext, &len);
    if (status || (len != 38))
        return srtp_err_status_fail;

    debug_print(mod_driver, "ciphertext:\n  %s",
                octet_string_hex_string(srtp_plaintext, len));
    debug_print(mod_driver, "ciphertext reference:\n  %s",
                octet_string_hex_string(srtp_ciphertext, len));

    if (srtp_octet_string_is_eq(srtp_plaintext, srtp_ciphertext, len))
        return srtp_err_status_fail;

    /*
     * create a receiver session context comparable to the one created
     * above - we need to do this so that the replay checking doesn't
     * complain
     */

    status = srtp_create(&srtp_recv, &policy);
    if (status)
        return status;

    /*
     * unprotect ciphertext, then compare with plaintext
     */

    status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len);
    if (status) {
        return status;
    } else if (len != 28) {
        return srtp_err_status_fail;
    }

    if (srtp_octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len))
        return srtp_err_status_fail;

    status = srtp_dealloc(srtp_snd);
    if (status)
        return status;

    status = srtp_dealloc(srtp_recv);
    if (status)
        return status;

    return srtp_err_status_ok;
}
#endif

/*
 * srtp_validate_aes_256() verifies the correctness of libsrtp by comparing
 * some computed packets against some pre-computed reference values.
 * These packets were made with the AES-CM-256/HMAC-SHA-1-80 policy.
 */


srtp_err_status_t srtp_validate_aes_256(void)
{
    // clang-format off
    unsigned char aes_256_test_key[46] = {
        0xf0, 0xf0, 0x49, 0x14, 0xb5, 0x13, 0xf2, 0x76,
        0x3a, 0x1b, 0x1f, 0xa1, 0x30, 0xf1, 0x0e, 0x29,
        0x98, 0xf6, 0xf6, 0xe4, 0x3e, 0x43, 0x09, 0xd1,
        0xe6, 0x22, 0xa0, 0xe3, 0x32, 0xb9, 0xf1, 0xb6,

        0x3b, 0x04, 0x80, 0x3d, 0xe5, 0x1e, 0xe7, 0xc9,
        0x64, 0x23, 0xab, 0x5b, 0x78, 0xd2
    };
    uint8_t srtp_plaintext_ref[28] = {
        0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab
    };
    uint8_t srtp_plaintext[38] = {
        0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
        0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };
    uint8_t srtp_ciphertext[38] = {
        0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad,
        0xca, 0xfe, 0xba, 0xbe, 0xf1, 0xd9, 0xde, 0x17,
        0xff, 0x25, 0x1f, 0xf1, 0xaa, 0x00, 0x77, 0x74,
        0xb0, 0xb4, 0xb4, 0x0d, 0xa0, 0x8d, 0x9d, 0x9a,
        0x5b, 0x3a, 0x55, 0xd8, 0x87, 0x3b
    };
    // clang-format on

    srtp_t srtp_snd, srtp_recv;
    srtp_err_status_t status;
    int len;
    srtp_policy_t policy;

    /*
     * create a session with a single stream using the default srtp
     * policy and with the SSRC value 0xcafebabe
     */

    memset(&policy, 0sizeof(policy));
    srtp_crypto_policy_set_aes_cm_256_hmac_sha1_80(&policy.rtp);
    srtp_crypto_policy_set_aes_cm_256_hmac_sha1_80(&policy.rtcp);
    policy.ssrc.type = ssrc_specific;
    policy.ssrc.value = 0xcafebabe;
    policy.key = aes_256_test_key;
    policy.deprecated_ekt = NULL;
    policy.window_size = 128;
    policy.allow_repeat_tx = 0;
    policy.next = NULL;

    status = srtp_create(&srtp_snd, &policy);
    if (status) {
        return status;
    }

    /*
     * protect plaintext, then compare with ciphertext
     */

    len = 28;
    status = srtp_protect(srtp_snd, srtp_plaintext, &len);
    if (status || (len != 38)) {
        return srtp_err_status_fail;
    }

    debug_print(mod_driver, "ciphertext:\n  %s",
                octet_string_hex_string(srtp_plaintext, len));
    debug_print(mod_driver, "ciphertext reference:\n  %s",
                octet_string_hex_string(srtp_ciphertext, len));

    if (srtp_octet_string_is_eq(srtp_plaintext, srtp_ciphertext, len)) {
        return srtp_err_status_fail;
    }

    /*
     * create a receiver session context comparable to the one created
     * above - we need to do this so that the replay checking doesn't
     * complain
     */

    status = srtp_create(&srtp_recv, &policy);
    if (status) {
        return status;
    }

    /*
     * unprotect ciphertext, then compare with plaintext
     */

    status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len);
    if (status || (len != 28)) {
        return status;
    }

    if (srtp_octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len)) {
        return srtp_err_status_fail;
    }

    status = srtp_dealloc(srtp_snd);
    if (status) {
        return status;
    }

    status = srtp_dealloc(srtp_recv);
    if (status) {
        return status;
    }

    return srtp_err_status_ok;
}

srtp_err_status_t srtp_create_big_policy(srtp_policy_t **list)
{
    extern const srtp_policy_t *policy_array[];
    srtp_policy_t *p = NULL;
    srtp_policy_t *tmp;
    int i = 0;
    uint32_t ssrc = 0;

    /* sanity checking */
    if ((list == NULL) || (policy_array[0] == NULL)) {
        return srtp_err_status_bad_param;
    }

    /*
     * loop over policy list, mallocing a new list and copying values
     * into it (and incrementing the SSRC value as we go along)
     */

    tmp = NULL;
    while (policy_array[i] != NULL) {
        p = (srtp_policy_t *)malloc(sizeof(srtp_policy_t));
        if (p == NULL) {
            return srtp_err_status_bad_param;
        }
        memcpy(p, policy_array[i], sizeof(srtp_policy_t));
        p->ssrc.type = ssrc_specific;
        p->ssrc.value = ssrc++;
        p->next = tmp;
        tmp = p;
        i++;
    }
    *list = p;

    return srtp_err_status_ok;
}

srtp_err_status_t srtp_dealloc_big_policy(srtp_policy_t *list)
{
    srtp_policy_t *p, *next;

    for (p = list; p != NULL; p = next) {
        next = p->next;
        free(p);
    }

    return srtp_err_status_ok;
}

srtp_err_status_t srtp_test_empty_payload(void)
{
    srtp_t srtp_snd, srtp_recv;
    srtp_err_status_t status;
    int len;
    srtp_policy_t policy;
    srtp_hdr_t *mesg;

    /*
     * create a session with a single stream using the default srtp
     * policy and with the SSRC value 0xcafebabe
     */

    memset(&policy, 0sizeof(policy));
    srtp_crypto_policy_set_rtp_default(&policy.rtp);
    srtp_crypto_policy_set_rtcp_default(&policy.rtcp);
    policy.ssrc.type = ssrc_specific;
    policy.ssrc.value = 0xcafebabe;
    policy.key = test_key;
    policy.deprecated_ekt = NULL;
    policy.window_size = 128;
    policy.allow_repeat_tx = 0;
    policy.next = NULL;

    status = srtp_create(&srtp_snd, &policy);
    if (status) {
        return status;
    }

    mesg = srtp_create_test_packet(0, policy.ssrc.value, &len);
    if (mesg == NULL) {
        return srtp_err_status_fail;
    }

    status = srtp_protect(srtp_snd, mesg, &len);
    if (status) {
        return status;
    } else if (len != 12 + 10) {
        return srtp_err_status_fail;
    }

    /*
     * create a receiver session context comparable to the one created
     * above - we need to do this so that the replay checking doesn't
     * complain
     */

    status = srtp_create(&srtp_recv, &policy);
    if (status) {
        return status;
    }

    /*
     * unprotect ciphertext, then compare with plaintext
     */

    status = srtp_unprotect(srtp_recv, mesg, &len);
    if (status) {
        return status;
    } else if (len != 12) {
        return srtp_err_status_fail;
    }

    status = srtp_dealloc(srtp_snd);
    if (status) {
        return status;
    }

    status = srtp_dealloc(srtp_recv);
    if (status) {
        return status;
    }

    free(mesg);

    return srtp_err_status_ok;
}

#ifdef GCM
srtp_err_status_t srtp_test_empty_payload_gcm(void)
{
    srtp_t srtp_snd, srtp_recv;
    srtp_err_status_t status;
    int len;
    srtp_policy_t policy;
    srtp_hdr_t *mesg;

    /*
     * create a session with a single stream using the default srtp
     * policy and with the SSRC value 0xcafebabe
     */

    memset(&policy, 0sizeof(policy));
    srtp_crypto_policy_set_aes_gcm_128_8_auth(&policy.rtp);
    srtp_crypto_policy_set_aes_gcm_128_8_auth(&policy.rtcp);
    policy.ssrc.type = ssrc_specific;
    policy.ssrc.value = 0xcafebabe;
    policy.key = test_key;
    policy.deprecated_ekt = NULL;
    policy.window_size = 128;
    policy.allow_repeat_tx = 0;
    policy.next = NULL;

    status = srtp_create(&srtp_snd, &policy);
    if (status) {
        return status;
    }

    mesg = srtp_create_test_packet(0, policy.ssrc.value, &len);
    if (mesg == NULL) {
        return srtp_err_status_fail;
    }

    status = srtp_protect(srtp_snd, mesg, &len);
    if (status) {
        return status;
    } else if (len != 12 + 8) {
        return srtp_err_status_fail;
    }

    /*
     * create a receiver session context comparable to the one created
     * above - we need to do this so that the replay checking doesn't
     * complain
     */

    status = srtp_create(&srtp_recv, &policy);
    if (status) {
        return status;
    }

    /*
     * unprotect ciphertext, then compare with plaintext
     */

    status = srtp_unprotect(srtp_recv, mesg, &len);
    if (status) {
        return status;
    } else if (len != 12) {
        return srtp_err_status_fail;
    }

    status = srtp_dealloc(srtp_snd);
    if (status) {
        return status;
    }

    status = srtp_dealloc(srtp_recv);
    if (status) {
        return status;
    }

    free(mesg);

    return srtp_err_status_ok;
}
#endif // GCM

srtp_err_status_t srtp_test_remove_stream(void)
{
    srtp_err_status_t status;
    srtp_policy_t *policy_list, policy;
    srtp_t session;
    srtp_stream_t stream;

    /*
     * srtp_get_stream() is a libSRTP internal function that we declare
     * here so that we can use it to verify the correct operation of the
     * library
     */

    extern srtp_stream_t srtp_get_stream(srtp_t srtp, uint32_t ssrc);

    status = srtp_create_big_policy(&policy_list);
    if (status) {
        return status;
    }

    status = srtp_create(&session, policy_list);
    if (status) {
        return status;
    }

    /*
     * check for false positives by trying to remove a stream that's not
     * in the session
     */

    status = srtp_remove_stream(session, htonl(0xaaaaaaaa));
    if (status != srtp_err_status_no_ctx) {
        return srtp_err_status_fail;
    }

    /*
     * check for false negatives by removing stream 0x1, then
     * searching for streams 0x0 and 0x2
     */

    status = srtp_remove_stream(session, htonl(0x1));
    if (status != srtp_err_status_ok) {
        return srtp_err_status_fail;
    }
    stream = srtp_get_stream(session, htonl(0x0));
    if (stream == NULL) {
        return srtp_err_status_fail;
    }
    stream = srtp_get_stream(session, htonl(0x2));
    if (stream == NULL) {
        return srtp_err_status_fail;
    }

    status = srtp_dealloc(session);
    if (status != srtp_err_status_ok) {
        return status;
    }

    status = srtp_dealloc_big_policy(policy_list);
    if (status != srtp_err_status_ok) {
        return status;
    }

    /* Now test adding and removing a single stream */
    memset(&policy, 0sizeof(policy));
    srtp_crypto_policy_set_rtp_default(&policy.rtp);
    srtp_crypto_policy_set_rtcp_default(&policy.rtcp);
    policy.ssrc.type = ssrc_specific;
    policy.ssrc.value = 0xcafebabe;
    policy.key = test_key;
    policy.deprecated_ekt = NULL;
    policy.window_size = 128;
    policy.allow_repeat_tx = 0;
    policy.next = NULL;

    status = srtp_create(&session, NULL);
    if (status != srtp_err_status_ok) {
        return status;
    }

    status = srtp_add_stream(session, &policy);
    if (status != srtp_err_status_ok) {
        return status;
    }

    status = srtp_remove_stream(session, htonl(0xcafebabe));
    if (status != srtp_err_status_ok) {
        return status;
    }

    status = srtp_dealloc(session);
    if (status != srtp_err_status_ok) {
        return status;
    }

    return srtp_err_status_ok;
}

// clang-format off
unsigned char test_alt_key[46] = {
  0xe5, 0x19, 0x6f, 0x01, 0x5e, 0xf1, 0x9b, 0xe1,
  0xd7, 0x47, 0xa7, 0x27, 0x07, 0xd7, 0x47, 0x33,
  0x01, 0xc2, 0x35, 0x4d, 0x59, 0x6a, 0xf7, 0x84,
  0x96, 0x98, 0xeb, 0xaa, 0xac, 0xf6, 0xa1, 0x45,
  0xc7, 0x15, 0xe2, 0xea, 0xfe, 0x55, 0x67, 0x96,
  0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6
};
// clang-format on

/*
 * srtp_test_update() verifies updating/rekeying exsisting streams.
 * As stated in https://tools.ietf.org/html/rfc3711#section-3.3.1
 * the value of the ROC must not be reset after a rekey, this test
 * atempts to prove that srtp_update does not reset the ROC.
 */


srtp_err_status_t srtp_test_update(void)
{
    srtp_err_status_t status;
    uint32_t ssrc = 0x12121212;
    int msg_len_octets = 32;
    int protected_msg_len_octets;
    srtp_hdr_t *msg;
    srtp_t srtp_snd, srtp_recv;
    srtp_policy_t policy;

    memset(&policy, 0sizeof(policy));
    srtp_crypto_policy_set_rtp_default(&policy.rtp);
    srtp_crypto_policy_set_rtcp_default(&policy.rtcp);
    policy.deprecated_ekt = NULL;
    policy.window_size = 128;
    policy.allow_repeat_tx = 0;
    policy.next = NULL;
    policy.key = test_key;

    /* create a send and recive ctx with defualt profile and test_key */
    policy.ssrc.type = ssrc_any_outbound;
    status = srtp_create(&srtp_snd, &policy);
    if (status)
        return status;

    policy.ssrc.type = ssrc_any_inbound;
    status = srtp_create(&srtp_recv, &policy);
    if (status)
        return status;

    /* protect and unprotect two msg's that will cause the ROC to be equal to 1
     */

    msg = srtp_create_test_packet(msg_len_octets, ssrc,
                                  &protected_msg_len_octets);
    if (msg == NULL)
        return srtp_err_status_alloc_fail;
    msg->seq = htons(65535);

    status = srtp_protect(srtp_snd, msg, &protected_msg_len_octets);
    if (status)
        return srtp_err_status_fail;

    status = srtp_unprotect(srtp_recv, msg, &protected_msg_len_octets);
    if (status)
        return status;

    free(msg);

    msg = srtp_create_test_packet(msg_len_octets, ssrc,
                                  &protected_msg_len_octets);
    if (msg == NULL)
        return srtp_err_status_alloc_fail;
    msg->seq = htons(1);

    status = srtp_protect(srtp_snd, msg, &protected_msg_len_octets);
    if (status)
        return srtp_err_status_fail;

    status = srtp_unprotect(srtp_recv, msg, &protected_msg_len_octets);
    if (status)
        return status;

    free(msg);

    /* update send ctx with same test_key t verify update works*/
    policy.ssrc.type = ssrc_any_outbound;
    policy.key = test_key;
    status = srtp_update(srtp_snd, &policy);
    if (status)
        return status;

    msg = srtp_create_test_packet(msg_len_octets, ssrc,
                                  &protected_msg_len_octets);
    if (msg == NULL)
        return srtp_err_status_alloc_fail;
    msg->seq = htons(2);

    status = srtp_protect(srtp_snd, msg, &protected_msg_len_octets);
    if (status)
        return srtp_err_status_fail;

    status = srtp_unprotect(srtp_recv, msg, &protected_msg_len_octets);
    if (status)
        return status;

    free(msg);

    /* update send ctx to use test_alt_key */
    policy.ssrc.type = ssrc_any_outbound;
    policy.key = test_alt_key;
    status = srtp_update(srtp_snd, &policy);
    if (status)
        return status;

    /* create and protect msg with new key and ROC still equal to 1 */
    msg = srtp_create_test_packet(msg_len_octets, ssrc,
                                  &protected_msg_len_octets);
    if (msg == NULL)
        return srtp_err_status_alloc_fail;
    msg->seq = htons(3);

    status = srtp_protect(srtp_snd, msg, &protected_msg_len_octets);
    if (status)
        return srtp_err_status_fail;

    /* verify that recive ctx will fail to unprotect as it still uses test_key
     */

    status = srtp_unprotect(srtp_recv, msg, &protected_msg_len_octets);
    if (status == srtp_err_status_ok)
        return srtp_err_status_fail;

    /* create a new recvieve ctx with test_alt_key but since it is new it will
     * have ROC equal to 1
     * and therefore should fail to unprotected */

    {
        srtp_t srtp_recv_roc_0;

        policy.ssrc.type = ssrc_any_inbound;
        policy.key = test_alt_key;
        status = srtp_create(&srtp_recv_roc_0, &policy);
        if (status)
            return status;

        status =
            srtp_unprotect(srtp_recv_roc_0, msg, &protected_msg_len_octets);
        if (status == srtp_err_status_ok)
            return srtp_err_status_fail;

        status = srtp_dealloc(srtp_recv_roc_0);
        if (status)
            return status;
    }

    /* update recive ctx to use test_alt_key */
    policy.ssrc.type = ssrc_any_inbound;
    policy.key = test_alt_key;
    status = srtp_update(srtp_recv, &policy);
    if (status)
        return status;

    /* verify that can still unprotect, therfore key is updated and ROC value is
     * preserved */

    status = srtp_unprotect(srtp_recv, msg, &protected_msg_len_octets);
    if (status)
        return status;

    free(msg);

    status = srtp_dealloc(srtp_snd);
    if (status)
        return status;

    status = srtp_dealloc(srtp_recv);
    if (status)
        return status;

    return srtp_err_status_ok;
}

srtp_err_status_t srtp_test_setup_protect_trailer_streams(
    srtp_t *srtp_send,
    srtp_t *srtp_send_mki,
    srtp_t *srtp_send_aes_gcm,
    srtp_t *srtp_send_aes_gcm_mki)
{
    srtp_err_status_t status;
    srtp_policy_t policy;
    srtp_policy_t policy_mki;

#ifdef GCM
    srtp_policy_t policy_aes_gcm;
    srtp_policy_t policy_aes_gcm_mki;
#else
    (void)srtp_send_aes_gcm;
    (void)srtp_send_aes_gcm_mki;
#endif // GCM

    memset(&policy, 0sizeof(policy));
    srtp_crypto_policy_set_rtp_default(&policy.rtp);
    srtp_crypto_policy_set_rtcp_default(&policy.rtcp);
    policy.deprecated_ekt = NULL;
    policy.window_size = 128;
    policy.allow_repeat_tx = 0;
    policy.next = NULL;
    policy.ssrc.type = ssrc_any_outbound;
    policy.key = test_key;

    memset(&policy_mki, 0sizeof(policy_mki));
    srtp_crypto_policy_set_rtp_default(&policy_mki.rtp);
    srtp_crypto_policy_set_rtcp_default(&policy_mki.rtcp);
    policy_mki.deprecated_ekt = NULL;
    policy_mki.window_size = 128;
    policy_mki.allow_repeat_tx = 0;
    policy_mki.next = NULL;
    policy_mki.ssrc.type = ssrc_any_outbound;
    policy_mki.key = NULL;
    policy_mki.keys = test_keys;
    policy_mki.num_master_keys = 2;

#ifdef GCM
    memset(&policy_aes_gcm, 0sizeof(policy_aes_gcm));
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy_aes_gcm.rtp);
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy_aes_gcm.rtcp);
    policy_aes_gcm.deprecated_ekt = NULL;
    policy_aes_gcm.window_size = 128;
    policy_aes_gcm.allow_repeat_tx = 0;
    policy_aes_gcm.next = NULL;
    policy_aes_gcm.ssrc.type = ssrc_any_outbound;
    policy_aes_gcm.key = test_key;

    memset(&policy_aes_gcm_mki, 0sizeof(policy_aes_gcm_mki));
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy_aes_gcm_mki.rtp);
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy_aes_gcm_mki.rtcp);
    policy_aes_gcm_mki.deprecated_ekt = NULL;
    policy_aes_gcm_mki.window_size = 128;
    policy_aes_gcm_mki.allow_repeat_tx = 0;
    policy_aes_gcm_mki.next = NULL;
    policy_aes_gcm_mki.ssrc.type = ssrc_any_outbound;
    policy_aes_gcm_mki.key = NULL;
    policy_aes_gcm_mki.keys = test_keys;
    policy_aes_gcm_mki.num_master_keys = 2;
#endif // GCM

    /* create a send ctx with defualt profile and test_key */
    status = srtp_create(srtp_send, &policy);
    if (status)
        return status;

    status = srtp_create(srtp_send_mki, &policy_mki);
    if (status)
        return status;

#ifdef GCM
    status = srtp_create(srtp_send_aes_gcm, &policy_aes_gcm);
    if (status)
        return status;

    status = srtp_create(srtp_send_aes_gcm_mki, &policy_aes_gcm_mki);
    if (status)
        return status;
#endif // GCM

    return srtp_err_status_ok;
}

srtp_err_status_t srtp_test_protect_trailer_length(void)
{
    srtp_t srtp_send;
    srtp_t srtp_send_mki;
    srtp_t srtp_send_aes_gcm;
    srtp_t srtp_send_aes_gcm_mki;
    uint32_t length = 0;
    srtp_err_status_t status;

    srtp_test_setup_protect_trailer_streams(
        &srtp_send, &srtp_send_mki, &srtp_send_aes_gcm, &srtp_send_aes_gcm_mki);

    status = srtp_get_protect_trailer_length(srtp_send, 00, &length);
    if (status)
        return status;

    /*  TAG Length: 10 bytes */
    if (length != 10)
        return srtp_err_status_fail;

    status = srtp_get_protect_trailer_length(srtp_send_mki, 11, &length);
    if (status)
        return status;

    /*  TAG Length: 10 bytes + MKI length: 4 bytes*/
    if (length != 14)
        return srtp_err_status_fail;

#ifdef GCM
    status = srtp_get_protect_trailer_length(srtp_send_aes_gcm, 00, &length);
    if (status)
        return status;

    /*  TAG Length: 16 bytes */
    if (length != 16)
        return srtp_err_status_fail;

    status =
        srtp_get_protect_trailer_length(srtp_send_aes_gcm_mki, 11, &length);
    if (status)
        return status;

    /*  TAG Length: 16 bytes + MKI length: 4 bytes*/
    if (length != 20)
        return srtp_err_status_fail;
#endif // GCM

    srtp_dealloc(srtp_send);
    srtp_dealloc(srtp_send_mki);
#ifdef GCM
    srtp_dealloc(srtp_send_aes_gcm);
    srtp_dealloc(srtp_send_aes_gcm_mki);
#endif

    return srtp_err_status_ok;
}

srtp_err_status_t srtp_test_protect_rtcp_trailer_length(void)
{
    srtp_t srtp_send;
    srtp_t srtp_send_mki;
    srtp_t srtp_send_aes_gcm;
    srtp_t srtp_send_aes_gcm_mki;
    uint32_t length = 0;
    srtp_err_status_t status;

    srtp_test_setup_protect_trailer_streams(
        &srtp_send, &srtp_send_mki, &srtp_send_aes_gcm, &srtp_send_aes_gcm_mki);

    status = srtp_get_protect_rtcp_trailer_length(srtp_send, 00, &length);
    if (status)
        return status;

    /*  TAG Length: 10 bytes + SRTCP Trailer 4 bytes*/
    if (length != 14)
        return srtp_err_status_fail;

    status = srtp_get_protect_rtcp_trailer_length(srtp_send_mki, 11, &length);
    if (status)
        return status;

    /*  TAG Length: 10 bytes + SRTCP Trailer 4 bytes + MKI 4 bytes*/
    if (length != 18)
        return srtp_err_status_fail;

#ifdef GCM
    status =
        srtp_get_protect_rtcp_trailer_length(srtp_send_aes_gcm, 00, &length);
    if (status)
        return status;

    /*  TAG Length: 16 bytes + SRTCP Trailer 4 bytes*/
    if (length != 20)
        return srtp_err_status_fail;

    status = srtp_get_protect_rtcp_trailer_length(srtp_send_aes_gcm_mki, 11,
                                                  &length);
    if (status)
        return status;

    /*  TAG Length: 16 bytes + SRTCP Trailer 4 bytes + MKI 4 bytes*/
    if (length != 24)
        return srtp_err_status_fail;
#endif // GCM

    srtp_dealloc(srtp_send);
    srtp_dealloc(srtp_send_mki);
#ifdef GCM
    srtp_dealloc(srtp_send_aes_gcm);
    srtp_dealloc(srtp_send_aes_gcm_mki);
#endif

    return srtp_err_status_ok;
}

srtp_err_status_t srtp_test_out_of_order_after_rollover(void)
{
    srtp_err_status_t status;

    srtp_policy_t sender_policy;
    srtp_t sender_session;

    srtp_policy_t receiver_policy;
    srtp_t receiver_session;

    const uint32_t num_pkts = 5;
    srtp_hdr_t *pkts[5];
    int pkt_len_octets[5];

    uint32_t i;
    uint32_t stream_roc;

    /* Create sender */
    memset(&sender_policy, 0sizeof(sender_policy));
#ifdef GCM
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&sender_policy.rtp);
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&sender_policy.rtcp);
    sender_policy.key = test_key_gcm;
#else
    srtp_crypto_policy_set_rtp_default(&sender_policy.rtp);
    srtp_crypto_policy_set_rtcp_default(&sender_policy.rtcp);
    sender_policy.key = test_key;
#endif
    sender_policy.ssrc.type = ssrc_specific;
    sender_policy.ssrc.value = 0xcafebabe;
    sender_policy.window_size = 128;

    status = srtp_create(&sender_session, &sender_policy);
    if (status) {
        return status;
    }

    /* Create the receiver */
    memset(&receiver_policy, 0sizeof(receiver_policy));
#ifdef GCM
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&receiver_policy.rtp);
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&receiver_policy.rtcp);
    receiver_policy.key = test_key_gcm;
#else
    srtp_crypto_policy_set_rtp_default(&receiver_policy.rtp);
    srtp_crypto_policy_set_rtcp_default(&receiver_policy.rtcp);
    receiver_policy.key = test_key;
#endif
    receiver_policy.ssrc.type = ssrc_specific;
    receiver_policy.ssrc.value = sender_policy.ssrc.value;
    receiver_policy.window_size = 128;

    status = srtp_create(&receiver_session, &receiver_policy);
    if (status) {
        return status;
    }

    /* Create and protect packets to get to get roc == 1 */
    pkts[0] = srtp_create_test_packet_extended(64, sender_policy.ssrc.value,
                                               655340, &pkt_len_octets[0]);
    status = srtp_protect(sender_session, pkts[0], &pkt_len_octets[0]);
    if (status) {
        return status;
    }
    status = srtp_get_stream_roc(sender_session, sender_policy.ssrc.value,
                                 &stream_roc);
    if (status) {
        return status;
    }
    if (stream_roc != 0) {
        return srtp_err_status_fail;
    }

    pkts[1] = srtp_create_test_packet_extended(64, sender_policy.ssrc.value,
                                               655351, &pkt_len_octets[1]);
    status = srtp_protect(sender_session, pkts[1], &pkt_len_octets[1]);
    if (status) {
        return status;
    }
    status = srtp_get_stream_roc(sender_session, sender_policy.ssrc.value,
                                 &stream_roc);
    if (status) {
        return status;
    }
    if (stream_roc != 0) {
        return srtp_err_status_fail;
    }

    pkts[2] = srtp_create_test_packet_extended(64, sender_policy.ssrc.value, 0,
                                               2, &pkt_len_octets[2]);
    status = srtp_protect(sender_session, pkts[2], &pkt_len_octets[2]);
    if (status) {
        return status;
    }
    status = srtp_get_stream_roc(sender_session, sender_policy.ssrc.value,
                                 &stream_roc);
    if (status) {
        return status;
    }
    if (stream_roc != 1) {
        return srtp_err_status_fail;
    }

    pkts[3] = srtp_create_test_packet_extended(64, sender_policy.ssrc.value, 1,
                                               3, &pkt_len_octets[3]);
    status = srtp_protect(sender_session, pkts[3], &pkt_len_octets[3]);
    if (status) {
        return status;
    }
    status = srtp_get_stream_roc(sender_session, sender_policy.ssrc.value,
                                 &stream_roc);
    if (status) {
        return status;
    }
    if (stream_roc != 1) {
        return srtp_err_status_fail;
    }

    pkts[4] = srtp_create_test_packet_extended(64, sender_policy.ssrc.value, 2,
                                               4, &pkt_len_octets[4]);
    status = srtp_protect(sender_session, pkts[4], &pkt_len_octets[4]);
    if (status) {
        return status;
    }
    status = srtp_get_stream_roc(sender_session, sender_policy.ssrc.value,
                                 &stream_roc);
    if (status) {
        return status;
    }
    if (stream_roc != 1) {
        return srtp_err_status_fail;
    }

    /* Unprotect packets in this seq order 65534, 0, 2, 1, 65535 which is
     * equivalent to index 0, 2, 4, 3, 1*/

    status = srtp_unprotect(receiver_session, pkts[0], &pkt_len_octets[0]);
    if (status) {
        return status;
    }
    status = srtp_get_stream_roc(receiver_session, receiver_policy.ssrc.value,
                                 &stream_roc);
    if (status) {
        return status;
    }
    if (stream_roc != 0) {
        return srtp_err_status_fail;
    }

    status = srtp_unprotect(receiver_session, pkts[2], &pkt_len_octets[2]);
    if (status) {
        return status;
    }
    status = srtp_get_stream_roc(receiver_session, receiver_policy.ssrc.value,
                                 &stream_roc);
    if (status) {
        return status;
    }
    if (stream_roc != 1) {
        return srtp_err_status_fail;
    }

    status = srtp_unprotect(receiver_session, pkts[4], &pkt_len_octets[4]);
    if (status) {
        return status;
    }
    status = srtp_get_stream_roc(receiver_session, receiver_policy.ssrc.value,
                                 &stream_roc);
    if (status) {
        return status;
    }
    if (stream_roc != 1) {
        return srtp_err_status_fail;
    }

    status = srtp_unprotect(receiver_session, pkts[3], &pkt_len_octets[3]);
    if (status) {
        return status;
    }
    status = srtp_get_stream_roc(receiver_session, receiver_policy.ssrc.value,
                                 &stream_roc);
    if (status) {
        return status;
    }
    if (stream_roc != 1) {
        return srtp_err_status_fail;
    }

    status = srtp_unprotect(receiver_session, pkts[1], &pkt_len_octets[1]);
    if (status) {
        return status;
    }
    status = srtp_get_stream_roc(receiver_session, receiver_policy.ssrc.value,
                                 &stream_roc);
    if (status) {
        return status;
    }
    if (stream_roc != 1) {
        return srtp_err_status_fail;
    }

    /* Cleanup */
    status = srtp_dealloc(sender_session);
    if (status) {
        return status;
    }

    status = srtp_dealloc(receiver_session);
    if (status) {
        return status;
    }

    for (i = 0; i < num_pkts; i++) {
        free(pkts[i]);
    }

    return srtp_err_status_ok;
}

srtp_err_status_t srtp_test_get_roc(void)
{
    srtp_err_status_t status;
    srtp_policy_t policy;
    srtp_t session;
    srtp_hdr_t *pkt;
    uint32_t i;
    uint32_t roc;
    uint32_t ts;
    uint16_t seq;

    int msg_len_octets = 32;
    int protected_msg_len_octets;

    memset(&policy, 0sizeof(policy));
    srtp_crypto_policy_set_rtp_default(&policy.rtp);
    srtp_crypto_policy_set_rtcp_default(&policy.rtcp);
    policy.ssrc.type = ssrc_specific;
    policy.ssrc.value = 0xcafebabe;
    policy.key = test_key;
    policy.window_size = 128;

    /* Create a sender session */
    status = srtp_create(&session, &policy);
    if (status) {
        return status;
    }

    /* Set start sequence so we roll over */
    seq = 65535;
    ts = 0;

    for (i = 0; i < 2; i++) {
        pkt = srtp_create_test_packet_extended(msg_len_octets,
                                               policy.ssrc.value, seq, ts,
                                               &protected_msg_len_octets);
        status = srtp_protect(session, pkt, &protected_msg_len_octets);
        free(pkt);
        if (status) {
            return status;
        }

        status = srtp_get_stream_roc(session, policy.ssrc.value, &roc);
        if (status) {
            return status;
        }

        if (roc != i) {
            return srtp_err_status_fail;
        }

        seq++;
        ts++;
    }

    /* Cleanup */
    status = srtp_dealloc(session);
    if (status) {
        return status;
    }

    return srtp_err_status_ok;
}

static srtp_err_status_t test_set_receiver_roc(uint32_t packets,
                                               uint32_t roc_to_set)
{
    srtp_err_status_t status;

    srtp_policy_t sender_policy;
    srtp_t sender_session;

    srtp_policy_t receiver_policy;
    srtp_t receiver_session;

    srtp_hdr_t *pkt_1;
    unsigned char *recv_pkt_1;

    srtp_hdr_t *pkt_2;
    unsigned char *recv_pkt_2;

    uint32_t i;
    uint32_t ts;
    uint16_t seq;
    uint16_t stride;

    int msg_len_octets = 32;
    int protected_msg_len_octets_1;
    int protected_msg_len_octets_2;

    /* Create sender */
    memset(&sender_policy, 0sizeof(sender_policy));
#ifdef GCM
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&sender_policy.rtp);
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&sender_policy.rtcp);
    sender_policy.key = test_key_gcm;
#else
    srtp_crypto_policy_set_rtp_default(&sender_policy.rtp);
    srtp_crypto_policy_set_rtcp_default(&sender_policy.rtcp);
    sender_policy.key = test_key;
#endif
    sender_policy.ssrc.type = ssrc_specific;
    sender_policy.ssrc.value = 0xcafebabe;
    sender_policy.window_size = 128;

    status = srtp_create(&sender_session, &sender_policy);
    if (status) {
        return status;
    }

    /* Create and protect packets */
    i = 0;
    seq = 0;
    ts = 0;
    stride = 0x4000;
    while (i < packets) {
        srtp_hdr_t *tmp_pkt;
        int tmp_len;

        tmp_pkt = srtp_create_test_packet_extended(
            msg_len_octets, sender_policy.ssrc.value, seq, ts, &tmp_len);
        status = srtp_protect(sender_session, tmp_pkt, &tmp_len);
        free(tmp_pkt);
        if (status) {
            return status;
        }

        while (stride > (packets - i) && stride > 1) {
            stride >>= 1;
        }

        i += stride;
        seq += stride;
        ts++;
    }

    /* Create the first packet to decrypt and test for ROC change */
    pkt_1 = srtp_create_test_packet_extended(msg_len_octets,
                                             sender_policy.ssrc.value, seq, ts,
                                             &protected_msg_len_octets_1);
    status = srtp_protect(sender_session, pkt_1, &protected_msg_len_octets_1);
    if (status) {
        return status;
    }

    /* Create the second packet to decrypt and test for ROC change */
    seq++;
    ts++;
    pkt_2 = srtp_create_test_packet_extended(msg_len_octets,
                                             sender_policy.ssrc.value, seq, ts,
                                             &protected_msg_len_octets_2);
    status = srtp_protect(sender_session, pkt_2, &protected_msg_len_octets_2);
    if (status) {
        return status;
    }

    /* Create the receiver */
    memset(&receiver_policy, 0sizeof(receiver_policy));
#ifdef GCM
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&receiver_policy.rtp);
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&receiver_policy.rtcp);
    receiver_policy.key = test_key_gcm;
#else
    srtp_crypto_policy_set_rtp_default(&receiver_policy.rtp);
    srtp_crypto_policy_set_rtcp_default(&receiver_policy.rtcp);
    receiver_policy.key = test_key;
#endif
    receiver_policy.ssrc.type = ssrc_specific;
    receiver_policy.ssrc.value = sender_policy.ssrc.value;
    receiver_policy.window_size = 128;

    status = srtp_create(&receiver_session, &receiver_policy);
    if (status) {
        return status;
    }

    /* Make a copy of the first sent protected packet */
    recv_pkt_1 = malloc(protected_msg_len_octets_1);
    if (recv_pkt_1 == NULL) {
        return srtp_err_status_fail;
    }
    memcpy(recv_pkt_1, pkt_1, protected_msg_len_octets_1);

    /* Make a copy of the second sent protected packet */
    recv_pkt_2 = malloc(protected_msg_len_octets_2);
    if (recv_pkt_2 == NULL) {
        return srtp_err_status_fail;
    }
    memcpy(recv_pkt_2, pkt_2, protected_msg_len_octets_2);

    /* Set the ROC to the wanted value */
    status = srtp_set_stream_roc(receiver_session, receiver_policy.ssrc.value,
                                 roc_to_set);
    if (status) {
        return status;
    }

    /* Unprotect the first packet */
    status = srtp_unprotect(receiver_session, recv_pkt_1,
                            &protected_msg_len_octets_1);
    if (status) {
        return status;
    }

    /* Unprotect the second packet */
    status = srtp_unprotect(receiver_session, recv_pkt_2,
                            &protected_msg_len_octets_2);
    if (status) {
        return status;
    }

    /* Cleanup */
    status = srtp_dealloc(sender_session);
    if (status) {
        return status;
    }

    status = srtp_dealloc(receiver_session);
    if (status) {
        return status;
    }

    free(pkt_1);
    free(recv_pkt_1);
    free(pkt_2);
    free(recv_pkt_2);

    return srtp_err_status_ok;
}

static srtp_err_status_t test_set_sender_roc(uint16_t seq, uint32_t roc_to_set)
{
    srtp_err_status_t status;

    srtp_policy_t sender_policy;
    srtp_t sender_session;

    srtp_policy_t receiver_policy;
    srtp_t receiver_session;

    srtp_hdr_t *pkt;
    unsigned char *recv_pkt;

    uint32_t ts;

    int msg_len_octets = 32;
    int protected_msg_len_octets;

    /* Create sender */
    memset(&sender_policy, 0sizeof(sender_policy));
#ifdef GCM
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&sender_policy.rtp);
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&sender_policy.rtcp);
    sender_policy.key = test_key_gcm;
#else
    srtp_crypto_policy_set_rtp_default(&sender_policy.rtp);
    srtp_crypto_policy_set_rtcp_default(&sender_policy.rtcp);
    sender_policy.key = test_key;
#endif
    sender_policy.ssrc.type = ssrc_specific;
    sender_policy.ssrc.value = 0xcafebabe;
    sender_policy.window_size = 128;

    status = srtp_create(&sender_session, &sender_policy);
    if (status) {
        return status;
    }

    /* Set the ROC before encrypting the first packet */
    status = srtp_set_stream_roc(sender_session, sender_policy.ssrc.value,
                                 roc_to_set);
    if (status != srtp_err_status_ok) {
        return status;
    }

    /* Create the packet to decrypt */
    ts = 0;
    pkt = srtp_create_test_packet_extended(msg_len_octets,
                                           sender_policy.ssrc.value, seq, ts,
                                           &protected_msg_len_octets);
    status = srtp_protect(sender_session, pkt, &protected_msg_len_octets);
    if (status) {
        return status;
    }

    /* Create the receiver */
    memset(&receiver_policy, 0sizeof(receiver_policy));
#ifdef GCM
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&receiver_policy.rtp);
    srtp_crypto_policy_set_aes_gcm_128_16_auth(&receiver_policy.rtcp);
    receiver_policy.key = test_key_gcm;
#else
    srtp_crypto_policy_set_rtp_default(&receiver_policy.rtp);
    srtp_crypto_policy_set_rtcp_default(&receiver_policy.rtcp);
    receiver_policy.key = test_key;
#endif
    receiver_policy.ssrc.type = ssrc_specific;
    receiver_policy.ssrc.value = sender_policy.ssrc.value;
    receiver_policy.window_size = 128;

    status = srtp_create(&receiver_session, &receiver_policy);
    if (status) {
        return status;
    }

    /* Make a copy of the sent protected packet */
    recv_pkt = malloc(protected_msg_len_octets);
    if (recv_pkt == NULL) {
        return srtp_err_status_fail;
    }
    memcpy(recv_pkt, pkt, protected_msg_len_octets);

    /* Set the ROC to the wanted value */
    status = srtp_set_stream_roc(receiver_session, receiver_policy.ssrc.value,
                                 roc_to_set);
    if (status) {
        return status;
    }

    status =
        srtp_unprotect(receiver_session, recv_pkt, &protected_msg_len_octets);
    if (status) {
        return status;
    }

    /* Cleanup */
    status = srtp_dealloc(sender_session);
    if (status) {
        return status;
    }

    status = srtp_dealloc(receiver_session);
    if (status) {
        return status;
    }

    free(pkt);
    free(recv_pkt);

    return srtp_err_status_ok;
}

srtp_err_status_t srtp_test_set_receiver_roc(void)
{
    int packets;
    uint32_t roc;
    srtp_err_status_t status;

    /* First test does not rollover */
    packets = 1;
    roc = 0;

    status = test_set_receiver_roc(packets - 1, roc);
    if (status) {
        return status;
    }

    status = test_set_receiver_roc(packets, roc);
    if (status) {
        return status;
    }

    status = test_set_receiver_roc(packets + 1, roc);
    if (status) {
        return status;
    }

    status = test_set_receiver_roc(packets + 60000, roc);
    if (status) {
        return status;
    }

    /* Second test should rollover */
    packets = 65535;
    roc = 0;

    status = test_set_receiver_roc(packets - 1, roc);
    if (status) {
        return status;
    }

    status = test_set_receiver_roc(packets, roc);
    if (status) {
        return status;
    }

    /* Now the rollover counter should be 1 */
    roc = 1;
    status = test_set_receiver_roc(packets + 1, roc);
    if (status) {
        return status;
    }

    status = test_set_receiver_roc(packets + 60000, roc);
    if (status) {
        return status;
    }

    status = test_set_receiver_roc(packets + 65535, roc);
    if (status) {
        return status;
    }

    return srtp_err_status_ok;
}

srtp_err_status_t srtp_test_set_sender_roc(void)
{
    uint32_t roc;
    uint16_t seq;
    srtp_err_status_t status;

    seq = 43210;
    roc = 0;
    status = test_set_sender_roc(seq, roc);
    if (status) {
        return status;
    }

    roc = 65535;
    status = test_set_sender_roc(seq, roc);
    if (status) {
        return status;
    }

    roc = 0xffff;
    status = test_set_sender_roc(seq, roc);
    if (status) {
        return status;
    }

    roc = 0xffff00;
    status = test_set_sender_roc(seq, roc);
    if (status) {
        return status;
    }

    roc = 0xfffffff0;
    status = test_set_sender_roc(seq, roc);
    if (status) {
        return status;
    }

    return srtp_err_status_ok;
}

/*
 * srtp policy definitions - these definitions are used above
 */


// clang-format off
unsigned char test_key[46] = {
    0xe1, 0xf9, 0x7a, 0x0d, 0x3e, 0x01, 0x8b, 0xe0,
    0xd6, 0x4f, 0xa3, 0x2c, 0x06, 0xde, 0x41, 0x39,
    0x0e, 0xc6, 0x75, 0xad, 0x49, 0x8a, 0xfe, 0xeb,
    0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6, 0xc1, 0x73,
    0xc3, 0x17, 0xf2, 0xda, 0xbe, 0x35, 0x77, 0x93,
    0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6
};

unsigned char test_key_2[46] = {
    0xf0, 0xf0, 0x49, 0x14, 0xb5, 0x13, 0xf2, 0x76,
    0x3a, 0x1b, 0x1f, 0xa1, 0x30, 0xf1, 0x0e, 0x29,
    0x98, 0xf6, 0xf6, 0xe4, 0x3e, 0x43, 0x09, 0xd1,
    0xe6, 0x22, 0xa0, 0xe3, 0x32, 0xb9, 0xf1, 0xb6,
    0xc3, 0x17, 0xf2, 0xda, 0xbe, 0x35, 0x77, 0x93,
    0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6
};

unsigned char test_key_gcm[28] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
    0xa8, 0xa9, 0xaa, 0xab
};

unsigned char test_mki_id[TEST_MKI_ID_SIZE] = {
    0xe1, 0xf9, 0x7a, 0x0d
};

unsigned char test_mki_id_2[TEST_MKI_ID_SIZE] = {
    0xf3, 0xa1, 0x46, 0x71
};
// clang-format on

const srtp_policy_t default_policy = {
    { ssrc_any_outbound, 0 }, /* SSRC */
    {
        /* SRTP policy */
        SRTP_AES_ICM_128,               /* cipher type                 */
        SRTP_AES_ICM_128_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_HMAC_SHA1,                 /* authentication func type    */
        16,                             /* auth key length in octets   */
        10,                             /* auth tag length in octets   */
        sec_serv_conf_and_auth          /* security services flag      */
    },
    {
        /* SRTCP policy */
        SRTP_AES_ICM_128,               /* cipher type                 */
        SRTP_AES_ICM_128_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_HMAC_SHA1,                 /* authentication func type    */
        16,                             /* auth key length in octets   */
        10,                             /* auth tag length in octets   */
        sec_serv_conf_and_auth          /* security services flag      */
    },
    NULL,
    (srtp_master_key_t **)test_keys,
    2,    /* indicates the number of Master keys          */
    NULL, /* indicates that EKT is not in use             */
    128,  /* replay window size                           */
    0,    /* retransmission not allowed                   */
    NULL, /* no encrypted extension headers               */
    0,    /* list of encrypted extension headers is empty */
    NULL
};

const srtp_policy_t aes_only_policy = {
    { ssrc_any_outbound, 0 }, /* SSRC                        */
    {
        SRTP_AES_ICM_128,               /* cipher type                 */
        SRTP_AES_ICM_128_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_NULL_AUTH,                 /* authentication func type    */
        0,                              /* auth key length in octets   */
        0,                              /* auth tag length in octets   */
        sec_serv_conf                   /* security services flag      */
    },
    {
        SRTP_AES_ICM_128,               /* cipher type                 */
        SRTP_AES_ICM_128_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_NULL_AUTH,                 /* authentication func type    */
        0,                              /* auth key length in octets   */
        0,                              /* auth tag length in octets   */
        sec_serv_conf                   /* security services flag      */
    },
    NULL,
    (srtp_master_key_t **)test_keys,
    2,    /* indicates the number of Master keys          */
    NULL, /* indicates that EKT is not in use             */
    128,  /* replay window size                           */
    0,    /* retransmission not allowed                   */
    NULL, /* no encrypted extension headers               */
    0,    /* list of encrypted extension headers is empty */
    NULL
};

const srtp_policy_t hmac_only_policy = {
    { ssrc_any_outbound, 0 }, /* SSRC */
    {
        SRTP_NULL_CIPHER,               /* cipher type                 */
        SRTP_AES_ICM_128_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_HMAC_SHA1,                 /* authentication func type    */
        20,                             /* auth key length in octets   */
        4,                              /* auth tag length in octets   */
        sec_serv_auth                   /* security services flag      */
    },
    {
        SRTP_NULL_CIPHER,               /* cipher type                 */
        SRTP_AES_ICM_128_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_HMAC_SHA1,                 /* authentication func type    */
        20,                             /* auth key length in octets   */
        4,                              /* auth tag length in octets   */
        sec_serv_auth                   /* security services flag      */
    },
    NULL,
    (srtp_master_key_t **)test_keys,
    2,    /* Number of Master keys associated with the policy */
    NULL, /* indicates that EKT is not in use                 */
    128,  /* replay window size                               */
    0,    /* retransmission not allowed                       */
    NULL, /* no encrypted extension headers                   */
    0,    /* list of encrypted extension headers is empty     */
    NULL
};

#ifdef GCM
const srtp_policy_t aes128_gcm_8_policy = {
    { ssrc_any_outbound, 0 }, /* SSRC */
    {
        /* SRTP policy */
        SRTP_AES_GCM_128,               /* cipher type                 */
        SRTP_AES_GCM_128_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_NULL_AUTH,                 /* authentication func type    */
        0,                              /* auth key length in octets   */
        8,                              /* auth tag length in octets   */
        sec_serv_conf_and_auth          /* security services flag      */
    },
    {
        /* SRTCP policy */
        SRTP_AES_GCM_128,               /* cipher type                 */
        SRTP_AES_GCM_128_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_NULL_AUTH,                 /* authentication func type    */
        0,                              /* auth key length in octets   */
        8,                              /* auth tag length in octets   */
        sec_serv_conf_and_auth          /* security services flag      */
    },
    NULL,
    (srtp_master_key_t **)test_keys,
    2,    /* indicates the number of Master keys          */
    NULL, /* indicates that EKT is not in use             */
    128,  /* replay window size                           */
    0,    /* retransmission not allowed                   */
    NULL, /* no encrypted extension headers               */
    0,    /* list of encrypted extension headers is empty */
    NULL
};

const srtp_policy_t aes128_gcm_8_cauth_policy = {
    { ssrc_any_outbound, 0 }, /* SSRC */
    {
        /* SRTP policy */
        SRTP_AES_GCM_128,               /* cipher type                 */
        SRTP_AES_GCM_128_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_NULL_AUTH,                 /* authentication func type    */
        0,                              /* auth key length in octets   */
        8,                              /* auth tag length in octets   */
        sec_serv_conf_and_auth          /* security services flag      */
    },
    {
        /* SRTCP policy */
        SRTP_AES_GCM_128,               /* cipher type                 */
        SRTP_AES_GCM_128_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_NULL_AUTH,                 /* authentication func type    */
        0,                              /* auth key length in octets   */
        8,                              /* auth tag length in octets   */
        sec_serv_auth                   /* security services flag      */
    },
    NULL,
    (srtp_master_key_t **)test_keys,
    2,    /* indicates the number of Master keys          */
    NULL, /* indicates that EKT is not in use             */
    128,  /* replay window size                           */
    0,    /* retransmission not allowed                   */
    NULL, /* no encrypted extension headers               */
    0,    /* list of encrypted extension headers is empty */
    NULL
};

const srtp_policy_t aes256_gcm_8_policy = {
    { ssrc_any_outbound, 0 }, /* SSRC */
    {
        /* SRTP policy */
        SRTP_AES_GCM_256,               /* cipher type                 */
        SRTP_AES_GCM_256_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_NULL_AUTH,                 /* authentication func type    */
        0,                              /* auth key length in octets   */
        8,                              /* auth tag length in octets   */
        sec_serv_conf_and_auth          /* security services flag      */
    },
    {
        /* SRTCP policy */
        SRTP_AES_GCM_256,               /* cipher type                 */
        SRTP_AES_GCM_256_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_NULL_AUTH,                 /* authentication func type    */
        0,                              /* auth key length in octets   */
        8,                              /* auth tag length in octets   */
        sec_serv_conf_and_auth          /* security services flag      */
    },
    NULL,
    (srtp_master_key_t **)test_keys,
    2,    /* indicates the number of Master keys          */
    NULL, /* indicates that EKT is not in use             */
    128,  /* replay window size                           */
    0,    /* retransmission not allowed                   */
    NULL, /* no encrypted extension headers               */
    0,    /* list of encrypted extension headers is empty */
    NULL
};

const srtp_policy_t aes256_gcm_8_cauth_policy = {
    { ssrc_any_outbound, 0 }, /* SSRC */
    {
        /* SRTP policy */
        SRTP_AES_GCM_256,               /* cipher type                 */
        SRTP_AES_GCM_256_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_NULL_AUTH,                 /* authentication func type    */
        0,                              /* auth key length in octets   */
        8,                              /* auth tag length in octets   */
        sec_serv_conf_and_auth          /* security services flag      */
    },
    {
        /* SRTCP policy */
        SRTP_AES_GCM_256,               /* cipher type                 */
        SRTP_AES_GCM_256_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_NULL_AUTH,                 /* authentication func type    */
        0,                              /* auth key length in octets   */
        8,                              /* auth tag length in octets   */
        sec_serv_auth                   /* security services flag      */
    },
    NULL,
    (srtp_master_key_t **)test_keys,
    2,    /* indicates the number of Master keys          */
    NULL, /* indicates that EKT is not in use             */
    128,  /* replay window size                           */
    0,    /* retransmission not allowed                   */
    NULL, /* no encrypted extension headers               */
    0,    /* list of encrypted extension headers is empty */
    NULL
};
#endif

const srtp_policy_t null_policy = {
    { ssrc_any_outbound, 0 }, /* SSRC */
    {
        SRTP_NULL_CIPHER,               /* cipher type                 */
        SRTP_AES_GCM_256_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_NULL_AUTH,                 /* authentication func type    */
        0,                              /* auth key length in octets   */
        0,                              /* auth tag length in octets   */
        sec_serv_none                   /* security services flag      */
    },
    {
        SRTP_NULL_CIPHER,               /* cipher type                 */
        SRTP_AES_GCM_256_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_NULL_AUTH,                 /* authentication func type    */
        0,                              /* auth key length in octets   */
        0,                              /* auth tag length in octets   */
        sec_serv_none                   /* security services flag      */
    },
    NULL,
    (srtp_master_key_t **)test_keys,
    2,    /* indicates the number of Master keys          */
    NULL, /* indicates that EKT is not in use             */
    128,  /* replay window size                           */
    0,    /* retransmission not allowed                   */
    NULL, /* no encrypted extension headers               */
    0,    /* list of encrypted extension headers is empty */
    NULL
};

// clang-format off
unsigned char test_256_key[46] = {
    0xf0, 0xf0, 0x49, 0x14, 0xb5, 0x13, 0xf2, 0x76,
    0x3a, 0x1b, 0x1f, 0xa1, 0x30, 0xf1, 0x0e, 0x29,
    0x98, 0xf6, 0xf6, 0xe4, 0x3e, 0x43, 0x09, 0xd1,
    0xe6, 0x22, 0xa0, 0xe3, 0x32, 0xb9, 0xf1, 0xb6,

    0x3b, 0x04, 0x80, 0x3d, 0xe5, 0x1e, 0xe7, 0xc9,
    0x64, 0x23, 0xab, 0x5b, 0x78, 0xd2
};

unsigned char test_256_key_2[46] = {
    0xe1, 0xf9, 0x7a, 0x0d, 0x3e, 0x01, 0x8b, 0xe0,
    0xd6, 0x4f, 0xa3, 0x2c, 0x06, 0xde, 0x41, 0x39,
    0x0e, 0xc6, 0x75, 0xad, 0x49, 0x8a, 0xfe, 0xeb,
    0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6, 0xc1, 0x73,
    0x3b, 0x04, 0x80, 0x3d, 0xe5, 0x1e, 0xe7, 0xc9,
    0x64, 0x23, 0xab, 0x5b, 0x78, 0xd2
};

srtp_master_key_t master_256_key_1 = {
    test_256_key,
    test_mki_id,
    TEST_MKI_ID_SIZE
};

srtp_master_key_t master_256_key_2 = {
    test_256_key_2,
    test_mki_id_2,
    TEST_MKI_ID_SIZE
};

srtp_master_key_t *test_256_keys[2] = {
    &master_key_1,
    &master_key_2
};
// clang-format on

const srtp_policy_t aes_256_hmac_policy = {
    { ssrc_any_outbound, 0 }, /* SSRC */
    {
        /* SRTP policy */
        SRTP_AES_ICM_256,               /* cipher type                 */
        SRTP_AES_ICM_256_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_HMAC_SHA1,                 /* authentication func type    */
        20,                             /* auth key length in octets   */
        10,                             /* auth tag length in octets   */
        sec_serv_conf_and_auth          /* security services flag      */
    },
    {
        /* SRTCP policy */
        SRTP_AES_ICM_256,               /* cipher type                 */
        SRTP_AES_ICM_256_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_HMAC_SHA1,                 /* authentication func type    */
        20,                             /* auth key length in octets   */
        10,                             /* auth tag length in octets   */
        sec_serv_conf_and_auth          /* security services flag      */
    },
    NULL,
    (srtp_master_key_t **)test_256_keys,
    2,    /* indicates the number of Master keys          */
    NULL, /* indicates that EKT is not in use             */
    128,  /* replay window size                           */
    0,    /* retransmission not allowed                   */
    NULL, /* no encrypted extension headers               */
    0,    /* list of encrypted extension headers is empty */
    NULL
};

const srtp_policy_t aes_256_hmac_32_policy = {
    { ssrc_any_outbound, 0 }, /* SSRC */
    {
        /* SRTP policy */
        SRTP_AES_ICM_256,               /* cipher type                 */
        SRTP_AES_ICM_256_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_HMAC_SHA1,                 /* authentication func type    */
        20,                             /* auth key length in octets   */
        4,                              /* auth tag length in octets   */
        sec_serv_conf_and_auth          /* security services flag      */
    },
    {
        /* SRTCP policy */
        SRTP_AES_ICM_256,               /* cipher type                 */
        SRTP_AES_ICM_256_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_HMAC_SHA1,                 /* authentication func type    */
        20,                             /* auth key length in octets   */
        10,                             /* auth tag length in octets.
                                           80 bits per RFC 3711. */

        sec_serv_conf_and_auth          /* security services flag      */
    },
    NULL,
    (srtp_master_key_t **)test_256_keys,
    2,    /* indicates the number of Master keys          */
    NULL, /* indicates that EKT is not in use             */
    128,  /* replay window size                           */
    0,    /* retransmission not allowed                   */
    NULL, /* no encrypted extension headers               */
    0,    /* list of encrypted extension headers is empty */
    NULL
};

char ekt_test_policy = 'x';

const srtp_policy_t hmac_only_with_ekt_policy = {
    { ssrc_any_outbound, 0 }, /* SSRC */
    {
        SRTP_NULL_CIPHER, /* cipher type                 */
        0,                /* cipher key length in octets */
        SRTP_HMAC_SHA1,   /* authentication func type    */
        20,               /* auth key length in octets   */
        4,                /* auth tag length in octets   */
        sec_serv_auth     /* security services flag      */
    },
    {
        SRTP_NULL_CIPHER, /* cipher type                 */
        0,                /* cipher key length in octets */
        SRTP_HMAC_SHA1,   /* authentication func type    */
        20,               /* auth key length in octets   */
        4,                /* auth tag length in octets   */
        sec_serv_auth     /* security services flag      */
    },
    NULL,
    (srtp_master_key_t **)test_keys,
    2,                /* indicates the number of Master keys          */
    &ekt_test_policy, /* requests deprecated EKT functionality        */
    128,              /* replay window size                           */
    0,                /* retransmission not allowed                   */
    NULL,             /* no encrypted extension headers               */
    0,                /* list of encrypted extension headers is empty */
    NULL
};

/*
 * an array of pointers to the policies listed above
 *
 * This array is used to test various aspects of libSRTP for
 * different cryptographic policies.  The order of the elements
 * matters - the timing test generates output that can be used
 * in a plot (see the gnuplot script file 'timing').  If you
 * add to this list, you should do it at the end.
 */


// clang-format off
const srtp_policy_t *policy_array[] = {
    &hmac_only_policy,
    &aes_only_policy,
    &default_policy,
#ifdef GCM
    &aes128_gcm_8_policy,
    &aes128_gcm_8_cauth_policy,
    &aes256_gcm_8_policy,
    &aes256_gcm_8_cauth_policy,
#endif
    &null_policy,
    &aes_256_hmac_policy,
    &aes_256_hmac_32_policy,
    NULL
};
// clang-format on

// clang-format off
const srtp_policy_t *invalid_policy_array[] = {
    &hmac_only_with_ekt_policy,
    NULL
};
// clang-format on

const srtp_policy_t wildcard_policy = {
    { ssrc_any_outbound, 0 }, /* SSRC */
    {
        /* SRTP policy */
        SRTP_AES_ICM_128,               /* cipher type                 */
        SRTP_AES_ICM_128_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_HMAC_SHA1,                 /* authentication func type    */
        16,                             /* auth key length in octets   */
        10,                             /* auth tag length in octets   */
        sec_serv_conf_and_auth          /* security services flag      */
    },
    {
        /* SRTCP policy */
        SRTP_AES_ICM_128,               /* cipher type                 */
        SRTP_AES_ICM_128_KEY_LEN_WSALT, /* cipher key length in octets */
        SRTP_HMAC_SHA1,                 /* authentication func type    */
        16,                             /* auth key length in octets   */
        10,                             /* auth tag length in octets   */
        sec_serv_conf_and_auth          /* security services flag      */
    },
    test_key,
    NULL,
    0,
    NULL,
    128,  /* replay window size                           */
    0,    /* retransmission not allowed                   */
    NULL, /* no encrypted extension headers               */
    0,    /* list of encrypted extension headers is empty */
    NULL
};

static srtp_stream_t stream_list_test_create_stream(uint32_t ssrc)
{
    srtp_stream_t stream = malloc(sizeof(srtp_stream_ctx_t));
    stream->ssrc = ssrc;
    return stream;
}

static void stream_list_test_free_stream(srtp_stream_t stream)
{
    free(stream);
}

int stream_list_test_count_cb(srtp_stream_t stream, void *data)
{
    int *count = (int *)data;
    (*count)++;
    (void)stream;
    return 0;
}

struct remove_one_data {
    uint32_t ssrc;
    srtp_stream_list_t list;
};

int stream_list_test_remove_one_cb(srtp_stream_t stream, void *data)
{
    struct remove_one_data *d = (struct remove_one_data *)data;
    if (stream->ssrc == d->ssrc) {
        srtp_stream_list_remove(d->list, stream);
        stream_list_test_free_stream(stream);
        return 1;
    }
    return 0;
}

int stream_list_test_remove_all_cb(srtp_stream_t stream, void *data)
{
    srtp_stream_list_t *list = (srtp_stream_list_t *)data;
    srtp_stream_list_remove(*list, stream);
    stream_list_test_free_stream(stream);
    return 0;
}

srtp_err_status_t srtp_stream_list_test(void)
{
    srtp_stream_list_t list;

    if (srtp_stream_list_alloc(&list)) {
        return srtp_err_status_fail;
    }

    /* add 4 streams*/
    if (srtp_stream_list_insert(list, stream_list_test_create_stream(1))) {
        return srtp_err_status_fail;
    }
    if (srtp_stream_list_insert(list, stream_list_test_create_stream(2))) {
        return srtp_err_status_fail;
    }
    if (srtp_stream_list_insert(list, stream_list_test_create_stream(3))) {
        return srtp_err_status_fail;
    }
    if (srtp_stream_list_insert(list, stream_list_test_create_stream(4))) {
        return srtp_err_status_fail;
    }

    /* find */
    if (srtp_stream_list_get(list, 3) == NULL) {
        return srtp_err_status_fail;
    }
    if (srtp_stream_list_get(list, 1) == NULL) {
        return srtp_err_status_fail;
    }
    if (srtp_stream_list_get(list, 2) == NULL) {
        return srtp_err_status_fail;
    }
    if (srtp_stream_list_get(list, 4) == NULL) {
        return srtp_err_status_fail;
    }

    /* find not in list */
    if (srtp_stream_list_get(list, 5)) {
        return srtp_err_status_fail;
    }

    /* for each */
    int count = 0;
    srtp_stream_list_for_each(list, stream_list_test_count_cb, &count);
    if (count != 4) {
        return srtp_err_status_fail;
    }

    /* remove */
    srtp_stream_t stream = srtp_stream_list_get(list, 3);
    if (stream == NULL) {
        return srtp_err_status_fail;
    }
    srtp_stream_list_remove(list, stream);
    stream_list_test_free_stream(stream);

    /* find after remove */
    if (srtp_stream_list_get(list, 3)) {
        return srtp_err_status_fail;
    }

    /* recount */
    count = 0;
    srtp_stream_list_for_each(list, stream_list_test_count_cb, &count);
    if (count != 3) {
        return srtp_err_status_fail;
    }

    /* remove one in for each */
    struct remove_one_data data = { 2, list };
    srtp_stream_list_for_each(list, stream_list_test_remove_one_cb, &data);

    /* find after remove */
    if (srtp_stream_list_get(list, 2)) {
        return srtp_err_status_fail;
    }

    /* recount */
    count = 0;
    srtp_stream_list_for_each(list, stream_list_test_count_cb, &count);
    if (count != 2) {
        return srtp_err_status_fail;
    }

    /* destroy non empty list */
    if (srtp_stream_list_dealloc(list) == srtp_err_status_ok) {
        return srtp_err_status_fail;
    }

    /* remove all in for each */
    srtp_stream_list_for_each(list, stream_list_test_remove_all_cb, &list);

    /* recount */
    count = 0;
    srtp_stream_list_for_each(list, stream_list_test_count_cb, &count);
    if (count != 0) {
        return srtp_err_status_fail;
    }

    /* destroy empty list */
    if (srtp_stream_list_dealloc(list)) {
        return srtp_err_status_fail;
    }

    return srtp_err_status_ok;
}

#ifdef SRTP_USE_TEST_STREAM_LIST

/*
 * A srtp_stream_list_ctx_t implementation using a single linked list
 * that does not use the internal next / prev fields.
 */


struct test_list_node {
    srtp_stream_t stream;
    struct test_list_node *next;
};
struct srtp_stream_list_ctx_t_ {
    struct test_list_node *head;
};

srtp_err_status_t srtp_stream_list_alloc(srtp_stream_list_t *list_ptr)
{
    struct srtp_stream_list_ctx_t_ *l =
        malloc(sizeof(struct srtp_stream_list_ctx_t_));
    l->head = NULL;
    *list_ptr = l;
    return srtp_err_status_ok;
}

srtp_err_status_t srtp_stream_list_dealloc(srtp_stream_list_t list)
{
    struct test_list_node *node = list->head;
    if (node) {
        return srtp_err_status_fail;
    }
    free(list);

    return srtp_err_status_ok;
}

srtp_err_status_t srtp_stream_list_insert(srtp_stream_list_t list,
                                          srtp_stream_t stream)
{
    struct test_list_node *node = malloc(sizeof(struct test_list_node));
    node->stream = stream;
    node->next = list->head;
    list->head = node;

    return srtp_err_status_ok;
}

srtp_stream_t srtp_stream_list_get(srtp_stream_list_t list, uint32_t ssrc)
{
    struct test_list_node *node = list->head;
    while (node != NULL) {
        if (node->stream->ssrc == ssrc)
            return node->stream;
        node = node->next;
    }
    return NULL;
}

void srtp_stream_list_remove(srtp_stream_list_t list, srtp_stream_t stream)
{
    struct test_list_node **node = &(list->head);
    while ((*node) != NULL) {
        if ((*node)->stream->ssrc == stream->ssrc) {
            struct test_list_node *tmp = (*node);
            (*node) = tmp->next;
            free(tmp);
            return;
        }
        node = &(*node)->next;
    }
}

void srtp_stream_list_for_each(srtp_stream_list_t list,
                               int (*callback)(srtp_stream_t, void *),
                               void *data)
{
    struct test_list_node *node = list->head;
    while (node != NULL) {
        struct test_list_node *tmp = node;
        node = node->next;
        if (callback(tmp->stream, data))
            break;
    }
}

#endif

Messung V0.5 in Prozent
C=87 H=97 G=91

¤ Dauer der Verarbeitung: 0.192 Sekunden  (vorverarbeitet am  2026-08-25) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=141584
#Domains=752002