2020-02-13 06:36:23 +00:00
|
|
|
#ifdef __RTP_CRYPTO__
|
2020-01-22 08:58:50 +00:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
#include <winsock2.h>
|
|
|
|
|
#include <mswsock.h>
|
|
|
|
|
#include <inaddr.h>
|
|
|
|
|
#else
|
|
|
|
|
#include <netinet/ip.h>
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-07-23 10:05:55 +00:00
|
|
|
#include <mutex>
|
2020-01-22 08:58:50 +00:00
|
|
|
#include <vector>
|
|
|
|
|
|
2020-02-13 06:36:23 +00:00
|
|
|
#include "crypto.hh"
|
2020-01-29 10:10:53 +00:00
|
|
|
#include "mzrtp/defines.hh"
|
2020-01-24 06:38:11 +00:00
|
|
|
#include "mzrtp/receiver.hh"
|
2020-01-22 08:58:50 +00:00
|
|
|
|
2020-04-27 11:07:24 +00:00
|
|
|
namespace uvg_rtp {
|
2020-01-22 08:58:50 +00:00
|
|
|
|
2020-01-31 05:25:04 +00:00
|
|
|
enum ROLE {
|
|
|
|
|
INITIATOR,
|
|
|
|
|
RESPONDER
|
|
|
|
|
};
|
|
|
|
|
|
2020-01-22 08:58:50 +00:00
|
|
|
typedef struct capabilities {
|
|
|
|
|
/* Supported ZRTP version */
|
|
|
|
|
uint32_t version;
|
|
|
|
|
|
|
|
|
|
/* Supported hash algorithms (empty for us) */
|
|
|
|
|
std::vector<uint32_t> hash_algos;
|
|
|
|
|
|
|
|
|
|
/* Supported cipher algorithms (empty for us) */
|
|
|
|
|
std::vector<uint32_t> cipher_algos;
|
|
|
|
|
|
|
|
|
|
/* Supported authentication tag types (empty for us) */
|
|
|
|
|
std::vector<uint32_t> auth_tags;
|
|
|
|
|
|
|
|
|
|
/* Supported Key Agreement types (empty for us) */
|
|
|
|
|
std::vector<uint32_t> key_agreements;
|
|
|
|
|
|
|
|
|
|
/* Supported SAS types (empty for us) */
|
|
|
|
|
std::vector<uint32_t> sas_types;
|
|
|
|
|
} zrtp_capab_t;
|
|
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
typedef struct zrtp_crypto_ctx {
|
2020-04-27 11:07:24 +00:00
|
|
|
uvg_rtp::crypto::hmac::sha256 *hmac_sha256;
|
|
|
|
|
uvg_rtp::crypto::sha256 *sha256;
|
|
|
|
|
uvg_rtp::crypto::dh *dh;
|
2020-02-02 07:05:25 +00:00
|
|
|
} zrtp_crypto_ctx_t;
|
2020-01-29 09:19:46 +00:00
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
typedef struct zrtp_secrets {
|
2020-04-27 11:07:24 +00:00
|
|
|
/* Retained (for uvgRTP, preshared mode is not supported so we're
|
2020-01-29 09:19:46 +00:00
|
|
|
* going to generate just some random values for these) */
|
|
|
|
|
uint8_t rs1[32];
|
|
|
|
|
uint8_t rs2[32];
|
|
|
|
|
uint8_t raux[32];
|
|
|
|
|
uint8_t rpbx[32];
|
|
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
/* Shared secrets
|
|
|
|
|
*
|
2020-04-27 11:07:24 +00:00
|
|
|
* Because uvgRTP supports only DH mode,
|
2020-02-02 07:05:25 +00:00
|
|
|
* other shared secrets (s1 - s3) are null */
|
|
|
|
|
uint8_t s0[32];
|
|
|
|
|
uint8_t *s1;
|
|
|
|
|
uint8_t *s2;
|
|
|
|
|
uint8_t *s3;
|
|
|
|
|
} zrtp_secrets_t;
|
2020-01-28 07:47:04 +00:00
|
|
|
|
2020-01-29 10:10:53 +00:00
|
|
|
typedef struct zrtp_messages {
|
2020-04-27 11:07:24 +00:00
|
|
|
std::pair<size_t, struct uvg_rtp::zrtp_msg::zrtp_commit *> commit;
|
|
|
|
|
std::pair<size_t, struct uvg_rtp::zrtp_msg::zrtp_hello *> hello;
|
|
|
|
|
std::pair<size_t, struct uvg_rtp::zrtp_msg::zrtp_dh *> dh;
|
2020-01-29 10:10:53 +00:00
|
|
|
} zrtp_messages_t;
|
|
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
/* Various ZRTP-related keys */
|
|
|
|
|
typedef struct zrtp_key_ctx {
|
|
|
|
|
uint8_t zrtp_sess_key[32];
|
|
|
|
|
uint8_t sas_hash[32];
|
2020-01-28 07:47:04 +00:00
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
/* ZRTP keys used to encrypt Confirm1/Confirm2 messages */
|
|
|
|
|
uint8_t zrtp_keyi[16];
|
|
|
|
|
uint8_t zrtp_keyr[16];
|
2020-01-24 08:13:43 +00:00
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
/* HMAC keys used to authenticate Confirm1/Confirm2 messages */
|
|
|
|
|
uint8_t hmac_keyi[32];
|
|
|
|
|
uint8_t hmac_keyr[32];
|
|
|
|
|
} zrtp_key_ctx_t;
|
2020-01-28 07:47:04 +00:00
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
/* Diffie-Hellman context for the ZRTP session */
|
|
|
|
|
typedef struct zrtp_dh_ctx {
|
|
|
|
|
/* Our public/private key pair */
|
2020-01-29 09:19:46 +00:00
|
|
|
uint8_t private_key[22];
|
|
|
|
|
uint8_t public_key[384];
|
|
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
/* Remote public key received in DHPart1/DHPart2 Message */
|
2020-01-29 09:19:46 +00:00
|
|
|
uint8_t remote_public[384];
|
|
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
/* DHResult aka "remote_public ^ private_key mod p" (see src/crypto/crypto.cc) */
|
2020-01-29 09:19:46 +00:00
|
|
|
uint8_t dh_result[384];
|
2020-02-02 07:05:25 +00:00
|
|
|
} zrtp_dh_ctx_t;
|
2020-01-29 09:19:46 +00:00
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
typedef struct zrtp_hash_ctx {
|
|
|
|
|
uint8_t o_hvi[32]; /* our hash value of initator (if we're the initiator) */
|
|
|
|
|
uint8_t r_hvi[32]; /* remote's hash value of initiator (if they're the initiator) */
|
2020-01-28 08:53:29 +00:00
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
/* Session hashes (H0 - H3), Section 9 of RFC 6189 */
|
|
|
|
|
uint8_t o_hash[4][32]; /* our session hashes */
|
|
|
|
|
uint8_t r_hash[4][32]; /* remote's session hashes */
|
2020-01-28 07:47:04 +00:00
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
uint64_t r_mac[4];
|
2020-01-28 06:34:56 +00:00
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
/* Section 4.4.1.4 */
|
2020-01-31 05:25:04 +00:00
|
|
|
uint8_t total_hash[32];
|
2020-02-02 07:05:25 +00:00
|
|
|
} zrtp_hash_ctx_t;
|
2020-01-31 05:25:04 +00:00
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
/* Collection of algorithms that are used by ZRTP
|
|
|
|
|
* (based on information gathered from Hello message) */
|
|
|
|
|
typedef struct zrtp_session {
|
|
|
|
|
int role; /* initiator/responder */
|
|
|
|
|
uint32_t ssrc;
|
|
|
|
|
uint16_t seq;
|
|
|
|
|
|
|
|
|
|
uint32_t hash_algo;
|
|
|
|
|
uint32_t cipher_algo;
|
|
|
|
|
uint32_t auth_tag_type;
|
|
|
|
|
uint32_t key_agreement_type;
|
|
|
|
|
uint32_t sas_type;
|
2020-01-31 05:25:04 +00:00
|
|
|
|
2020-02-02 07:16:56 +00:00
|
|
|
/* Session capabilities */
|
|
|
|
|
zrtp_capab_t capabilities;
|
2020-01-29 09:19:46 +00:00
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
/* Various hash values of the ZRTP session */
|
|
|
|
|
zrtp_hash_ctx_t hash_ctx;
|
2020-01-29 09:19:46 +00:00
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
/* DH-related variables */
|
|
|
|
|
zrtp_dh_ctx_t dh_ctx;
|
2020-01-22 08:58:50 +00:00
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
/* ZRTP keying material (for HMAC/AES etc) */
|
|
|
|
|
zrtp_key_ctx_t key_ctx;
|
2020-01-31 05:25:04 +00:00
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
/* Retained and shared secrets of the ZRTP session */
|
|
|
|
|
zrtp_secrets_t secrets;
|
2020-01-31 05:25:04 +00:00
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
uint8_t o_zid[12]; /* our ZID */
|
|
|
|
|
uint8_t r_zid[12]; /* remote ZID */
|
2020-01-29 10:10:53 +00:00
|
|
|
|
|
|
|
|
/* Pointers to messages sent by us and messages received from remote.
|
2020-02-02 07:05:25 +00:00
|
|
|
* These are used to calculate various hash values */
|
2020-01-29 10:10:53 +00:00
|
|
|
zrtp_messages_t l_msg;
|
|
|
|
|
zrtp_messages_t r_msg;
|
2020-01-28 07:47:04 +00:00
|
|
|
} zrtp_session_t;
|
2020-01-28 06:34:56 +00:00
|
|
|
|
2020-01-22 08:58:50 +00:00
|
|
|
class zrtp {
|
|
|
|
|
public:
|
|
|
|
|
zrtp();
|
|
|
|
|
~zrtp();
|
|
|
|
|
|
2020-02-10 08:21:59 +00:00
|
|
|
/* Initialize ZRTP for a multimedia session
|
|
|
|
|
*
|
|
|
|
|
* If this the first ZRTP session initialization for this object,
|
|
|
|
|
* ZRTP will perform DHMode initialization, otherwise Multistream Mode
|
|
|
|
|
* initialization is performed.
|
2020-01-24 06:38:11 +00:00
|
|
|
*
|
|
|
|
|
* Return RTP_OK on success
|
|
|
|
|
* Return RTP_TIMEOUT if remote did not send messages in timely manner */
|
2020-01-22 08:58:50 +00:00
|
|
|
rtp_error_t init(uint32_t ssrc, socket_t& socket, sockaddr_in& addr);
|
|
|
|
|
|
2020-02-25 07:48:02 +00:00
|
|
|
/* Get SRTP keys for the session that was just initialized
|
|
|
|
|
*
|
|
|
|
|
* NOTE: "key_len" and "salt_len" denote the lengths in **bits**
|
|
|
|
|
*
|
|
|
|
|
* TODO are there any requirements (thinking of Multistream Mode and keys getting overwritten?)
|
|
|
|
|
*
|
|
|
|
|
* Return RTP_OK on success
|
|
|
|
|
* Return RTP_NOT_INITIALIZED if init() has not been called yet
|
|
|
|
|
* Return RTP_INVALID_VALUE if one of the parameters is invalid */
|
|
|
|
|
rtp_error_t get_srtp_keys(
|
|
|
|
|
uint8_t *our_mkey, size_t okey_len,
|
|
|
|
|
uint8_t *their_mkey, size_t tkey_len,
|
|
|
|
|
uint8_t *our_msalt, size_t osalt_len,
|
|
|
|
|
uint8_t *their_msalt, size_t tsalt_len
|
|
|
|
|
);
|
|
|
|
|
|
2020-01-22 08:58:50 +00:00
|
|
|
private:
|
2020-02-10 08:21:59 +00:00
|
|
|
/* Initialize ZRTP session between us and remote using Diffie-Hellman Mode
|
|
|
|
|
*
|
|
|
|
|
* Return RTP_OK on success
|
|
|
|
|
* Return RTP_TIMEOUT if remote did not send messages in timely manner */
|
|
|
|
|
rtp_error_t init_dhm(uint32_t ssrc, socket_t& socket, sockaddr_in& addr);
|
|
|
|
|
|
|
|
|
|
/* Initialize ZRTP session between us and remote using Multistream mode
|
|
|
|
|
*
|
|
|
|
|
* Return RTP_OK on success
|
|
|
|
|
* Return RTP_TIMEOUT if remote did not send messages in timely manner */
|
|
|
|
|
rtp_error_t init_msm(uint32_t ssrc, socket_t& socket, sockaddr_in& addr);
|
|
|
|
|
|
2020-01-22 08:58:50 +00:00
|
|
|
/* Set timeout for a socket, needed by backoff timers of ZRTP
|
|
|
|
|
*
|
|
|
|
|
* "timeout" tells the timeout in milliseconds
|
|
|
|
|
*
|
|
|
|
|
* Return RTP_OK on success
|
|
|
|
|
* Return RTP_GENERIC_ERROR if timeout could not be set */
|
|
|
|
|
rtp_error_t set_timeout(size_t timeout);
|
|
|
|
|
|
|
|
|
|
/* Generate zid for this ZRTP instance. ZID is a unique, 96-bit long ID */
|
2020-01-28 06:34:56 +00:00
|
|
|
void generate_zid();
|
|
|
|
|
|
2020-01-31 05:25:04 +00:00
|
|
|
/* Create private/public key pair and generate random values for retained secrets */
|
2020-01-29 09:19:46 +00:00
|
|
|
void generate_secrets();
|
|
|
|
|
|
2020-01-31 05:25:04 +00:00
|
|
|
/* Calculate DHResult, total_hash, and s0 according to rules defined in RFC 6189 */
|
|
|
|
|
void generate_shared_secrets();
|
|
|
|
|
|
2020-01-28 08:53:29 +00:00
|
|
|
/* Compare our and remote's hvi values to determine who is the initiator */
|
|
|
|
|
bool are_we_initiator(uint8_t *our_hvi, uint8_t *their_hvi);
|
|
|
|
|
|
2020-01-28 06:34:56 +00:00
|
|
|
/* Initialize the four session hashes defined in Section 9 of RFC 6189 */
|
|
|
|
|
void init_session_hashes();
|
2020-01-22 08:58:50 +00:00
|
|
|
|
2020-01-31 05:25:04 +00:00
|
|
|
/* Derive new key using s0 as HMAC key */
|
|
|
|
|
void derive_key(const char *label, uint32_t key_len, uint8_t *key);
|
|
|
|
|
|
2020-01-22 08:58:50 +00:00
|
|
|
/* Being the ZRTP session by sending a Hello message to remote,
|
2020-01-24 06:38:11 +00:00
|
|
|
* and responding to remote's Hello message using HelloAck message
|
2020-01-22 08:58:50 +00:00
|
|
|
*
|
|
|
|
|
* If session begins successfully, remote zrtp_capab_t are put into
|
|
|
|
|
* "remote_capab" for later use
|
|
|
|
|
*
|
2020-01-24 06:38:11 +00:00
|
|
|
* Return RTP_OK on success
|
2020-01-22 08:58:50 +00:00
|
|
|
* Return RTP_NOT_SUPPORTED if remote did not answer to our Hello messages */
|
|
|
|
|
rtp_error_t begin_session();
|
|
|
|
|
|
2020-01-24 06:38:11 +00:00
|
|
|
/* Select algorithms used by the session, exchange this information with remote
|
|
|
|
|
* and based on Commit messages, select roles for the participants (initiator/responder)
|
|
|
|
|
*
|
|
|
|
|
* Return RTP_OK on success
|
|
|
|
|
* Return RTP_TIMEOUT if no message is received from remote before T2 expires */
|
2020-06-26 05:18:55 +00:00
|
|
|
rtp_error_t init_session(int key_agreement);
|
2020-01-24 06:38:11 +00:00
|
|
|
|
2020-02-01 05:56:39 +00:00
|
|
|
/* Calculate HMAC-SHA256 using "key" for "buf" of "len" bytes
|
|
|
|
|
* and compare the truncated, 64-bit hash digest against "mac".
|
|
|
|
|
*
|
|
|
|
|
* Return RTP_OK if they match
|
|
|
|
|
* Return RTP_INVALID if they do not match */
|
|
|
|
|
rtp_error_t verify_hash(uint8_t *key, uint8_t *buf, size_t len, uint64_t mac);
|
|
|
|
|
|
|
|
|
|
/* Validate all received MACs and Hashes to make sure that we're really
|
|
|
|
|
* talking with the correct person */
|
|
|
|
|
rtp_error_t validate_session();
|
|
|
|
|
|
2020-01-24 08:13:43 +00:00
|
|
|
/* Perform Diffie-Hellman key exchange Part1 (responder)
|
|
|
|
|
* This message also acts as an ACK to Commit message */
|
|
|
|
|
rtp_error_t dh_part1();
|
|
|
|
|
|
|
|
|
|
/* Perform Diffie-Hellman key exchange Part2 (initiator)
|
|
|
|
|
* This message also acts as an ACK to DHPart1 message
|
|
|
|
|
*
|
|
|
|
|
* Return RTP_OK if DHPart2 was successful
|
|
|
|
|
* Return RTP_TIMEOUT if no message is received from remote before T2 expires */
|
|
|
|
|
rtp_error_t dh_part2();
|
|
|
|
|
|
2020-02-01 05:56:39 +00:00
|
|
|
/* Calculate all the shared secrets (f.ex. DHResult and ZRTP Session Keys) */
|
2020-01-29 10:10:53 +00:00
|
|
|
rtp_error_t calculate_shared_secret();
|
|
|
|
|
|
2020-02-01 05:56:39 +00:00
|
|
|
/* Finalize the session for responder by sending Confirm1 and Conf2ACK messages
|
|
|
|
|
* Before this step validate_session() is called to make sure we have a valid session */
|
2020-01-24 08:49:44 +00:00
|
|
|
rtp_error_t responder_finalize_session();
|
|
|
|
|
|
2020-02-01 05:56:39 +00:00
|
|
|
/* Finalize the session for initiator by sending Confirm2 message
|
|
|
|
|
* Before this step validate_session() is called to make sure we have a valid session */
|
2020-01-24 08:49:44 +00:00
|
|
|
rtp_error_t initiator_finalize_session();
|
|
|
|
|
|
2020-01-22 08:58:50 +00:00
|
|
|
uint32_t ssrc_;
|
|
|
|
|
socket_t socket_;
|
|
|
|
|
sockaddr_in addr_;
|
|
|
|
|
|
2020-02-10 08:21:59 +00:00
|
|
|
/* Has the ZRTP connection been initialized using DH */
|
|
|
|
|
bool initialized_;
|
|
|
|
|
|
2020-01-22 08:58:50 +00:00
|
|
|
/* Our own and remote capability structs */
|
|
|
|
|
zrtp_capab_t capab_;
|
|
|
|
|
zrtp_capab_t rcapab_;
|
|
|
|
|
|
2020-02-02 07:05:25 +00:00
|
|
|
/* ZRTP packet receiver */
|
2020-04-27 11:07:24 +00:00
|
|
|
uvg_rtp::zrtp_msg::receiver receiver_;
|
2020-01-24 06:38:11 +00:00
|
|
|
|
2020-01-28 07:47:04 +00:00
|
|
|
zrtp_crypto_ctx_t cctx_;
|
2020-01-24 06:38:11 +00:00
|
|
|
zrtp_session_t session_;
|
2020-07-23 10:05:55 +00:00
|
|
|
|
|
|
|
|
std::mutex zrtp_mtx_;
|
2020-01-22 08:58:50 +00:00
|
|
|
};
|
|
|
|
|
};
|
2020-02-13 06:36:23 +00:00
|
|
|
#endif
|