Skip to content

Commit 590d1cf

Browse files
sirzooroSean-Der
authored andcommitted
Added support for NULL ciphers
Added support for NULL ciphers. When they are used, created SRTP and SRTCP packets are authenticated only (no encryption). Received SRTP/SRTCP packets are checked if their authentication tag is valid, and extra SRTP protocol fields are removed before returning then to application. Fixed processing of SRTCP packets with E (encryption) bit cleared, previously duplicate check and tag valiation was not performed, and whole packet was returned as-is (with extra fields) from decryptRTCP. Use of NULL ciphers can be enabled independently for SRTP and SRTCP using SRTPNoEncryption and SRTCPNoEncryption options. They can be used with key exchange protocols which allows to configure them separately. Added support for SRTP_NULL_HMAC_SHA1_80 and SRTP_NULL_HMAC_SHA1_32 cipher suites. They use key and salt of the same length as AES_CM_128 ones. Added new tests to verify test vectors from RFCs.
1 parent 2a52aa0 commit 590d1cf

11 files changed

+1021
-65
lines changed

context.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ type Context struct {
6262

6363
sendMKI []byte // Master Key Identifier used for encrypting RTP/RTCP packets. Set to nil if MKI is not enabled.
6464
mkis map[string]srtpCipher // Master Key Identifier to cipher mapping. Used for decrypting packets. Empty if MKI is not enabled.
65+
66+
encryptSRTP bool
67+
encryptSRTCP bool
6568
}
6669

6770
// CreateContext creates a new SRTP Context.
@@ -83,6 +86,8 @@ func CreateContext(masterKey, masterSalt []byte, profile ProtectionProfile, opts
8386
[]ContextOption{ // Default options
8487
SRTPNoReplayProtection(),
8588
SRTCPNoReplayProtection(),
89+
SRTPEncryption(),
90+
SRTCPEncryption(),
8691
},
8792
opts..., // User specified options
8893
) {
@@ -91,7 +96,7 @@ func CreateContext(masterKey, masterSalt []byte, profile ProtectionProfile, opts
9196
}
9297
}
9398

94-
c.cipher, err = c.createCipher(c.sendMKI, masterKey, masterSalt)
99+
c.cipher, err = c.createCipher(c.sendMKI, masterKey, masterSalt, c.encryptSRTP, c.encryptSRTCP)
95100
if err != nil {
96101
return nil, err
97102
}
@@ -116,15 +121,15 @@ func (c *Context) AddCipherForMKI(mki, masterKey, masterSalt []byte) error {
116121
return errMKIAlreadyInUse
117122
}
118123

119-
cipher, err := c.createCipher(mki, masterKey, masterSalt)
124+
cipher, err := c.createCipher(mki, masterKey, masterSalt, c.encryptSRTP, c.encryptSRTCP)
120125
if err != nil {
121126
return err
122127
}
123128
c.mkis[string(mki)] = cipher
124129
return nil
125130
}
126131

