err_status_t srtp_validate() { unsigned char test_key[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[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 }; srtp_t srtp_snd, srtp_recv; 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 */ crypto_policy_set_rtp_default(&policy.rtp); crypto_policy_set_rtcp_default(&policy.rtcp); policy.ssrc.type = ssrc_specific; policy.ssrc.value = 0xcafebabe; policy.key = test_key; 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 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 (octet_string_is_eq(srtp_plaintext, srtp_ciphertext, len)) return 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 (octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len)) return err_status_fail; return err_status_ok; }
bool SrtpChannel::configureSrtpSession(srtp_t *session, const char* key, enum TransmissionType type) { srtp_policy_t policy; memset(&policy, 0, sizeof(policy)); crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp); crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); if (type == SENDING) { policy.ssrc.type = ssrc_any_outbound; } else { policy.ssrc.type = ssrc_any_inbound; } policy.ssrc.value = 0; policy.window_size = 1024; policy.allow_repeat_tx = 1; policy.next = NULL; //ELOG_DEBUG("auth_tag_len %d", policy.rtp.auth_tag_len); gsize len = 0; uint8_t *akey = (uint8_t*) g_base64_decode((gchar*) key, &len); ELOG_DEBUG("set master key/salt to %s/", octet_string_hex_string(akey, 16)); // allocate and initialize the SRTP session policy.key = akey; int res = srtp_create(session, &policy); if (res!=0){ ELOG_ERROR("Failed to create srtp session with %s, %d", octet_string_hex_string(akey, 16), res); } return res!=0? false:true; }
srtpw_err_status_t srtpw_validate_key(unsigned char *input_key) { char key[SRTP_MAX_KEY_LEN]; int len; /* * read key from hexadecimal into an octet string */ len = hex_string_to_octet_string((char *)key, (char *)input_key, SRTP_MASTER_KEY_LEN*2); /* check that hex string is the right length */ if (len < SRTP_MASTER_KEY_LEN*2) { srtpw_log(err_level_error, "error: too few digits in key/salt " "(should be %d hexadecimal digits, found %d)\n", SRTP_MASTER_KEY_LEN*2, len); return srtpw_err_status_bad_param; } if (strlen((const char *)input_key) > SRTP_MASTER_KEY_LEN*2) { srtpw_log(err_level_error, "error: too many digits in key/salt " "(should be %d hexadecimal digits, found %u)\n", SRTP_MASTER_KEY_LEN*2, (unsigned)strlen((const char *)input_key)); return srtpw_err_status_bad_param; } srtpw_log(err_level_info,"set master key/salt to %s/", octet_string_hex_string(key, SRTP_MASTERKEY_LEN)); srtpw_log(err_level_info,"%s\n", octet_string_hex_string(key+SRTP_MASTERKEY_LEN, SRTP_MASTERSALT_LEN)); return srtpw_err_status_ok; }
err_status_t sha1_test_case_validate(const hash_test_case_t *test_case) { sha1_ctx_t ctx; uint32_t hash_value[5]; if (test_case == NULL) return err_status_bad_param; if (test_case->hash_len != 20) return err_status_bad_param; if (test_case->data_len > MAX_HASH_DATA_LEN) return err_status_bad_param; sha1_init(&ctx); sha1_update(&ctx, test_case->data, test_case->data_len); sha1_final(&ctx, hash_value); if (0 == memcmp(test_case->hash, hash_value, 20)) { #if VERBOSE printf("PASSED: reference value: %s\n", octet_string_hex_string((const uint8_t *)test_case->hash, 20)); printf("PASSED: computed value: %s\n", octet_string_hex_string((const uint8_t *)hash_value, 20)); #endif return err_status_ok; } printf("reference value: %s\n", octet_string_hex_string((const uint8_t *)test_case->hash, 20)); printf("computed value: %s\n", octet_string_hex_string((const uint8_t *)hash_value, 20)); return err_status_algo_fail; }
err_status_t null_enc(void *key, const void *clear, unsigned clear_len, void *iv, void *opaque, unsigned *opaque_len) { int i; unsigned char *auth_tag; unsigned char *init_vec = iv; /* check if we're doing authentication only */ if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) { /* perform authentication only */ } else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) { /* * bad parameter - we expect either all three pointers to be NULL, * or none of those pointers to be NULL */ return err_status_fail; } else { #if DEBUG printf("NULL ENC using key %s\n", octet_string_hex_string(key, KEY_LEN)); printf("NULL_TAG_LEN: %d\n", NULL_TAG_LEN); printf("plaintext len: %d\n", *opaque_len); #endif for (i=0; i < IV_LEN; i++) init_vec[i] = i + (i * 16); #if DEBUG printf("iv: %s\n", octet_string_hex_string(iv, IV_LEN)); printf("plaintext: %s\n", octet_string_hex_string(opaque, *opaque_len)); #endif auth_tag = opaque; auth_tag += *opaque_len; for (i=0; i < NULL_TAG_LEN; i++) auth_tag[i] = i + (i * 16); *opaque_len += NULL_TAG_LEN; #if DEBUG printf("protected data len: %d\n", *opaque_len); printf("protected data: %s\n", octet_string_hex_string(opaque, *opaque_len)); #endif } return err_status_ok; }
void ekt_write_data(ekt_stream_t ekt, uint8_t *base_tag, unsigned base_tag_len, int *packet_len, xtd_seq_num_t pkt_index) { uint32_t roc; uint16_t isn; unsigned emk_len; uint8_t *packet; /* if the pointer ekt is NULL, then EKT is not in effect */ if (!ekt) { debug_print(mod_srtp, "EKT not in use", NULL); return; } /* write zeros into the location of the base tag */ octet_string_set_to_zero(base_tag, base_tag_len); packet = base_tag + base_tag_len; /* copy encrypted master key into packet */ emk_len = ekt_octets_after_base_tag(ekt); memcpy(packet, ekt->encrypted_master_key, emk_len); debug_print(mod_srtp, "writing EKT EMK: %s,", octet_string_hex_string(packet, emk_len)); packet += emk_len; /* copy ROC into packet */ roc = (uint32_t)(pkt_index >> 16); *((uint32_t *)packet) = be32_to_cpu(roc); debug_print(mod_srtp, "writing EKT ROC: %s,", octet_string_hex_string(packet, sizeof(roc))); packet += sizeof(roc); /* copy ISN into packet */ isn = (uint16_t)pkt_index; *((uint16_t *)packet) = htons(isn); debug_print(mod_srtp, "writing EKT ISN: %s,", octet_string_hex_string(packet, sizeof(isn))); packet += sizeof(isn); /* copy SPI into packet */ *((uint16_t *)packet) = htons(ekt->data->spi); debug_print(mod_srtp, "writing EKT SPI: %s,", octet_string_hex_string(packet, sizeof(ekt->data->spi))); /* increase packet length appropriately */ *packet_len += EKT_OCTETS_AFTER_EMK + emk_len; }
err_status_t hmac_init(hmac_ctx_t *state, const octet_t *key, int key_len) { int i; /* * check key length - note that we don't support keys larger * than 20 bytes yet */ if (key_len > 20) return err_status_bad_param; /* * set values of ipad and opad in the context by exoring the key * into the appropriate constant values */ for (i=0; i < key_len; i++) { state->ipad[i] = key[i] ^ 0x36; state->opad[i] = key[i] ^ 0x5c; } /* set the rest of ipad, opad to constant values */ for ( ; i < 64; i++) { ((octet_t *)state->ipad)[i] = 0x36; ((octet_t *)state->opad)[i] = 0x5c; } debug_print(mod_hmac, "ipad: %s", octet_string_hex_string(state->ipad, 64)); /* initialize sha1 context */ sha1_init(&state->ctx); /* hash ipad ^ key */ sha1_update(&state->ctx, (octet_t *)state->ipad, 64); return err_status_ok; }
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 */ sprintf(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; }
static void printSessionList (void) { ismacryp_session_t *temp; int i = 0; fprintf(stdout, "Session List:\n"); if (sessionList == NULL) { fprintf(stdout, " -- EMPTY --\n"); return; } temp=sessionList; while(temp != NULL) { i++; fprintf(stdout, " -- Session #%d: session id: %d \n", i, temp->sessid ); fprintf(stdout, " key l: %d salt l: %d ctr l: %d iv l: %d key t: %c\n", AES_KEY_LEN, AES_SALT_LEN, AES_COUNTER_LEN, temp->IV_len, ismacryp_keytypeStr[temp->key_type][7]); fprintf(stdout, " key : %s", #ifdef HAVE_SRTP octet_string_hex_string(temp->kk.ksc.key, AES_KEY_LEN) #else "n/a" #endif ); fprintf(stdout, "\n"); fprintf(stdout, " salt: %s", #ifdef HAVE_SRTP octet_string_hex_string(temp->kk.ksc.salt, AES_SALT_LEN) #else "n/a" #endif ); fprintf(stdout, "\n"); fprintf(stdout, " ctr : %s", #ifdef HAVE_SRTP octet_string_hex_string(temp->kk.ksc.counter, AES_COUNTER_LEN) #else "n/a" #endif ); fprintf(stdout, "\n"); temp=temp->next; } }
err_status_t null_dec(void *key, const void *clear, unsigned clear_len, void *iv, void *opaque, unsigned *opaque_len) { unsigned char *auth_tag; /* check if we're doing authentication only */ if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) { /* perform authentication only */ } else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) { /* * bad parameter - we expect either all three pointers to be NULL, * or none of those pointers to be NULL */ return err_status_fail; } else { #if DEBUG printf("NULL DEC using key %s\n", octet_string_hex_string(key, KEY_LEN)); printf("protected data len: %d\n", *opaque_len); printf("protected data: %s\n", octet_string_hex_string(opaque, *opaque_len)); #endif auth_tag = opaque; auth_tag += (*opaque_len - NULL_TAG_LEN); #if DEBUG printf("iv: %s\n", octet_string_hex_string(iv, IV_LEN)); #endif *opaque_len -= NULL_TAG_LEN; #if DEBUG printf("plaintext len: %d\n", *opaque_len); printf("plaintext: %s\n", octet_string_hex_string(opaque, *opaque_len)); #endif } return err_status_ok; }
err_status_t hmac_compute (hmac_ctx_t *state, const void *message, int msg_octets, int tag_len, uint8_t *result) { uint32_t hash_value[5]; uint32_t H[5]; int i; /* check tag length, return error if we can't provide the value expected */ if (tag_len > HMAC_KEYLEN_MAX) { return err_status_bad_param; } /* hash message, copy output into H */ sha1_update(&state->ctx, message, msg_octets); sha1_final(&state->ctx, H); /* * note that we don't need to debug_print() the input, since the * function hmac_update() already did that for us */ debug_print(mod_hmac, "intermediate state: %s", octet_string_hex_string((uint8_t*)H, sizeof(H))); /* re-initialize hash context */ sha1_init(&state->ctx); /* hash opad ^ key */ sha1_update(&state->ctx, (uint8_t*)state->opad, sizeof(state->opad)); /* hash the result of the inner hash */ sha1_update(&state->ctx, (uint8_t*)H, sizeof(H)); /* the result is returned in the array hash_value[] */ sha1_final(&state->ctx, hash_value); /* copy hash_value to *result */ for (i = 0; i < tag_len; i++) { result[i] = ((uint8_t*)hash_value)[i]; } debug_print(mod_hmac, "output: %s", octet_string_hex_string((uint8_t*)hash_value, tag_len)); return err_status_ok; }
void test_hex_string_funcs(void) { char hex1[] = "abadcafe"; char hex2[] = "0123456789abcdefqqqqq"; char raw[10]; int len; len = hex_string_to_octet_string(raw, hex1, strlen(hex1)); printf("computed length: %d\tstring: %s\n", len, octet_string_hex_string(raw, len/2)); printf("expected length: %u\tstring: %s\n", (unsigned)strlen(hex1), hex1); len = hex_string_to_octet_string(raw, hex2, strlen(hex2)); printf("computed length: %d\tstring: %s\n", len, octet_string_hex_string(raw, len/2)); printf("expected length: %d\tstring: %s\n", 16, "0123456789abcdef"); }
// int main(int argc, char *argv[]) { int aes_calc(char *key8, char *phrase8, char *cipher8) { v128_t data, key; aes_expanded_key_t exp_key; int len; int verbose = 0; /* read in key, checking length */ if (strlen(key8) > AES_KEY_LEN * 2) { fprintf(stderr, "error: too many digits in key " "(should be %d hexadecimal digits, found %u)\n", AES_KEY_LEN * 2, (unsigned) strlen(key8)); return(1); } len = hex_string_to_octet_string((char *) &key, key8, AES_KEY_LEN*2); /* check that hex string is the right length */ if (len < AES_KEY_LEN * 2) { fprintf(stderr, "error: too few digits in key " "(should be %d hexadecimal digits, found %d)\n", AES_KEY_LEN * 2, len); return(1); } /* read in plaintext, checking length */ if (strlen(phrase8) > 16 * 2) { fprintf(stderr, "error: too many digits in plaintext " "(should be %d hexadecimal digits, found %u)\n", 16 * 2, (unsigned) strlen(phrase8)); return(1); } len = hex_string_to_octet_string((char *) (&data), phrase8, 16 * 2); /* check that hex string is the right length */ if (len < 16 * 2) { fprintf(stderr, "error: too few digits in plaintext " "(should be %d hexadecimal digits, found %d)\n", 16 * 2, len); return(1); } if (verbose) { /* print out plaintext */ printf("plaintext:\t%s\n", octet_string_hex_string((uint8_t *) &data, 16)); } /* encrypt plaintext */ aes_expand_encryption_key(&key, exp_key); aes_encrypt(&data, exp_key); /* write ciphertext to output */ if (verbose) { printf("key:\t\t%s\n", v128_hex_string(&key)); printf("ciphertext:\t"); } printf("%s\n", v128_hex_string(&data)); return strcmp(v128_hex_string(&data), cipher8); }
void test_bswap(void) { uint32_t x = 0x11223344; uint64_t y = 0x1122334455667788LL; printf("before: %0x\nafter: %0x\n", x, (unsigned int)be32_to_cpu(x)); printf("before: %0llx\nafter: %0llx\n", (unsigned long long)y, (unsigned long long)be64_to_cpu(y)); y = 1234; printf("1234: %0llx\n", (unsigned long long)y); printf("as octet string: %s\n", octet_string_hex_string((uint8_t *) &y, 8)); y = be64_to_cpu(y); printf("bswapped octet string: %s\n", octet_string_hex_string((uint8_t *) &y, 8)); }
srtpw_err_status_t srtpw_srtp_protect(srtpw_srtp_policy *p, srtpw_srtp *srtp, void *buf, int *len,int rtcp) { int res; #ifdef DEBUG srtpw_log(err_level_debug,"reference packet before protection:\n%s", octet_string_hex_string((uint8_t *)buf, *len)); #endif return (res = rtcp ? srtp_protect_rtcp((srtp_t)srtp, buf, len) : srtp_protect((srtp_t)srtp, buf, len)); }
err_status_t hmac_update(hmac_ctx_t *state, const uint8_t *message, int msg_octets) { debug_print(mod_hmac, "input: %s", octet_string_hex_string(message, msg_octets)); /* hash message into sha1 context */ sha1_update(&state->ctx, message, msg_octets); return err_status_ok; }
err_status_t aes_cbc_context_init(aes_cbc_ctx_t *c, const uint8_t *key, int key_len) { debug_print(mod_aes_cbc, "key: %s", octet_string_hex_string(key, key_len)); /* * Save the key until we have the IV later. We don't * know the direction until the IV is set. */ c->key_len = (key_len <= 32 ? key_len : 32); memcpy(c->key, key, c->key_len); return err_status_ok; }
// int main(int argc, char *argv[]) { int rand_gen(unsigned num_octets, unsigned do_debug) { unsigned do_list_mods = 0; err_status_t status; /* initialize kernel - we need to do this before anything else */ status = crypto_kernel_init(0); if (status) { printf("error: crypto_kernel init failed\n"); return(1); } if (do_debug) { status = crypto_kernel_set_debug_module(optarg, 1); if (status) { printf("error: set debug module (%s) failed\n", optarg); return(1); } } if (do_list_mods) { status = crypto_kernel_list_debug_modules(); if (status) { printf("error: list of debug modules failed\n"); return(1); } } if (num_octets > 0) { uint8_t buffer[BUF_LEN]; status = crypto_get_random(buffer, num_octets); if (status) { printf("error: failure in random source\n"); } else { printf("%s\n", octet_string_hex_string(buffer, num_octets)); } } status = crypto_kernel_shutdown(); if (status) { printf("error: crypto_kernel shutdown failed\n"); return(1); } return 0; }
err_status_t hmac_init (hmac_ctx_t *state, const uint8_t *key, int key_len) { int i; uint8_t ipad[64]; /* * check key length - note that we don't support keys larger * than 20 bytes yet */ if (key_len > HMAC_KEYLEN_MAX) { return err_status_bad_param; } /* * set values of ipad and opad by exoring the key into the * appropriate constant values */ for (i = 0; i < key_len; i++) { ipad[i] = key[i] ^ 0x36; state->opad[i] = key[i] ^ 0x5c; } /* set the rest of ipad, opad to constant values */ for (; i < sizeof(ipad); i++) { ipad[i] = 0x36; ((uint8_t*)state->opad)[i] = 0x5c; } debug_print(mod_hmac, "ipad: %s", octet_string_hex_string(ipad, sizeof(ipad))); /* initialize sha1 context */ sha1_init(&state->init_ctx); state->init_ctx_initialized = 1; /* hash ipad ^ key */ sha1_update(&state->init_ctx, ipad, sizeof(ipad)); return (hmac_start(state)); }
char *srtpw_octet_string_hex_string(const void *str, int length) { return octet_string_hex_string(str,length); }
err_status_t stat_test_rand_source(rand_source_func_t get_rand_bytes) { int i; double poker; uint8_t *data, *data_end; uint16_t f[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; uint8_t buffer[RAND_SRC_BUF_OCTETS]; err_status_t status; int ones_count = 0; uint16_t runs[6] = { 0, 0, 0, 0, 0, 0 }; uint16_t gaps[6] = { 0, 0, 0, 0, 0, 0 }; uint16_t lo_value[6] = { 2315, 1114, 527, 240, 103, 103 }; uint16_t hi_value[6] = { 2685, 1386, 723, 384, 209, 209 }; int state = 0; uint16_t mask; /* counters for monobit, poker, and runs tests are initialized above */ /* main loop: fill buffer, update counters for stat tests */ for (i=0; i < 2500; i+=RAND_SRC_BUF_OCTETS) { /* fill data buffer */ status = get_rand_bytes(buffer, RAND_SRC_BUF_OCTETS); if (status) { debug_print(mod_stat, "couldn't get rand bytes: %d",status); return status; } #if 0 debug_print(mod_stat, "%s", octet_string_hex_string(buffer, RAND_SRC_BUF_OCTETS)); #endif data = buffer; data_end = data + RAND_SRC_BUF_OCTETS; while (data < data_end) { /* update monobit test counter */ ones_count += octet_get_weight(*data); /* update poker test counters */ f[*data & 0x0f]++; /* increment freq. count for low nibble */ f[(*data) >> 4]++; /* increment freq. count for high nibble */ /* update runs test counters */ /* loop over the bits of this byte */ for (mask = 1; mask < 256; mask <<= 1) { if (*data & mask) { /* next bit is a one */ if (state > 0) { /* prefix is a run, so increment the run-count */ state++; /* check for long runs */ if (state > 25) { debug_print(mod_stat, ">25 runs (3): %d", state); return err_status_algo_fail; } } else if (state < 0) { /* prefix is a gap */ if (state < -25) { debug_print(mod_stat, ">25 gaps (3): %d", state); return err_status_algo_fail; /* long-runs test failed */ } if (state < -6) { state = -6; /* group together gaps > 5 */ } gaps[-1-state]++; /* increment gap count */ state = 1; /* set state at one set bit */ } else { /* state is zero; this happens only at initialization */ state = 1; } } else { /* next bit is a zero */ if (state > 0) { /* prefix is a run */ if (state > 25) { debug_print(mod_stat, ">25 runs (4): %d", state); return err_status_algo_fail; /* long-runs test failed */ } if (state > 6) { state = 6; /* group together runs > 5 */ } runs[state-1]++; /* increment run count */ state = -1; /* set state at one zero bit */ } else if (state < 0) { /* prefix is a gap, so increment gap-count (decrement state) */ state--; /* check for long gaps */ if (state < -25) { debug_print(mod_stat, ">25 gaps (4): %d", state); return err_status_algo_fail; } } else { /* state is zero; this happens only at initialization */ state = -1; } } } /* advance data pointer */ data++; } } /* check to see if test data is within bounds */ /* check monobit test data */ debug_print(mod_stat, "stat: bit count: %d", ones_count); if ((ones_count < 9725) || (ones_count > 10275)) { debug_print(mod_stat, "stat: failed monobit test %d", ones_count); return err_status_algo_fail; } /* check poker test data */ poker = 0.0; for (i=0; i < 16; i++) poker += (double) f[i] * f[i]; poker *= (16.0 / 5000.0); poker -= 5000.0; debug_print(mod_stat, "stat: poker test: %f", poker); if ((poker < 2.16) || (poker > 46.17)) { debug_print(mod_stat, "stat: failed poker test", NULL); return err_status_algo_fail; } /* check run and gap counts against the fixed limits */ for (i=0; i < 6; i++) if ((runs[i] < lo_value[i] ) || (runs[i] > hi_value[i]) || (gaps[i] < lo_value[i] ) || (gaps[i] > hi_value[i])) { debug_print(mod_stat, "stat: failed run/gap test", NULL); return err_status_algo_fail; } debug_print(mod_stat, "passed random stat test", NULL); return err_status_ok; }
err_status_t aes_128_cbc_hmac_sha1_96_enc(void *key, const void *clear, unsigned clear_len, void *iv, void *opaque, unsigned *opaque_len) { aes_cbc_ctx_t aes_ctx; hmac_ctx_t hmac_ctx; unsigned char enc_key[ENC_KEY_LEN]; unsigned char mac_key[MAC_KEY_LEN]; unsigned char *auth_tag; err_status_t status; /* check if we're doing authentication only */ if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) { /* perform authentication only */ } else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) { /* * bad parameter - we expect either all three pointers to be NULL, * or none of those pointers to be NULL */ return err_status_fail; } else { #if DEBUG printf("ENC using key %s\n", octet_string_hex_string(key, KEY_LEN)); #endif /* derive encryption and authentication keys from the input key */ status = hmac_init(&hmac_ctx, key, KEY_LEN); if (status) return status; status = hmac_compute(&hmac_ctx, "ENC", 3, ENC_KEY_LEN, enc_key); if (status) return status; status = hmac_init(&hmac_ctx, key, KEY_LEN); if (status) return status; status = hmac_compute(&hmac_ctx, "MAC", 3, MAC_KEY_LEN, mac_key); if (status) return status; /* perform encryption and authentication */ /* set aes key */ status = aes_cbc_context_init(&aes_ctx, key, direction_encrypt); if (status) return status; /* set iv */ status = rand_source_get_octet_string(iv, IV_LEN); if (status) return status; status = aes_cbc_set_iv(&aes_ctx, iv); if (status) return status; #if DEBUG printf("plaintext len: %d\n", *opaque_len); printf("iv: %s\n", octet_string_hex_string(iv, IV_LEN)); printf("plaintext: %s\n", octet_string_hex_string(opaque, *opaque_len)); #endif #if ENC /* encrypt the opaque data */ status = aes_cbc_nist_encrypt(&aes_ctx, opaque, opaque_len); if (status) return status; #endif #if DEBUG printf("ciphertext len: %d\n", *opaque_len); printf("ciphertext: %s\n", octet_string_hex_string(opaque, *opaque_len)); #endif /* * authenticate clear and opaque data, then write the * authentication tag to the location immediately following the * ciphertext */ status = hmac_init(&hmac_ctx, mac_key, MAC_KEY_LEN); if (status) return status; status = hmac_start(&hmac_ctx); if (status) return status; status = hmac_update(&hmac_ctx, clear, clear_len); if (status) return status; #if DEBUG printf("hmac input: %s\n", octet_string_hex_string(clear, clear_len)); #endif auth_tag = (unsigned char *)opaque; auth_tag += *opaque_len; status = hmac_compute(&hmac_ctx, opaque, *opaque_len, TAG_LEN, auth_tag); if (status) return status; #if DEBUG printf("hmac input: %s\n", octet_string_hex_string(opaque, *opaque_len)); #endif /* bump up the opaque_len to reflect the authentication tag */ *opaque_len += TAG_LEN; #if DEBUG printf("prot data len: %d\n", *opaque_len); printf("prot data: %s\n", octet_string_hex_string(opaque, *opaque_len)); #endif } return err_status_ok; }
err_status_t auth_type_self_test(const auth_type_t *at) { auth_test_case_t *test_case = at->test_data; auth_t *a; err_status_t status; uint8_t tag[SELF_TEST_TAG_BUF_OCTETS]; int i, case_num = 0; debug_print(mod_auth, "running self-test for auth function %s", at->description); /* * check to make sure that we have at least one test case, and * return an error if we don't - we need to be paranoid here */ if (test_case == NULL) return err_status_cant_check; /* loop over all test cases */ while (test_case != NULL) { /* check test case parameters */ if (test_case->tag_length_octets > SELF_TEST_TAG_BUF_OCTETS) return err_status_bad_param; /* allocate auth */ status = auth_type_alloc(at, &a, test_case->key_length_octets, test_case->tag_length_octets); if (status) return status; /* initialize auth */ status = auth_init(a, test_case->key); if (status) { auth_dealloc(a); return status; } /* zeroize tag then compute */ octet_string_set_to_zero(tag, test_case->tag_length_octets); status = auth_compute(a, test_case->data, test_case->data_length_octets, tag); if (status) { auth_dealloc(a); return status; } debug_print(mod_auth, "key: %s", octet_string_hex_string(test_case->key, test_case->key_length_octets)); debug_print(mod_auth, "data: %s", octet_string_hex_string(test_case->data, test_case->data_length_octets)); debug_print(mod_auth, "tag computed: %s", octet_string_hex_string(tag, test_case->tag_length_octets)); debug_print(mod_auth, "tag expected: %s", octet_string_hex_string(test_case->tag, test_case->tag_length_octets)); /* check the result */ status = err_status_ok; for (i=0; i < test_case->tag_length_octets; i++) if (tag[i] != test_case->tag[i]) { status = err_status_algo_fail; debug_print(mod_auth, "test case %d failed", case_num); debug_print(mod_auth, " (mismatch at octet %d)", i); } if (status) { auth_dealloc(a); return err_status_algo_fail; } /* deallocate the auth function */ status = auth_dealloc(a); if (status) return status; /* * the auth function passed the test case, so move on to the next test * case in the list; if NULL, we'll quit and return an OK */ test_case = test_case->next_test_case; ++case_num; } return err_status_ok; }
int main (int argc, char *argv[]) { char *dictfile = DICT_FILE; FILE *dict; char word[MAX_WORD_LEN]; int sock, ret; struct in_addr rcvr_addr; struct sockaddr_in name; struct ip_mreq mreq; #if BEW struct sockaddr_in local; #endif program_type prog_type = unknown; sec_serv_t sec_servs = sec_serv_none; unsigned char ttl = 5; int c; int key_size = 128; int tag_size = 8; int gcm_on = 0; char *input_key = NULL; char *address = NULL; char key[MAX_KEY_LEN]; unsigned short port = 0; rtp_sender_t snd; srtp_policy_t policy; err_status_t status; int len; int do_list_mods = 0; uint32_t ssrc = 0xdeadbeef; /* ssrc value hardcoded for now */ #ifdef RTPW_USE_WINSOCK2 WORD wVersionRequested = MAKEWORD(2, 0); WSADATA wsaData; ret = WSAStartup(wVersionRequested, &wsaData); if (ret != 0) { fprintf(stderr, "error: WSAStartup() failed: %d\n", ret); exit(1); } #endif if (setup_signal_handler(argv[0]) != 0) { exit(1); } /* initialize srtp library */ status = srtp_init(); if (status) { printf("error: srtp initialization failed with error code %d\n", status); exit(1); } /* check args */ while (1) { c = getopt_s(argc, argv, "k:rsgt:ae:ld:"); if (c == -1) { break; } switch (c) { case 'k': input_key = optarg_s; break; case 'e': key_size = atoi(optarg_s); if (key_size != 128 && key_size != 256) { printf("error: encryption key size must be 128 or 256 (%d)\n", key_size); exit(1); } sec_servs |= sec_serv_conf; break; case 't': tag_size = atoi(optarg_s); if (tag_size != 8 && tag_size != 16) { printf("error: GCM tag size must be 8 or 16 (%d)\n", tag_size); exit(1); } break; case 'a': sec_servs |= sec_serv_auth; break; case 'g': gcm_on = 1; sec_servs |= sec_serv_auth; break; case 'r': prog_type = receiver; break; case 's': prog_type = sender; break; case 'd': status = crypto_kernel_set_debug_module(optarg_s, 1); if (status) { printf("error: set debug module (%s) failed\n", optarg_s); exit(1); } break; case 'l': do_list_mods = 1; break; default: usage(argv[0]); } } if (prog_type == unknown) { if (do_list_mods) { status = crypto_kernel_list_debug_modules(); if (status) { printf("error: list of debug modules failed\n"); exit(1); } return 0; } else { printf("error: neither sender [-s] nor receiver [-r] specified\n"); usage(argv[0]); } } if ((sec_servs && !input_key) || (!sec_servs && input_key)) { /* * a key must be provided if and only if security services have * been requested */ usage(argv[0]); } if (argc != optind_s + 2) { /* wrong number of arguments */ usage(argv[0]); } /* get address from arg */ address = argv[optind_s++]; /* get port from arg */ port = atoi(argv[optind_s++]); /* set address */ #ifdef HAVE_INET_ATON if (0 == inet_aton(address, &rcvr_addr)) { fprintf(stderr, "%s: cannot parse IP v4 address %s\n", argv[0], address); exit(1); } if (rcvr_addr.s_addr == INADDR_NONE) { fprintf(stderr, "%s: address error", argv[0]); exit(1); } #else rcvr_addr.s_addr = inet_addr(address); if (0xffffffff == rcvr_addr.s_addr) { fprintf(stderr, "%s: cannot parse IP v4 address %s\n", argv[0], address); exit(1); } #endif /* open socket */ sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sock < 0) { int err; #ifdef RTPW_USE_WINSOCK2 err = WSAGetLastError(); #else err = errno; #endif fprintf(stderr, "%s: couldn't open socket: %d\n", argv[0], err); exit(1); } name.sin_addr = rcvr_addr; name.sin_family = PF_INET; name.sin_port = htons(port); if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) { if (prog_type == sender) { ret = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); if (ret < 0) { fprintf(stderr, "%s: Failed to set TTL for multicast group", argv[0]); perror(""); exit(1); } } mreq.imr_multiaddr.s_addr = rcvr_addr.s_addr; mreq.imr_interface.s_addr = htonl(INADDR_ANY); ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*)&mreq, sizeof(mreq)); if (ret < 0) { fprintf(stderr, "%s: Failed to join multicast group", argv[0]); perror(""); exit(1); } } /* report security services selected on the command line */ printf("security services: "); if (sec_servs & sec_serv_conf) printf("confidentiality "); if (sec_servs & sec_serv_auth) printf("message authentication"); if (sec_servs == sec_serv_none) printf("none"); printf("\n"); /* set up the srtp policy and master key */ if (sec_servs) { /* * create policy structure, using the default mechanisms but * with only the security services requested on the command line, * using the right SSRC value */ switch (sec_servs) { case sec_serv_conf_and_auth: if (gcm_on) { #ifdef OPENSSL switch (key_size) { case 128: crypto_policy_set_aes_gcm_128_8_auth(&policy.rtp); crypto_policy_set_aes_gcm_128_8_auth(&policy.rtcp); break; case 256: crypto_policy_set_aes_gcm_256_8_auth(&policy.rtp); crypto_policy_set_aes_gcm_256_8_auth(&policy.rtcp); break; } #else printf("error: GCM mode only supported when using the OpenSSL crypto engine.\n"); return 0; #endif } else { switch (key_size) { case 128: crypto_policy_set_rtp_default(&policy.rtp); crypto_policy_set_rtcp_default(&policy.rtcp); break; case 256: crypto_policy_set_aes_cm_256_hmac_sha1_80(&policy.rtp); crypto_policy_set_rtcp_default(&policy.rtcp); break; } } break; case sec_serv_conf: if (gcm_on) { printf("error: GCM mode must always be used with auth enabled\n"); return -1; } else { switch (key_size) { case 128: crypto_policy_set_aes_cm_128_null_auth(&policy.rtp); crypto_policy_set_rtcp_default(&policy.rtcp); break; case 256: crypto_policy_set_aes_cm_256_null_auth(&policy.rtp); crypto_policy_set_rtcp_default(&policy.rtcp); break; } } break; case sec_serv_auth: if (gcm_on) { #ifdef OPENSSL switch (key_size) { case 128: crypto_policy_set_aes_gcm_128_8_only_auth(&policy.rtp); crypto_policy_set_aes_gcm_128_8_only_auth(&policy.rtcp); break; case 256: crypto_policy_set_aes_gcm_256_8_only_auth(&policy.rtp); crypto_policy_set_aes_gcm_256_8_only_auth(&policy.rtcp); break; } #else printf("error: GCM mode only supported when using the OpenSSL crypto engine.\n"); return 0; #endif } else { crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtp); crypto_policy_set_rtcp_default(&policy.rtcp); } break; default: printf("error: unknown security service requested\n"); return -1; } policy.ssrc.type = ssrc_specific; policy.ssrc.value = ssrc; policy.key = (uint8_t *) key; policy.ekt = NULL; policy.next = NULL; policy.window_size = 128; policy.allow_repeat_tx = 0; policy.rtp.sec_serv = sec_servs; policy.rtcp.sec_serv = sec_serv_none; /* we don't do RTCP anyway */ if (gcm_on && tag_size != 8) { policy.rtp.auth_tag_len = tag_size; } /* * read key from hexadecimal on command line into an octet string */ len = hex_string_to_octet_string(key, input_key, policy.rtp.cipher_key_len*2); /* check that hex string is the right length */ if (len < policy.rtp.cipher_key_len*2) { fprintf(stderr, "error: too few digits in key/salt " "(should be %d hexadecimal digits, found %d)\n", policy.rtp.cipher_key_len*2, len); exit(1); } if (strlen(input_key) > policy.rtp.cipher_key_len*2) { fprintf(stderr, "error: too many digits in key/salt " "(should be %d hexadecimal digits, found %u)\n", policy.rtp.cipher_key_len*2, (unsigned)strlen(input_key)); exit(1); } printf("set master key/salt to %s/", octet_string_hex_string(key, 16)); printf("%s\n", octet_string_hex_string(key+16, 14)); } else { /* * we're not providing security services, so set the policy to the * null policy * * Note that this policy does not conform to the SRTP * specification, since RTCP authentication is required. However, * the effect of this policy is to turn off SRTP, so that this * application is now a vanilla-flavored RTP application. */ policy.key = (uint8_t *)key; policy.ssrc.type = ssrc_specific; policy.ssrc.value = ssrc; policy.rtp.cipher_type = NULL_CIPHER; policy.rtp.cipher_key_len = 0; policy.rtp.auth_type = NULL_AUTH; policy.rtp.auth_key_len = 0; policy.rtp.auth_tag_len = 0; policy.rtp.sec_serv = sec_serv_none; policy.rtcp.cipher_type = NULL_CIPHER; policy.rtcp.cipher_key_len = 0; policy.rtcp.auth_type = NULL_AUTH; policy.rtcp.auth_key_len = 0; policy.rtcp.auth_tag_len = 0; policy.rtcp.sec_serv = sec_serv_none; policy.window_size = 0; policy.allow_repeat_tx = 0; policy.ekt = NULL; policy.next = NULL; } if (prog_type == sender) { #if BEW /* bind to local socket (to match crypto policy, if need be) */ memset(&local, 0, sizeof(struct sockaddr_in)); local.sin_addr.s_addr = htonl(INADDR_ANY); local.sin_port = htons(port); ret = bind(sock, (struct sockaddr *) &local, sizeof(struct sockaddr_in)); if (ret < 0) { fprintf(stderr, "%s: bind failed\n", argv[0]); perror(""); exit(1); } #endif /* BEW */ /* initialize sender's rtp and srtp contexts */ snd = rtp_sender_alloc(); if (snd == NULL) { fprintf(stderr, "error: malloc() failed\n"); exit(1); } rtp_sender_init(snd, sock, name, ssrc); status = rtp_sender_init_srtp(snd, &policy); if (status) { fprintf(stderr, "error: srtp_create() failed with code %d\n", status); exit(1); } /* open dictionary */ dict = fopen (dictfile, "r"); if (dict == NULL) { fprintf(stderr, "%s: couldn't open file %s\n", argv[0], dictfile); if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) { leave_group(sock, mreq, argv[0]); } exit(1); } /* read words from dictionary, then send them off */ while (!interrupted && fgets(word, MAX_WORD_LEN, dict) != NULL) { len = strlen(word) + 1; /* plus one for null */ if (len > MAX_WORD_LEN) printf("error: word %s too large to send\n", word); else { rtp_sendto(snd, word, len); printf("sending word: %s", word); } usleep(USEC_RATE); } rtp_sender_deinit_srtp(snd); rtp_sender_dealloc(snd); fclose(dict); } else { /* prog_type == receiver */ rtp_receiver_t rcvr; if (bind(sock, (struct sockaddr *)&name, sizeof(name)) < 0) { close(sock); fprintf(stderr, "%s: socket bind error\n", argv[0]); perror(NULL); if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) { leave_group(sock, mreq, argv[0]); } exit(1); } rcvr = rtp_receiver_alloc(); if (rcvr == NULL) { fprintf(stderr, "error: malloc() failed\n"); exit(1); } rtp_receiver_init(rcvr, sock, name, ssrc); status = rtp_receiver_init_srtp(rcvr, &policy); if (status) { fprintf(stderr, "error: srtp_create() failed with code %d\n", status); exit(1); } /* get next word and loop */ while (!interrupted) { len = MAX_WORD_LEN; if (rtp_recvfrom(rcvr, word, &len) > -1) printf("\tword: %s\n", word); } rtp_receiver_deinit_srtp(rcvr); rtp_receiver_dealloc(rcvr); } if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) { leave_group(sock, mreq, argv[0]); } #ifdef RTPW_USE_WINSOCK2 ret = closesocket(sock); #else ret = close(sock); #endif if (ret < 0) { fprintf(stderr, "%s: Failed to close socket", argv[0]); perror(""); } status = srtp_shutdown(); if (status) { printf("error: srtp shutdown failed with error code %d\n", status); exit(1); } #ifdef RTPW_USE_WINSOCK2 WSACleanup(); #endif return 0; }
err_status_t aes_128_cbc_hmac_sha1_96_dec(void *key, const void *clear, unsigned clear_len, void *iv, void *opaque, unsigned *opaque_len) { aes_cbc_ctx_t aes_ctx; hmac_ctx_t hmac_ctx; unsigned char enc_key[ENC_KEY_LEN]; unsigned char mac_key[MAC_KEY_LEN]; unsigned char tmp_tag[TAG_LEN]; unsigned char *auth_tag; unsigned ciphertext_len; err_status_t status; int i; /* check if we're doing authentication only */ if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) { /* perform authentication only */ } else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) { /* * bad parameter - we expect either all three pointers to be NULL, * or none of those pointers to be NULL */ return err_status_fail; } else { #if DEBUG printf("DEC using key %s\n", octet_string_hex_string(key, KEY_LEN)); #endif /* derive encryption and authentication keys from the input key */ status = hmac_init(&hmac_ctx, key, KEY_LEN); if (status) return status; status = hmac_compute(&hmac_ctx, "ENC", 3, ENC_KEY_LEN, enc_key); if (status) return status; status = hmac_init(&hmac_ctx, key, KEY_LEN); if (status) return status; status = hmac_compute(&hmac_ctx, "MAC", 3, MAC_KEY_LEN, mac_key); if (status) return status; #if DEBUG printf("prot data len: %d\n", *opaque_len); printf("prot data: %s\n", octet_string_hex_string(opaque, *opaque_len)); #endif /* * set the protected data length to that of the ciphertext, by * subtracting out the length of the authentication tag */ ciphertext_len = *opaque_len - TAG_LEN; #if DEBUG printf("ciphertext len: %d\n", ciphertext_len); #endif /* verify the authentication tag */ /* * compute the authentication tag for the clear and opaque data, * and write it to a temporary location */ status = hmac_init(&hmac_ctx, mac_key, MAC_KEY_LEN); if (status) return status; status = hmac_start(&hmac_ctx); if (status) return status; status = hmac_update(&hmac_ctx, clear, clear_len); if (status) return status; #if DEBUG printf("hmac input: %s\n", octet_string_hex_string(clear, clear_len)); #endif status = hmac_compute(&hmac_ctx, opaque, ciphertext_len, TAG_LEN, tmp_tag); if (status) return status; #if DEBUG printf("hmac input: %s\n", octet_string_hex_string(opaque, ciphertext_len)); #endif /* * compare the computed tag with the one provided as input (which * immediately follows the ciphertext) */ auth_tag = (unsigned char *)opaque; auth_tag += ciphertext_len; #if DEBUG printf("auth_tag: %s\n", octet_string_hex_string(auth_tag, TAG_LEN)); printf("tmp_tag: %s\n", octet_string_hex_string(tmp_tag, TAG_LEN)); #endif for (i=0; i < TAG_LEN; i++) { if (tmp_tag[i] != auth_tag[i]) return err_status_auth_fail; } /* bump down the opaque_len to reflect the authentication tag */ *opaque_len -= TAG_LEN; /* decrypt the confidential data */ status = aes_cbc_context_init(&aes_ctx, key, direction_decrypt); if (status) return status; status = aes_cbc_set_iv(&aes_ctx, iv); if (status) return status; #if DEBUG printf("ciphertext: %s\n", octet_string_hex_string(opaque, *opaque_len)); printf("iv: %s\n", octet_string_hex_string(iv, IV_LEN)); #endif #if ENC status = aes_cbc_nist_decrypt(&aes_ctx, opaque, &ciphertext_len); if (status) return status; #endif #if DEBUG printf("plaintext len: %d\n", ciphertext_len); printf("plaintext: %s\n", octet_string_hex_string(opaque, ciphertext_len)); #endif /* indicate the length of the plaintext */ *opaque_len = ciphertext_len; } return err_status_ok; }
/* * Initialize and start SRTP session with the given parameters. */ PJ_DEF(pj_status_t) pjmedia_transport_srtp_start( pjmedia_transport *tp, const pjmedia_srtp_crypto *tx, const pjmedia_srtp_crypto *rx) { transport_srtp *srtp = (transport_srtp*) tp; srtp_policy_t tx_; srtp_policy_t rx_; err_status_t err; int cr_tx_idx = 0; int au_tx_idx = 0; int cr_rx_idx = 0; int au_rx_idx = 0; int crypto_suites_cnt; PJ_ASSERT_RETURN(tp && tx && rx, PJ_EINVAL); if (srtp->session_inited) { pjmedia_transport_srtp_stop(tp); } crypto_suites_cnt = sizeof(crypto_suites)/sizeof(crypto_suites[0]); /* Get encryption and authentication method */ cr_tx_idx = au_tx_idx = get_crypto_idx(&tx->name); if (tx->flags & PJMEDIA_SRTP_NO_ENCRYPTION) cr_tx_idx = 0; if (tx->flags & PJMEDIA_SRTP_NO_AUTHENTICATION) au_tx_idx = 0; cr_rx_idx = au_rx_idx = get_crypto_idx(&rx->name); if (rx->flags & PJMEDIA_SRTP_NO_ENCRYPTION) cr_rx_idx = 0; if (rx->flags & PJMEDIA_SRTP_NO_AUTHENTICATION) au_rx_idx = 0; /* Check whether the crypto-suite requested is supported */ if (cr_tx_idx == -1 || cr_rx_idx == -1 || au_tx_idx == -1 || au_rx_idx == -1) return PJMEDIA_SRTP_ENOTSUPCRYPTO; /* If all options points to 'NULL' method, just bypass SRTP */ if (cr_tx_idx == 0 && cr_rx_idx == 0 && au_tx_idx == 0 && au_rx_idx == 0) { srtp->bypass_srtp = PJ_TRUE; return PJ_SUCCESS; } /* Check key length */ if (tx->key.slen != (pj_ssize_t)crypto_suites[cr_tx_idx].cipher_key_len || rx->key.slen != (pj_ssize_t)crypto_suites[cr_rx_idx].cipher_key_len) return PJMEDIA_SRTP_EINKEYLEN; /* Init transmit direction */ pj_bzero(&tx_, sizeof(srtp_policy_t)); pj_memmove(srtp->tx_key, tx->key.ptr, tx->key.slen); if (cr_tx_idx && au_tx_idx) tx_.rtp.sec_serv = sec_serv_conf_and_auth; else if (cr_tx_idx) tx_.rtp.sec_serv = sec_serv_conf; else if (au_tx_idx) tx_.rtp.sec_serv = sec_serv_auth; else tx_.rtp.sec_serv = sec_serv_none; tx_.key = (uint8_t*)srtp->tx_key; tx_.ssrc.type = ssrc_any_outbound; tx_.ssrc.value = 0; tx_.rtp.cipher_type = crypto_suites[cr_tx_idx].cipher_type; tx_.rtp.cipher_key_len = crypto_suites[cr_tx_idx].cipher_key_len; tx_.rtp.auth_type = crypto_suites[au_tx_idx].auth_type; tx_.rtp.auth_key_len = crypto_suites[au_tx_idx].auth_key_len; tx_.rtp.auth_tag_len = crypto_suites[au_tx_idx].srtp_auth_tag_len; tx_.rtcp = tx_.rtp; tx_.rtcp.auth_tag_len = crypto_suites[au_tx_idx].srtcp_auth_tag_len; tx_.next = NULL; err = srtp_create(&srtp->srtp_tx_ctx, &tx_); if (err != err_status_ok) { return PJMEDIA_ERRNO_FROM_LIBSRTP(err); } srtp->tx_policy = *tx; pj_strset(&srtp->tx_policy.key, srtp->tx_key, tx->key.slen); srtp->tx_policy.name=pj_str(crypto_suites[get_crypto_idx(&tx->name)].name); /* Init receive direction */ pj_bzero(&rx_, sizeof(srtp_policy_t)); pj_memmove(srtp->rx_key, rx->key.ptr, rx->key.slen); if (cr_rx_idx && au_rx_idx) rx_.rtp.sec_serv = sec_serv_conf_and_auth; else if (cr_rx_idx) rx_.rtp.sec_serv = sec_serv_conf; else if (au_rx_idx) rx_.rtp.sec_serv = sec_serv_auth; else rx_.rtp.sec_serv = sec_serv_none; rx_.key = (uint8_t*)srtp->rx_key; rx_.ssrc.type = ssrc_any_inbound; rx_.ssrc.value = 0; rx_.rtp.sec_serv = crypto_suites[cr_rx_idx].service; rx_.rtp.cipher_type = crypto_suites[cr_rx_idx].cipher_type; rx_.rtp.cipher_key_len = crypto_suites[cr_rx_idx].cipher_key_len; rx_.rtp.auth_type = crypto_suites[au_rx_idx].auth_type; rx_.rtp.auth_key_len = crypto_suites[au_rx_idx].auth_key_len; rx_.rtp.auth_tag_len = crypto_suites[au_rx_idx].srtp_auth_tag_len; rx_.rtcp = rx_.rtp; rx_.rtcp.auth_tag_len = crypto_suites[au_rx_idx].srtcp_auth_tag_len; rx_.next = NULL; err = srtp_create(&srtp->srtp_rx_ctx, &rx_); if (err != err_status_ok) { srtp_dealloc(srtp->srtp_tx_ctx); return PJMEDIA_ERRNO_FROM_LIBSRTP(err); } srtp->rx_policy = *rx; pj_strset(&srtp->rx_policy.key, srtp->rx_key, rx->key.slen); srtp->rx_policy.name=pj_str(crypto_suites[get_crypto_idx(&rx->name)].name); /* Declare SRTP session initialized */ srtp->session_inited = PJ_TRUE; PJ_LOG(5, (srtp->pool->obj_name, "TX: %s key=%s", srtp->tx_policy.name.ptr, octet_string_hex_string(tx->key.ptr, tx->key.slen))); if (srtp->tx_policy.flags) { PJ_LOG(5,(srtp->pool->obj_name,"TX: disable%s%s", (cr_tx_idx?"":" enc"), (au_tx_idx?"":" auth"))); } PJ_LOG(5, (srtp->pool->obj_name, "RX: %s key=%s", srtp->rx_policy.name.ptr, octet_string_hex_string(rx->key.ptr, rx->key.slen))); if (srtp->rx_policy.flags) { PJ_LOG(5,(srtp->pool->obj_name,"RX: disable%s%s", (cr_rx_idx?"":" enc"), (au_rx_idx?"":" auth"))); } return PJ_SUCCESS; }
int main(int argc, char *argv[]) { int q; int num_octets = 0; err_status_t status; uint32_t iterations = 0; int print_values = 0; if (argc == 1) { exit(255); } status = crypto_kernel_init(); if (status) { printf("error: crypto_kernel init failed\n"); exit(1); } while (1) { q = getopt_s(argc, argv, "pvn:"); if (q == -1) { break; } switch (q) { case 'p': print_values = 1; break; case 'n': num_octets = atoi(optarg_s); if (num_octets < 0 || num_octets > BUF_LEN) { exit(255); } break; case 'v': num_octets = 30; print_values = 0; break; default: exit(255); } } if (num_octets > 0) { while (iterations < 300000) { uint8_t buffer[BUF_LEN]; status = crypto_get_random(buffer, num_octets); if (status) { printf("iteration %d error: failure in random source\n", iterations); exit(255); } else if (print_values) { printf("%s\n", octet_string_hex_string(buffer, num_octets)); } iterations++; } } status = crypto_kernel_shutdown(); if (status) { printf("error: crypto_kernel shutdown failed\n"); exit(1); } return 0; }
err_status_t cipher_driver_test_buffering (cipher_t *c) { int i, j, num_trials = 1000; unsigned len, buflen = 1024; uint8_t buffer0[buflen], buffer1[buflen], *current, *end; uint8_t idx[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34 }; err_status_t status; printf("testing output buffering for cipher %s...", c->type->description); for (i = 0; i < num_trials; i++) { /* set buffers to zero */ for (j = 0; j < buflen; j++) { buffer0[j] = buffer1[j] = 0; } /* initialize cipher */ status = cipher_set_iv(c, idx, direction_encrypt); if (status) { return status; } /* generate 'reference' value by encrypting all at once */ status = cipher_encrypt(c, buffer0, &buflen); if (status) { return status; } /* re-initialize cipher */ status = cipher_set_iv(c, idx, direction_encrypt); if (status) { return status; } /* now loop over short lengths until buffer1 is encrypted */ current = buffer1; end = buffer1 + buflen; while (current < end) { /* choose a short length */ len = rand() & 0x01f; /* make sure that len doesn't cause us to overreach the buffer */ if (current + len > end) { len = end - current; } status = cipher_encrypt(c, current, &len); if (status) { return status; } /* advance pointer into buffer1 to reflect encryption */ current += len; /* if buffer1 is all encrypted, break out of loop */ if (current == end) { break; } } /* compare buffers */ for (j = 0; j < buflen; j++) { if (buffer0[j] != buffer1[j]) { #if PRINT_DEBUG printf("test case %d failed at byte %d\n", i, j); printf("computed: %s\n", octet_string_hex_string(buffer1, buflen)); printf("expected: %s\n", octet_string_hex_string(buffer0, buflen)); #endif return err_status_algo_fail; } } } printf("passed\n"); return err_status_ok; }
err_status_t srtcp_test(const srtp_policy_t *policy) { int i; srtp_t srtcp_sender; srtp_t srtcp_rcvr; err_status_t status = err_status_ok; srtp_hdr_t *hdr, *hdr2; uint8_t hdr_enc[64]; uint8_t *pkt_end; int msg_len_octets, msg_len_enc; int len; int tag_length = policy->rtp.auth_tag_len; uint32_t ssrc; srtp_policy_t *rcvr_policy; 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_test_packet(msg_len_octets, ssrc); if (hdr == NULL) return err_status_alloc_fail; hdr2 = srtp_create_test_packet(msg_len_octets, ssrc); if (hdr2 == NULL) { free(hdr); return err_status_alloc_fail; } /* set message length */ len = msg_len_octets; 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_protect_rtcp(srtcp_sender, hdr, &len)); 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. */ pkt_end = (uint8_t *)hdr + sizeof(srtp_hdr_t) + msg_len_octets + 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 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 = err_status_algo_fail; for (i=12; i < msg_len_octets+12; i++) if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) { status = 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 = malloc(sizeof(srtp_policy_t)); if (rcvr_policy == NULL) return 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_unprotect_rtcp(srtcp_rcvr, hdr, &len)); 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 < msg_len_octets; i++) if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) { fprintf(stdout, "mismatch at octet %d\n", i); status = err_status_algo_fail; } if (status) { free(hdr); free(hdr2); 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..."); /* set message length */ len = msg_len_enc; /* unprotect a second time - should fail with a replay error */ status = srtp_unprotect_rtcp(srtcp_rcvr, hdr_enc, &len); if (status != err_status_replay_fail) { printf("failed with error code %d\n", status); free(hdr); free(hdr2); return status; } else { printf("passed\n"); } printf("testing for false positives in auth check..."); /* increment sequence number in header */ hdr->seq++; /* set message length */ len = msg_len_octets; /* apply protection */ err_check(srtp_protect_rtcp(srtcp_sender, hdr, &len)); /* flip bits in packet */ data[0] ^= 0xff; /* unprotect, and check for authentication failure */ status = srtp_unprotect_rtcp(srtcp_rcvr, hdr, &len); if (status != err_status_auth_fail) { printf("failed\n"); free(hdr); free(hdr2); return status; } else { printf("passed\n"); } } err_check(srtp_dealloc(srtcp_sender)); err_check(srtp_dealloc(srtcp_rcvr)); free(hdr); free(hdr2); return err_status_ok; }
int main (int argc, char *argv[]) { extern char *optarg; int q; int num_octets = 0; unsigned do_list_mods = 0; err_status_t status; if (argc == 1) usage(argv[0]); /* initialize kernel - we need to do this before anything else */ status = crypto_kernel_init(); if (status) { printf("error: crypto_kernel init failed\n"); exit(1); } /* process input arguments */ while (1) { q = getopt(argc, argv, "ld:n:"); if (q == -1) break; switch (q) { case 'd': status = crypto_kernel_set_debug_module(optarg, 1); if (status) { printf("error: set debug module (%s) failed\n", optarg); exit(1); } break; case 'l': do_list_mods = 1; break; case 'n': num_octets = atoi(optarg); if (num_octets < 0 || num_octets > BUF_LEN) usage(argv[0]); break; default: usage(argv[0]); } } if (do_list_mods) { status = crypto_kernel_list_debug_modules(); if (status) { printf("error: list of debug modules failed\n"); exit(1); } } if (num_octets > 0) { uint8_t buffer[BUF_LEN]; status = crypto_get_random(buffer, num_octets); if (status) { printf("error: failure in random source\n"); } else { printf("%s\n", octet_string_hex_string(buffer, num_octets)); } } status = crypto_kernel_shutdown(); if (status) { printf("error: crypto_kernel shutdown failed\n"); exit(1); } return 0; }