⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 srtp.c

📁 VLC Player Source Code
💻 C
📖 第 1 页 / 共 2 页
字号:
 * * If RCC rate is 1, RCC mode 1 and 2 are functionally identical. * * @param rate RoC Carry rate (MUST NOT be zero) */void srtp_setrcc_rate (srtp_session_t *s, uint16_t rate){    assert (rate != 0);    s->rtp_rcc = rate;}/** AES-CM for RTP (salt = 14 bytes + 2 nul bytes) */static intrtp_crypt (gcry_cipher_hd_t hd, uint32_t ssrc, uint32_t roc, uint16_t seq,           const uint32_t *salt, uint8_t *data, size_t len){    /* Determines cryptographic counter (IV) */    uint32_t counter[4];    counter[0] = salt[0];    counter[1] = salt[1] ^ ssrc;    counter[2] = salt[2] ^ htonl (roc);    counter[3] = salt[3] ^ htonl (seq << 16);    /* Encryption */    return ctr_crypt (hd, counter, data, len);}/** Determines SRTP Roll-Over-Counter (in host-byte order) */static uint32_tsrtp_compute_roc (const srtp_session_t *s, uint16_t seq){    uint32_t roc = s->rtp_roc;    if (((seq - s->rtp_seq) & 0xffff) < 0x8000)    {        /* Sequence is ahead, good */        if (seq < s->rtp_seq)            roc++; /* Sequence number wrap */    }    else    {        /* Sequence is late, bad */        if (seq > s->rtp_seq)            roc--; /* Wrap back */    }    return roc;}/** Returns RTP sequence (in host-byte order) */static inline uint16_t rtp_seq (const uint8_t *buf){    return (buf[2] << 8) | buf[3];}/** Message Authentication and Integrity for RTP */static const uint8_t *rtp_digest (srtp_session_t *s, const uint8_t *data, size_t len,            uint32_t roc){    const gcry_md_hd_t md = s->rtp.mac;    gcry_md_reset (md);    gcry_md_write (md, data, len);    gcry_md_write (md, &(uint32_t){ htonl (roc) }, 4);    return gcry_md_read (md, 0);}/** * Encrypts/decrypts a RTP packet and updates SRTP context * (CTR block cypher mode of operation has identical encryption and * decryption function). * * @param buf RTP packet to be en-/decrypted * @param len RTP packet length * * @return 0 on success, in case of error: *  EINVAL  malformatted RTP packet *  EACCES  replayed packet or out-of-window or sync lost */static int srtp_crypt (srtp_session_t *s, uint8_t *buf, size_t len){    assert (s != NULL);    if ((len < 12) || ((buf[0] >> 6) != 2))        return EINVAL;    /* Computes encryption offset */    uint16_t offset = 12;    offset += (buf[0] & 0xf) * 4; // skips CSRC    if (buf[0] & 0x10)    {        uint16_t extlen;        offset += 4;        if (len < offset)            return EINVAL;        memcpy (&extlen, buf + offset - 2, 2);        offset += htons (extlen); // skips RTP extension header    }    if (len < offset)        return EINVAL;    /* Determines RTP 48-bits counter and SSRC */    uint16_t seq = rtp_seq (buf);    uint32_t roc = srtp_compute_roc (s, seq), ssrc;    memcpy (&ssrc, buf + 8, 4);    /* Updates ROC and sequence (it's safe now) */    int16_t diff = seq - s->rtp_seq;    if (diff > 0)    {        /* Sequence in the future, good */        s->rtp.window = s->rtp.window << diff;        s->rtp.window |= 1;        s->rtp_seq = seq, s->rtp_roc = roc;    }    else    {        /* Sequence in the past/present, bad */        diff = -diff;        if ((diff >= 64) || ((s->rtp.window >> diff) & 1))            return EACCES; /* Replay attack */        s->rtp.window |= 1 << diff;    }    /* Encrypt/Decrypt */    if (s->flags & SRTP_UNENCRYPTED)        return 0;    if (rtp_crypt (s->rtp.cipher, ssrc, roc, seq, s->rtp.salt,                   buf + offset, len - offset))        return EINVAL;    return 0;}/** * Turns a RTP packet into a SRTP packet: encrypt it, then computes * the authentication tag and appends it. * Note that you can encrypt packet in disorder. * * @param buf RTP packet to be encrypted/digested * @param lenp pointer to the RTP packet length on entry, *             set to the SRTP length on exit (undefined on non-ENOSPC error) * @param bufsize size (bytes) of the packet buffer * * @return 0 on success, in case of error: *  EINVAL  malformatted RTP packet or internal error *  ENOSPC  bufsize is too small to add authentication tag *          (<lenp> will hold the required byte size) *  EACCES  packet would trigger a replay error on receiver */intsrtp_send (srtp_session_t *s, uint8_t *buf, size_t *lenp, size_t bufsize){    size_t len = *lenp;    size_t tag_len = s->tag_len;    if (!(s->flags & SRTP_UNAUTHENTICATED))    {        *lenp = len + tag_len;        if (bufsize < (len + tag_len))            return ENOSPC;    }    int val = srtp_crypt (s, buf, len);    if (val)        return val;    if (!(s->flags & SRTP_UNAUTHENTICATED))    {        uint32_t roc = srtp_compute_roc (s, rtp_seq (buf));        const uint8_t *tag = rtp_digest (s, buf, len, roc);        if (rcc_mode (s))        {            assert (s->rtp_rcc);            if ((rtp_seq (buf) % s->rtp_rcc) == 0)            {                memcpy (buf + len, &(uint32_t){ htonl (s->rtp_roc) }, 4);                len += 4;                if (rcc_mode (s) == 3)                    tag_len = 0;                else                    tag_len -= 4;            }            else            {                if (rcc_mode (s) & 1)                    tag_len = 0;            }        }        memcpy (buf + len, tag, tag_len);    }    return 0;}/** * Turns a SRTP packet into a RTP packet: authenticates the packet, * then decrypts it. * * @param buf RTP packet to be digested/decrypted * @param lenp pointer to the SRTP packet length on entry, *             set to the RTP length on exit (undefined in case of error) * * @return 0 on success, in case of error: *  EINVAL  malformatted SRTP packet *  EACCES  authentication failed (spoofed packet or out-of-sync) */intsrtp_recv (srtp_session_t *s, uint8_t *buf, size_t *lenp){    size_t len = *lenp;    if (len < 12u)        return EINVAL;    if (!(s->flags & SRTP_UNAUTHENTICATED))    {        size_t tag_len = s->tag_len, roc_len = 0;        if (rcc_mode (s))        {            if ((rtp_seq (buf) % s->rtp_rcc) == 0)            {                roc_len = 4;                if (rcc_mode (s) == 3)                    tag_len = 0;                else                    tag_len -= 4;            }            else            {                if (rcc_mode (s) & 1)                    tag_len = 0; // RCC mode 1 or 3: no auth            }        }        if (len < (12u + roc_len + tag_len))            return EINVAL;        len -= roc_len + tag_len;        uint32_t roc = srtp_compute_roc (s, rtp_seq (buf)), rcc;        if (roc_len)        {            assert (roc_len == 4);            memcpy (&rcc, buf + len, 4);            rcc = ntohl (rcc);        }        else            rcc = roc;        const uint8_t *tag = rtp_digest (s, buf, len, rcc);#if 0        printf ("Computed: 0x");        for (unsigned i = 0; i < tag_len; i++)            printf ("%02x", tag[i]);        printf ("\nReceived: 0x");        for (unsigned i = 0; i < tag_len; i++)            printf ("%02x", buf[len + roc_len + i]);        puts ("");#endif        if (memcmp (buf + len + roc_len, tag, tag_len))            return EACCES;        if (roc_len)        {            /* Authenticated packet carried a Roll-Over-Counter */            s->rtp_roc += rcc - roc;            assert (srtp_compute_roc (s, rtp_seq (buf)) == rcc);        }        *lenp = len;    }    return srtp_crypt (s, buf, len);}/** AES-CM for RTCP (salt = 14 bytes + 2 nul bytes) */static intrtcp_crypt (gcry_cipher_hd_t hd, uint32_t ssrc, uint32_t index,            const uint32_t *salt, uint8_t *data, size_t len){    return rtp_crypt (hd, ssrc, index >> 16, index & 0xffff, salt, data, len);}/** Message Authentication and Integrity for RTCP */static const uint8_t *rtcp_digest (gcry_md_hd_t md, const void *data, size_t len){    gcry_md_reset (md);    gcry_md_write (md, data, len);    return gcry_md_read (md, 0);}/** * Encrypts/decrypts a RTCP packet and updates SRTCP context * (CTR block cypher mode of operation has identical encryption and * decryption function). * * @param buf RTCP packet to be en-/decrypted * @param len RTCP packet length * * @return 0 on success, in case of error: *  EINVAL  malformatted RTCP packet */static int srtcp_crypt (srtp_session_t *s, uint8_t *buf, size_t len){    assert (s != NULL);    /* 8-bytes unencrypted header, and 4-bytes unencrypted footer */    if ((len < 12) || ((buf[0] >> 6) != 2))        return EINVAL;    uint32_t index;    memcpy (&index, buf + len, 4);    index = ntohl (index);    if (((index >> 31) != 0) != ((s->flags & SRTCP_UNENCRYPTED) == 0))        return EINVAL; // E-bit mismatch    index &= ~(1 << 31); // clear E-bit for counter    /* Updates SRTCP index (safe here) */    int32_t diff = index - s->rtcp_index;    if (diff > 0)    {        /* Packet in the future, good */        s->rtcp.window = s->rtcp.window << diff;        s->rtcp.window |= 1;        s->rtcp_index = index;    }    else    {        /* Packet in the past/present, bad */        diff = -diff;        if ((diff >= 64) || ((s->rtcp.window >> diff) & 1))            return EACCES; // replay attack!        s->rtp.window |= 1 << diff;    }    /* Crypts SRTCP */    if (s->flags & SRTCP_UNENCRYPTED)        return 0;    uint32_t ssrc;    memcpy (&ssrc, buf + 4, 4);    if (rtcp_crypt (s->rtcp.cipher, ssrc, index, s->rtp.salt,                    buf + 8, len - 8))        return EINVAL;    return 0;}/** * Turns a RTCP packet into a SRTCP packet: encrypt it, then computes * the authentication tag and appends it. * * @param buf RTCP packet to be encrypted/digested * @param lenp pointer to the RTCP packet length on entry, *             set to the SRTCP length on exit (undefined in case of error) * @param bufsize size (bytes) of the packet buffer * * @return 0 on success, in case of error: *  EINVAL  malformatted RTCP packet or internal error *  ENOSPC  bufsize is too small (to add index and authentication tag) */intsrtcp_send (srtp_session_t *s, uint8_t *buf, size_t *lenp, size_t bufsize){    size_t len = *lenp;    if (bufsize < (len + 4 + s->tag_len))        return ENOSPC;    uint32_t index = ++s->rtcp_index;    if (index >> 31)        s->rtcp_index = index = 0; /* 31-bit wrap */    if ((s->flags & SRTCP_UNENCRYPTED) == 0)        index |= 0x80000000; /* Set Encrypted bit */    memcpy (buf + len, &(uint32_t){ htonl (index) }, 4);    int val = srtcp_crypt (s, buf, len);    if (val)        return val;    len += 4; /* Digests SRTCP index too */    const uint8_t *tag = rtcp_digest (s->rtp.mac, buf, len);    memcpy (buf + len, tag, s->tag_len);    *lenp = len + s->tag_len;    return 0;}/** * Turns a SRTCP packet into a RTCP packet: authenticates the packet, * then decrypts it. * * @param buf RTCP packet to be digested/decrypted * @param lenp pointer to the SRTCP packet length on entry, *             set to the RTCP length on exit (undefined in case of error) * * @return 0 on success, in case of error: *  EINVAL  malformatted SRTCP packet *  EACCES  authentication failed (spoofed packet or out-of-sync) */intsrtcp_recv (srtp_session_t *s, uint8_t *buf, size_t *lenp){    size_t len = *lenp;    if (len < (4u + s->tag_len))        return EINVAL;    len -= s->tag_len;    const uint8_t *tag = rtcp_digest (s->rtp.mac, buf, len);    if (memcmp (buf + len, tag, s->tag_len))         return EACCES;    len -= 4; /* Remove SRTCP index before decryption */    *lenp = len;    return srtp_crypt (s, buf, len);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -