defmodule ExLibSRTP.Policy do
@moduledoc """
Policy for setting up SRTP stream configuration.
For meaning of particular fields maps to the fields of `srtp_policy_t` C struct found in libSRTP.
It is described in [srtp.h header](https://github.com/cisco/libsrtp/blob/43dab118f7acbd471edd68ca16e23ed7075dbd38/include/srtp.h#L285)
Here's a brief description:
* `:ssrc` - Either an accepted SSRC or atoms mapping to `SSRC_ANY_(INBOUND/OUTBOUND)` flags
* `:key` - a master key for encrpytion
* `:rtp` - crypto profile defining a policy for RTP encryption
* `:rtcp` - crypto profile defining a policy for RTCP encryption
* `:windows_size` - the sequence number window size used for replay protection
As the comment [here](https://github.com/cisco/libsrtp/blob/43dab118f7acbd471edd68ca16e23ed7075dbd38/srtp/srtp.c#L1270) says,
it must be at least 64 and any value above 2^15 (32768) won't be effective as explained [here](https://github.com/cisco/libsrtp/issues/470).
The default value is 128
* `:allow_repeat_tx` - if true, packet with repeated sequence number won't cause an error.
Note that unless the RTP payload is the same it may introduce a severe security weakness.
"""
# TODO: add EKT, enc_xtn_hdr
alias ExLibSRTP.MasterKey
@type ssrc_pattern_t :: ExLibSRTP.ssrc_t() | :any_inbound | :any_outbound
@type crypto_profile_t ::
:rtp_default
| :rtcp_default
| :aes_cm_128_hmac_sha1_80
| :aes_cm_128_hmac_sha1_32
| :aes_cm_128_null_auth
| :null_cipher_hmac_sha1_80
| :null_cipher_hmac_null
| :aes_cm_256_hmac_sha1_80
| :aes_cm_256_hmac_sha1_32
| :aes_cm_256_null_auth
| :aes_cm_192_hmac_sha1_80
| :aes_cm_192_hmac_sha1_32
| :aes_cm_192_null_auth
| :aes_gcm_128_8_auth
| :aes_gcm_256_8_auth
| :aes_gcm_128_8_only_auth
| :aes_gcm_256_8_only_auth
| :aes_gcm_128_16_auth
| :aes_gcm_256_16_auth
@type key_spec_t :: binary() | [MasterKey.t()]
@type t :: %__MODULE__{
ssrc: ssrc_pattern_t,
key: key_spec_t(),
rtp: crypto_profile_t(),
rtcp: crypto_profile_t(),
window_size: 64..32_768 | :default,
allow_repeat_tx: boolean()
}
@enforce_keys [:ssrc, :key]
defstruct @enforce_keys ++
[
rtp: :rtp_default,
rtcp: :rtcp_default,
window_size: :default,
allow_repeat_tx: false
]
@doc """
Relevant specification: https://www.iana.org/assignments/srtp-protection/srtp-protection.xhtml
"""
@spec crypto_profile_from_dtls_srtp_protection_profile(
value :: pos_integer() | {pos_integer(), pos_integer()}
) :: {:ok, crypto_profile_t()} | {:error, :unsupported_crypto_profile}
def crypto_profile_from_dtls_srtp_protection_profile(0x01), do: {:ok, :aes_cm_128_hmac_sha1_80}
def crypto_profile_from_dtls_srtp_protection_profile(0x02), do: {:ok, :aes_cm_128_hmac_sha1_32}
def crypto_profile_from_dtls_srtp_protection_profile(0x05), do: {:ok, :null_cipher_hmac_sha1_80}
# null_cipher_hmac_sha1_32 is not supported in libsrtp2
def crypto_profile_from_dtls_srtp_protection_profile(0x06),
do: {:error, :unsupported_crypto_profile}
def crypto_profile_from_dtls_srtp_protection_profile(0x07), do: {:ok, :aes_gcm_128_16_auth}
def crypto_profile_from_dtls_srtp_protection_profile(0x08), do: {:ok, :aes_gcm_256_16_auth}
def crypto_profile_from_dtls_srtp_protection_profile(b) when is_number(b) do
{:error, :unsupported_crypto_profile}
end
def crypto_profile_from_dtls_srtp_protection_profile({0x00, b}) when is_number(b) do
crypto_profile_from_dtls_srtp_protection_profile(b)
end
def crypto_profile_from_dtls_srtp_protection_profile({a, b})
when is_number(a) and is_number(b) do
{:error, :unsupported_crypto_profile}
end
end