Ejemplo n.º 1
0
        /// <summary>
        /// SRTP implementations use an "implicit" packet index for sequencing,
        /// i.e., not all of the index is explicitly carried in the SRTP packet.
        /// For the pre-defined transforms, the index i is used in replay
        /// protection (Section 3.3.2), encryption (Section 4.1), message
        /// authentication (Section 4.2), and for the key derivation (Section
        /// 4.3).
        ///
        /// https://tools.ietf.org/html/rfc3711#section-3.3.1
        /// </summary>
        private static int DetermineSrtpPacketIndex(RtpPacket rtp, SrtpStreamContext srtpStreamContext)
        {
            if (rtp.SequenceNumber - srtpStreamContext.PreviousSequenceNumber < ushort.MinValue)
            {
                srtpStreamContext.RollOverCounter++;
            }

            srtpStreamContext.PreviousSequenceNumber = rtp.SequenceNumber;

            var packetIndex = srtpStreamContext.RollOverCounter << 16 | rtp.SequenceNumber;

            return(packetIndex);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Recall that an RTP session for each participant is defined [RFC3550]
        /// by a pair of destination transport addresses (one network address
        /// plus a port pair for RTP and RTCP), and that a multimedia session is
        /// defined as a collection of RTP sessions.  For example, a particular
        /// multimedia session could include an audio RTP session, a video RTP
        /// session, and a text RTP session.
        ///
        /// A cryptographic context SHALL be uniquely identified by the triplet
        /// context identifier:
        ///
        /// context id = &lt;SSRC, destination network address, destination
        /// transport port number&gt;
        ///
        /// where the destination network address and the destination transport
        /// port are the ones in the SRTP packet.  It is assumed that, when
        /// presented with this information, the key management returns a context
        /// with the information as described in Section 3.2.
        ///
        /// As noted above, SRTP and SRTCP by default share the bulk of the
        /// parameters in the cryptographic context.  Thus, retrieving the crypto
        /// context parameters for an SRTCP stream in practice may imply a
        /// binding to the correspondent SRTP crypto context.  It is up to the
        /// implementation to assure such binding, since the RTCP port may not be
        /// directly deducible from the RTP port only.  Alternatively, the key
        /// management may choose to provide separate SRTP- and SRTCP- contexts,
        /// duplicating the common parameters (such as master key(s)).  The
        /// latter approach then also enables SRTP and SRTCP to use, e.g.,
        /// distinct transforms, if so desired.  Similar considerations arise
        /// when multiple SRTP streams, forming part of one single RTP session,
        /// share keys and other parameters.
        ///
        /// If no valid context can be found for a packet corresponding to a
        /// certain context identifier, that packet MUST be discarded.
        ///
        /// https://tools.ietf.org/html/rfc3711#section-3.2.3
        /// </summary>
        private SrtpStreamContext DetermineCryptoStreamContext(RtpPacket rtp, IPEndPoint remoteEndPoint)
        {
            var key = new SrtpStreamContextKey(rtp.SynchronizationSource, remoteEndPoint);

            if (_streams.TryGetValue(key, out var srtpStream))
            {
                return(srtpStream);
            }

            srtpStream = new SrtpStreamContext
            {
                SynchronizationSource = rtp.SynchronizationSource
            };
            _streams.AddOrUpdate(key, k => srtpStream, (k, v) => srtpStream);

            return(srtpStream);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Regardless of the encryption or message authentication transform that
        /// is employed (it may be an SRTP pre-defined transform or newly
        /// introduced according to Section 6), interoperable SRTP
        /// implementations MUST use the SRTP key derivation to generate session
        /// keys.  Once the key derivation rate is properly signaled at the start
        /// of the session, there is no need for extra communication between the
        /// parties that use SRTP key derivation.
        ///
        /// https://tools.ietf.org/html/rfc3711#section-4.3
        /// </summary>
        private void DeriveKeys(SrtpStreamContext srtpStreamContext, int packetIndex, byte[] masterKey, byte[] masterSalt)
        {
            /*
             * At least one initial key derivation SHALL be performed by SRTP, i.e.,
             * the first key derivation is REQUIRED.  Further applications of the
             * key derivation MAY be performed, according to the
             * "key_derivation_rate" value in the cryptographic context.  The key
             * derivation function SHALL initially be invoked before the first
             * packet and then, when r > 0, a key derivation is performed whenever
             * index mod r equals zero.  This can be thought of as "refreshing" the
             * session keys.  The value of "key_derivation_rate" MUST be kept fixed
             * for the lifetime of the associated master key.
             */
            /*
             * Let "a DIV t" denote integer division of a by t, rounded down, and
             * with the convention that "a DIV 0 = 0" for all a.  We also make the
             * convention of treating "a DIV t" as a bit string of the same length
             * as a, and thus "a DIV t" will in general have leading zeros.
             *
             * Let r = index DIV key_derivation_rate (with DIV as defined above).
             */

            var kdr = srtpStreamContext.KeyDerivationRate;

            var r = (uint)(kdr == 0 ? 0 : packetIndex / kdr);

            var shouldDeriveKeys = srtpStreamContext.DerivedKeys is null || r > 0 && packetIndex % r == 0;

            if (!shouldDeriveKeys)
            {
                return;
            }

            var derivedKeys = new SrtpDerivedkeys();

            derivedKeys.SessionKey = DeriveKey(masterKey, masterSalt, r, SrtpEncryptionKeyLabel.SrtpEncryptionKey, SrtpConstants.SrtpDefaultEncryptionSessionKeyLength);

            derivedKeys.AuthKey = DeriveKey(masterKey, masterSalt, r, SrtpEncryptionKeyLabel.SrtpMessageAuthenticationKey, SrtpConstants.SrtpDefaultAuthSessionKeyLength);

            derivedKeys.CipherSalt = DeriveKey(masterKey, masterSalt, r, SrtpEncryptionKeyLabel.SrtpSaltingKey, SrtpConstants.SrtpDefaultSaltSessionKeyLength);

            srtpStreamContext.DerivedKeys = derivedKeys;
        }