127-
func (c *Context) createCipher(mki, masterKey, masterSalt []byte) (srtpCipher, error) {
132+
func (c *Context) createCipher(mki, masterKey, masterSalt []byte, encryptSRTP, encryptSRTCP bool) (srtpCipher, error) {
128133
keyLen, err := c.profile.KeyLen()
129134
if err != nil {
130135
return nil, err
@@ -143,9 +148,11 @@ func (c *Context) createCipher(mki, masterKey, masterSalt []byte) (srtpCipher, e
143148

144149
switch c.profile {
145150
case ProtectionProfileAeadAes128Gcm, ProtectionProfileAeadAes256Gcm:
146-
return newSrtpCipherAeadAesGcm(c.profile, masterKey, masterSalt, mki)
151+
return newSrtpCipherAeadAesGcm(c.profile, masterKey, masterSalt, mki, encryptSRTP, encryptSRTCP)
147152
case ProtectionProfileAes128CmHmacSha1_32, ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAes256CmHmacSha1_32, ProtectionProfileAes256CmHmacSha1_80:
148-
return newSrtpCipherAesCmHmacSha1(c.profile, masterKey, masterSalt, mki)
153+
return newSrtpCipherAesCmHmacSha1(c.profile, masterKey, masterSalt, mki, encryptSRTP, encryptSRTCP)
154+
case ProtectionProfileNullHmacSha1_32, ProtectionProfileNullHmacSha1_80:
155+
return newSrtpCipherAesCmHmacSha1(c.profile, masterKey, masterSalt, mki, false, false)
149156
default:
150157
return nil, fmt.Errorf("%w: %#v", errNoSuchSRTPProfile, c.profile)
151158
}

option.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,37 @@ func MasterKeyIndicator(mki []byte) ContextOption {
8484
return nil
8585
}
8686
}
87+
88+
// SRTPEncryption enables SRTP encryption.
89+
func SRTPEncryption() ContextOption { // nolint:revive
90+
return func(c *Context) error {
91+
c.encryptSRTP = true
92+
return nil
93+
}
94+
}
95+
96+
// SRTPNoEncryption disables SRTP encryption. This option is useful when you want to use NullCipher for SRTP and keep authentication only.
97+
// It simplifies debugging and testing, but it is not recommended for production use.
98+
func SRTPNoEncryption() ContextOption { // nolint:revive
99+
return func(c *Context) error {
100+
c.encryptSRTP = false
101+
return nil
102+
}
103+
}
104+
105+
// SRTCPEncryption enables SRTCP encryption.
106+
func SRTCPEncryption() ContextOption {
107+
return func(c *Context) error {
108+
c.encryptSRTCP = true
109+
return nil
110+
}
111+
}
112+
113+
// SRTCPNoEncryption disables SRTCP encryption. This option is useful when you want to use NullCipher for SRTCP and keep authentication only.
114+
// It simplifies debugging and testing, but it is not recommended for production use.
115+
func SRTCPNoEncryption() ContextOption {
116+
return func(c *Context) error {
117+
c.encryptSRTCP = false
118+
return nil
119+
}
120+
}

protection_profile.go

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,24 @@ type ProtectionProfile uint16
1515
// in RFC 5764. They were in earlier draft of this RFC: https://datatracker.ietf.org/doc/html/draft-ietf-avt-dtls-srtp-03#section-4.1.2
1616
// Their IDs are now marked as reserved in the IANA registry. Despite this Chrome supports them:
1717
// https://chromium.googlesource.com/chromium/deps/libsrtp/+/84122798bb16927b1e676bd4f938a6e48e5bf2fe/srtp/include/srtp.h#694
18+
//
19+
// Null profiles disable encryption, they are used for debugging and testing. They are not recommended for production use.
20+
// Use of them is equivalent to using ProtectionProfileAes128CmHmacSha1_NN profile with SRTPNoEncryption and SRTCPNoEncryption options.
1821
const (
1922
ProtectionProfileAes128CmHmacSha1_80 ProtectionProfile = 0x0001
2023
ProtectionProfileAes128CmHmacSha1_32 ProtectionProfile = 0x0002
2124
ProtectionProfileAes256CmHmacSha1_80 ProtectionProfile = 0x0003
2225
ProtectionProfileAes256CmHmacSha1_32 ProtectionProfile = 0x0004
26+
ProtectionProfileNullHmacSha1_80 ProtectionProfile = 0x0005
27+
ProtectionProfileNullHmacSha1_32 ProtectionProfile = 0x0006
2328
ProtectionProfileAeadAes128Gcm ProtectionProfile = 0x0007
2429
ProtectionProfileAeadAes256Gcm ProtectionProfile = 0x0008
2530
)
2631

27-
// KeyLen returns length of encryption key in bytes.
32+
// KeyLen returns length of encryption key in bytes. For all profiles except NullHmacSha1_32 and NullHmacSha1_80 is is also the length of the session key.
2833
func (p ProtectionProfile) KeyLen() (int, error) {
2934
switch p {
30-
case ProtectionProfileAes128CmHmacSha1_32, ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAeadAes128Gcm:
35+
case ProtectionProfileAes128CmHmacSha1_32, ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAeadAes128Gcm, ProtectionProfileNullHmacSha1_32, ProtectionProfileNullHmacSha1_80:
3136
return 16, nil
3237
case ProtectionProfileAeadAes256Gcm, ProtectionProfileAes256CmHmacSha1_32, ProtectionProfileAes256CmHmacSha1_80:
3338
return 32, nil
@@ -36,10 +41,10 @@ func (p ProtectionProfile) KeyLen() (int, error) {
3641
}
3742
}
3843

39-
// SaltLen returns length of salt key in bytes.
44+
// SaltLen returns length of salt key in bytes. For all profiles except NullHmacSha1_32 and NullHmacSha1_80 is is also the length of the session salt.
4045
func (p ProtectionProfile) SaltLen() (int, error) {
4146
switch p {
42-
case ProtectionProfileAes128CmHmacSha1_32, ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAes256CmHmacSha1_32, ProtectionProfileAes256CmHmacSha1_80:
47+
case ProtectionProfileAes128CmHmacSha1_32, ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAes256CmHmacSha1_32, ProtectionProfileAes256CmHmacSha1_80, ProtectionProfileNullHmacSha1_32, ProtectionProfileNullHmacSha1_80:
4348
return 14, nil
4449
case ProtectionProfileAeadAes128Gcm, ProtectionProfileAeadAes256Gcm:
4550
return 12, nil
@@ -51,9 +56,9 @@ func (p ProtectionProfile) SaltLen() (int, error) {
5156
// AuthTagRTPLen returns length of RTP authentication tag in bytes for AES protection profiles. For AEAD ones it returns zero.
5257
func (p ProtectionProfile) AuthTagRTPLen() (int, error) {
5358
switch p {
54-
case ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAes256CmHmacSha1_80:
59+
case ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAes256CmHmacSha1_80, ProtectionProfileNullHmacSha1_80:
5560
return 10, nil
56-
case ProtectionProfileAes128CmHmacSha1_32, ProtectionProfileAes256CmHmacSha1_32:
61+
case ProtectionProfileAes128CmHmacSha1_32, ProtectionProfileAes256CmHmacSha1_32, ProtectionProfileNullHmacSha1_32:
5762
return 4, nil
5863
case ProtectionProfileAeadAes128Gcm, ProtectionProfileAeadAes256Gcm:
5964
return 0, nil
@@ -65,7 +70,7 @@ func (p ProtectionProfile) AuthTagRTPLen() (int, error) {
6570
// AuthTagRTCPLen returns length of RTCP authentication tag in bytes for AES protection profiles. For AEAD ones it returns zero.
6671
func (p ProtectionProfile) AuthTagRTCPLen() (int, error) {
6772
switch p {
68-
case ProtectionProfileAes128CmHmacSha1_32, ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAes256CmHmacSha1_32, ProtectionProfileAes256CmHmacSha1_80:
73+
case ProtectionProfileAes128CmHmacSha1_32, ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAes256CmHmacSha1_32, ProtectionProfileAes256CmHmacSha1_80, ProtectionProfileNullHmacSha1_32, ProtectionProfileNullHmacSha1_80:
6974
return 10, nil
7075
case ProtectionProfileAeadAes128Gcm, ProtectionProfileAeadAes256Gcm:
7176
return 0, nil
@@ -77,7 +82,7 @@ func (p ProtectionProfile) AuthTagRTCPLen() (int, error) {
7782
// AEADAuthTagLen returns length of authentication tag in bytes for AEAD protection profiles. For AES ones it returns zero.
7883
func (p ProtectionProfile) AEADAuthTagLen() (int, error) {
7984
switch p {
80-
case ProtectionProfileAes128CmHmacSha1_32, ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAes256CmHmacSha1_32, ProtectionProfileAes256CmHmacSha1_80:
85+
case ProtectionProfileAes128CmHmacSha1_32, ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAes256CmHmacSha1_32, ProtectionProfileAes256CmHmacSha1_80, ProtectionProfileNullHmacSha1_32, ProtectionProfileNullHmacSha1_80:
8186
return 0, nil
8287
case ProtectionProfileAeadAes128Gcm, ProtectionProfileAeadAes256Gcm:
8388
return 16, nil
@@ -89,7 +94,7 @@ func (p ProtectionProfile) AEADAuthTagLen() (int, error) {
8994
// AuthKeyLen returns length of authentication key in bytes for AES protection profiles. For AEAD ones it returns zero.
9095
func (p ProtectionProfile) AuthKeyLen() (int, error) {
9196
switch p {
92-
case ProtectionProfileAes128CmHmacSha1_32, ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAes256CmHmacSha1_32, ProtectionProfileAes256CmHmacSha1_80:
97+
case ProtectionProfileAes128CmHmacSha1_32, ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAes256CmHmacSha1_32, ProtectionProfileAes256CmHmacSha1_80, ProtectionProfileNullHmacSha1_32, ProtectionProfileNullHmacSha1_80:
9398
return 20, nil
9499
case ProtectionProfileAeadAes128Gcm, ProtectionProfileAeadAes256Gcm:
95100
return 0, nil
@@ -113,6 +118,10 @@ func (p ProtectionProfile) String() string {
113118
return "SRTP_AEAD_AES_128_GCM"
114119
case ProtectionProfileAeadAes256Gcm:
115120
return "SRTP_AEAD_AES_256_GCM"
121+
case ProtectionProfileNullHmacSha1_80:
122+
return "SRTP_NULL_HMAC_SHA1_80"
123+
case ProtectionProfileNullHmacSha1_32:
124+
return "SRTP_NULL_HMAC_SHA1_32"
116125
default:
117126
return fmt.Sprintf("Unknown SRTP profile: %#v", p)
118127
}

srtcp.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ import (
1212

1313
const maxSRTCPIndex = 0x7FFFFFFF
1414

15-
func (c *Context) decryptRTCP(dst, encrypted []byte) ([]byte, error) {
16-
out := allocateIfMismatch(dst, encrypted)
15+
const srtcpHeaderSize = 8
1716

17+
func (c *Context) decryptRTCP(dst, encrypted []byte) ([]byte, error) {
1818
authTagLen, err := c.cipher.AuthTagRTCPLen()
1919
if err != nil {
2020
return nil, err
@@ -24,12 +24,10 @@ func (c *Context) decryptRTCP(dst, encrypted []byte) ([]byte, error) {
2424
return nil, err
2525
}
2626
mkiLen := len(c.sendMKI)
27-
tailOffset := len(encrypted) - (authTagLen + mkiLen + srtcpIndexSize)
2827

29-
if tailOffset < aeadAuthTagLen {
28+
// Verify that encrypted packet is long enough
29+
if len(encrypted) < (srtcpHeaderSize + aeadAuthTagLen + srtcpIndexSize + mkiLen + authTagLen) {
3030
return nil, fmt.Errorf("%w: %d", errTooShortRTCP, len(encrypted))
31-
} else if isEncrypted := encrypted[tailOffset] >> 7; isEncrypted == 0 {
32-
return out, nil
3331
}
3432

3533
index := c.cipher.getRTCPIndex(encrypted)
@@ -51,6 +49,8 @@ func (c *Context) decryptRTCP(dst, encrypted []byte) ([]byte, error) {
5149
}
5250
}
5351

52+
out := allocateIfMismatch(dst, encrypted)
53+
5454
out, err = cipher.decryptRTCP(out, encrypted, index, ssrc)
5555
if err != nil {
5656
return nil, err
@@ -74,7 +74,7 @@ func (c *Context) DecryptRTCP(dst, encrypted []byte, header *rtcp.Header) ([]byt
7474
}
7575

7676
func (c *Context) encryptRTCP(dst, decrypted []byte) ([]byte, error) {
77-
if len(decrypted) < 8 {
77+
if len(decrypted) < srtcpHeaderSize {
7878
return nil, fmt.Errorf("%w: %d", errTooShortRTCP, len(decrypted))
7979
}
8080

srtp.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
package srtp
66

77
import (
8+
"fmt"
9+
810
"github.com/pion/rtp"
911
)
1012

@@ -13,9 +15,15 @@ func (c *Context) decryptRTP(dst, ciphertext []byte, header *rtp.Header, headerL
1315
if err != nil {
1416
return nil, err
1517
}
18+
aeadAuthTagLen, err := c.cipher.AEADAuthTagLen()
19+
if err != nil {
20+
return nil, err
21+
}
22+
mkiLen := len(c.sendMKI)
1623

17-
if len(ciphertext) < headerLen+len(c.sendMKI)+authTagLen {
18-
return nil, errTooShortRTP
24+
// Verify that encrypted packet is long enough
25+
if len(ciphertext) < (headerLen + aeadAuthTagLen + mkiLen + authTagLen) {
26+
return nil, fmt.Errorf("%w: %d", errTooShortRTP, len(ciphertext))
1927
}
2028

2129
s := c.getSRTPSSRCState(header.SSRC)

srtp_cipher_aead_aes_gcm.go

Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"crypto/aes"
88
"crypto/cipher"
99
"encoding/binary"
10+
"fmt"
1011

1112
"github.com/pion/rtp"
1213
)
@@ -23,10 +24,16 @@ type srtpCipherAeadAesGcm struct {
2324
srtpSessionSalt, srtcpSessionSalt []byte
2425

2526
mki []byte
27+
28+
srtpEncrypted, srtcpEncrypted bool
2629
}
2730

28-
func newSrtpCipherAeadAesGcm(profile ProtectionProfile, masterKey, masterSalt, mki []byte) (*srtpCipherAeadAesGcm, error) {
29-
s := &srtpCipherAeadAesGcm{ProtectionProfile: profile}
31+
func newSrtpCipherAeadAesGcm(profile ProtectionProfile, masterKey, masterSalt, mki []byte, encryptSRTP, encryptSRTCP bool) (*srtpCipherAeadAesGcm, error) {
32+
s := &srtpCipherAeadAesGcm{
33+
ProtectionProfile: profile,
34+
srtpEncrypted: encryptSRTP,
35+
srtcpEncrypted: encryptSRTCP,
36+
}
3037

3138
srtpSessionKey, err := aesCmKeyDerivation(labelSRTPEncryption, masterKey, masterSalt, 0, len(masterKey))
3239
if err != nil {
@@ -87,7 +94,13 @@ func (s *srtpCipherAeadAesGcm) encryptRTP(dst []byte, header *rtp.Header, payloa
8794
}
8895

8996
iv := s.rtpInitializationVector(header, roc)
90-
s.srtpCipher.Seal(dst[n:n], iv[:], payload, dst[:n])
97+
if s.srtpEncrypted {
98+
s.srtpCipher.Seal(dst[n:n], iv[:], payload, dst[:n])
99+
} else {
100+
clearLen := n + len(payload)
101+
copy(dst[n:], payload)
102+
s.srtpCipher.Seal(dst[clearLen:clearLen], iv[:], nil, dst[:clearLen])
103+
}
91104

92105
// Add MKI after the encrypted payload
93106
if len(s.mki) > 0 {
@@ -113,10 +126,20 @@ func (s *srtpCipherAeadAesGcm) decryptRTP(dst, ciphertext []byte, header *rtp.He
113126
iv := s.rtpInitializationVector(header, roc)
114127

115128
nEnd := len(ciphertext) - len(s.mki)
116-
if _, err := s.srtpCipher.Open(
117-
dst[headerLen:headerLen], iv[:], ciphertext[headerLen:nEnd], ciphertext[:headerLen],
118-
); err != nil {
119-
return nil, err
129+
if s.srtpEncrypted {
130+
if _, err := s.srtpCipher.Open(
131+
dst[headerLen:headerLen], iv[:], ciphertext[headerLen:nEnd], ciphertext[:headerLen],
132+
); err != nil {
133+
return nil, fmt.Errorf("%w: %w", ErrFailedToVerifyAuthTag, err)
134+
}
135+
} else {
136+
nDataEnd := nEnd - authTagLen
137+
if _, err := s.srtpCipher.Open(
138+
nil, iv[:], ciphertext[nDataEnd:nEnd], ciphertext[:nDataEnd],
139+
); err != nil {
140+
return nil, fmt.Errorf("%w: %w", ErrFailedToVerifyAuthTag, err)
141+
}
142+
copy(dst[headerLen:], ciphertext[headerLen:nDataEnd])
120143
}
121144

122145
copy(dst[:headerLen], ciphertext[:headerLen])
@@ -133,12 +156,25 @@ func (s *srtpCipherAeadAesGcm) encryptRTCP(dst, decrypted []byte, srtcpIndex uin
133156
dst = growBufferSize(dst, aadPos+srtcpIndexSize+len(s.mki))
134157

135158
iv := s.rtcpInitializationVector(srtcpIndex, ssrc)
136-
aad := s.rtcpAdditionalAuthenticatedData(decrypted, srtcpIndex)
137-
138-
s.srtcpCipher.Seal(dst[8:8], iv[:], decrypted[8:], aad[:])
159+
if s.srtcpEncrypted {
160+
aad := s.rtcpAdditionalAuthenticatedData(decrypted, srtcpIndex)
161+
copy(dst[:8], decrypted[:8])
162+
copy(dst[aadPos:aadPos+4], aad[8:12])
163+
s.srtcpCipher.Seal(dst[8:8], iv[:], decrypted[8:], aad[:])
164+
} else {
165+
// Copy the packet unencrypted.
166+
copy(dst, decrypted)
167+
// Append the SRTCP index to the end of the packet - this will form the AAD.
168+
binary.BigEndian.PutUint32(dst[len(decrypted):], srtcpIndex)
169+
// Generate the authentication tag.
170+
tag := make([]byte, authTagLen)
171+
s.srtcpCipher.Seal(tag[0:0], iv[:], nil, dst[:len(decrypted)+4])
172+
// Copy index to the proper place.
173+
copy(dst[aadPos:], dst[len(decrypted):len(decrypted)+4])
174+
// Copy the auth tag after RTCP payload.
175+
copy(dst[len(decrypted):], tag)
176+
}
139177

140-
copy(dst[:8], decrypted[:8])
141-
copy(dst[aadPos:aadPos+4], aad[8:12])
142178
copy(dst[aadPos+4:], s.mki)
143179
return dst, nil
144180
}
@@ -157,11 +193,25 @@ func (s *srtpCipherAeadAesGcm) decryptRTCP(dst, encrypted []byte, srtcpIndex, ss
157193
}
158194
dst = growBufferSize(dst, nDst)
159195

196+
isEncrypted := encrypted[aadPos]>>7 != 0
160197
iv := s.rtcpInitializationVector(srtcpIndex, ssrc)
161-
aad := s.rtcpAdditionalAuthenticatedData(encrypted, srtcpIndex)
162-
163-
if _, err := s.srtcpCipher.Open(dst[8:8], iv[:], encrypted[8:aadPos], aad[:]); err != nil {
164-
return nil, err
198+
if isEncrypted {
199+
aad := s.rtcpAdditionalAuthenticatedData(encrypted, srtcpIndex)
200+
if _, err := s.srtcpCipher.Open(dst[8:8], iv[:], encrypted[8:aadPos], aad[:]); err != nil {
201+
return nil, fmt.Errorf("%w: %w", ErrFailedToVerifyAuthTag, err)
202+
}
203+
} else {
204+
// Prepare AAD for received packet.
205+
dataEnd := aadPos - authTagLen
206+
aad := make([]byte, dataEnd+4)
207+
copy(aad, encrypted[:dataEnd])
208+
copy(aad[dataEnd:], encrypted[aadPos:aadPos+4])
209+
// Verify the auth tag.
210+
if _, err := s.srtcpCipher.Open(nil, iv[:], encrypted[dataEnd:aadPos], aad); err != nil {
211+
return nil, fmt.Errorf("%w: %w", ErrFailedToVerifyAuthTag, err)
212+
}
213+
// Copy the unencrypted payload.
214+
copy(dst[8:], encrypted[8:dataEnd])
165215
}
166216

167217
copy(dst[:8], encrypted[:8])

0 commit comments

Comments
 (0)