srtp_stream_init_keys(srtp_stream_ctx_t *srtp, const void *key) {
  err_status_t stat;
  srtp_kdf_t kdf;
  uint8_t tmp_key[MAX_SRTP_KEY_LEN];
  int kdf_keylen = 30, rtp_keylen, rtcp_keylen;
  int rtp_base_key_len, rtp_salt_len;
  int rtcp_base_key_len, rtcp_salt_len;

  /* If RTP or RTCP have a key length > AES-128, assume matching kdf. */
  /* TODO: kdf algorithm, master key length, and master salt length should
   * be part of srtp_policy_t. */
  rtp_keylen = cipher_get_key_length(srtp->rtp_cipher);
  rtcp_keylen = cipher_get_key_length(srtp->rtcp_cipher);
  rtp_base_key_len = base_key_length(srtp->rtp_cipher->type, rtp_keylen);
  rtp_salt_len = rtp_keylen - rtp_base_key_len;

  if (rtp_keylen > kdf_keylen) {
    kdf_keylen = 46;  /* AES-CTR mode is always used for KDF */
  }

  if (rtcp_keylen > kdf_keylen) {
    kdf_keylen = 46;  /* AES-CTR mode is always used for KDF */
  }

  debug_print(mod_srtp, "srtp key len: %d", rtp_keylen);
  debug_print(mod_srtp, "srtcp key len: %d", rtcp_keylen);
  debug_print(mod_srtp, "base key len: %d", rtp_base_key_len);
  debug_print(mod_srtp, "kdf key len: %d", kdf_keylen);
  debug_print(mod_srtp, "rtp salt len: %d", rtp_salt_len);

  /* 
   * Make sure the key given to us is 'zero' appended.  GCM
   * mode uses a shorter master SALT (96 bits), but still relies on 
   * the legacy CTR mode KDF, which uses a 112 bit master SALT.
   */
  memset(tmp_key, 0x0, MAX_SRTP_KEY_LEN);
  memcpy(tmp_key, key, (rtp_base_key_len + rtp_salt_len));

  /* initialize KDF state     */
  stat = srtp_kdf_init(&kdf, AES_ICM, (const uint8_t *)tmp_key, kdf_keylen);
  if (stat) {
    return err_status_init_fail;
  }
  
  /* generate encryption key  */
  stat = srtp_kdf_generate(&kdf, label_rtp_encryption, 
			   tmp_key, rtp_base_key_len);
  if (stat) {
    /* zeroize temp buffer */
    octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
    return err_status_init_fail;
  }
  debug_print(mod_srtp, "cipher key: %s", 
	      octet_string_hex_string(tmp_key, rtp_base_key_len));

  /* 
   * if the cipher in the srtp context uses a salt, then we need
   * to generate the salt value
   */
  if (rtp_salt_len > 0) {
    debug_print(mod_srtp, "found rtp_salt_len > 0, generating salt", NULL);

    /* generate encryption salt, put after encryption key */
    stat = srtp_kdf_generate(&kdf, label_rtp_salt, 
			     tmp_key + rtp_base_key_len, rtp_salt_len);
    if (stat) {
      /* zeroize temp buffer */
      octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
      return err_status_init_fail;
    }
    memcpy(srtp->salt, tmp_key + rtp_base_key_len, SRTP_AEAD_SALT_LEN);
  }
  if (rtp_salt_len > 0) {
    debug_print(mod_srtp, "cipher salt: %s",
		octet_string_hex_string(tmp_key + rtp_base_key_len, rtp_salt_len));
  }

  /* initialize cipher */
  stat = cipher_init(srtp->rtp_cipher, tmp_key);
  if (stat) {
    /* zeroize temp buffer */
    octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
    return err_status_init_fail;
  }

  /* generate authentication key */
  stat = srtp_kdf_generate(&kdf, label_rtp_msg_auth,
			   tmp_key, auth_get_key_length(srtp->rtp_auth));
  if (stat) {
    /* zeroize temp buffer */
    octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
    return err_status_init_fail;
  }
  debug_print(mod_srtp, "auth key:   %s",
	      octet_string_hex_string(tmp_key, 
				      auth_get_key_length(srtp->rtp_auth))); 

  /* initialize auth function */
  stat = auth_init(srtp->rtp_auth, tmp_key);
  if (stat) {
    /* zeroize temp buffer */
    octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
    return err_status_init_fail;
  }

  /*
   * ...now initialize SRTCP keys
   */

  rtcp_base_key_len = base_key_length(srtp->rtcp_cipher->type, rtcp_keylen);
  rtcp_salt_len = rtcp_keylen - rtcp_base_key_len;
  debug_print(mod_srtp, "rtcp salt len: %d", rtcp_salt_len);
  
  /* generate encryption key  */
  stat = srtp_kdf_generate(&kdf, label_rtcp_encryption, 
			   tmp_key, rtcp_base_key_len);
  if (stat) {
    /* zeroize temp buffer */
    octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
    return err_status_init_fail;
  }

  /* 
   * if the cipher in the srtp context uses a salt, then we need
   * to generate the salt value
   */
  if (rtcp_salt_len > 0) {
    debug_print(mod_srtp, "found rtcp_salt_len > 0, generating rtcp salt",
		NULL);

    /* generate encryption salt, put after encryption key */
    stat = srtp_kdf_generate(&kdf, label_rtcp_salt, 
			     tmp_key + rtcp_base_key_len, rtcp_salt_len);
    if (stat) {
      /* zeroize temp buffer */
      octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
      return err_status_init_fail;
    }
    memcpy(srtp->c_salt, tmp_key + rtcp_base_key_len, SRTP_AEAD_SALT_LEN);
  }
  debug_print(mod_srtp, "rtcp cipher key: %s", 
	      octet_string_hex_string(tmp_key, rtcp_base_key_len));  
  if (rtcp_salt_len > 0) {
    debug_print(mod_srtp, "rtcp cipher salt: %s",
		octet_string_hex_string(tmp_key + rtcp_base_key_len, rtcp_salt_len));
  }

  /* initialize cipher */
  stat = cipher_init(srtp->rtcp_cipher, tmp_key);
  if (stat) {
    /* zeroize temp buffer */
    octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
    return err_status_init_fail;
  }

  /* generate authentication key */
  stat = srtp_kdf_generate(&kdf, label_rtcp_msg_auth,
			   tmp_key, auth_get_key_length(srtp->rtcp_auth));
  if (stat) {
    /* zeroize temp buffer */
    octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
    return err_status_init_fail;
  }

  debug_print(mod_srtp, "rtcp auth key:   %s",
	      octet_string_hex_string(tmp_key, 
		     auth_get_key_length(srtp->rtcp_auth))); 

  /* initialize auth function */
  stat = auth_init(srtp->rtcp_auth, tmp_key);
  if (stat) {
    /* zeroize temp buffer */
    octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
    return err_status_init_fail;
  }

  /* clear memory then return */
  stat = srtp_kdf_clear(&kdf);
  octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);  
  if (stat)
    return err_status_init_fail;

  return err_status_ok;
}