summaryrefslogtreecommitdiff
path: root/vendor/github.com/pion/srtp/v2
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/pion/srtp/v2')
-rw-r--r--vendor/github.com/pion/srtp/v2/.gitignore24
-rw-r--r--vendor/github.com/pion/srtp/v2/.golangci.yml89
-rw-r--r--vendor/github.com/pion/srtp/v2/DESIGN.md20
-rw-r--r--vendor/github.com/pion/srtp/v2/LICENSE21
-rw-r--r--vendor/github.com/pion/srtp/v2/README.md54
-rw-r--r--vendor/github.com/pion/srtp/v2/codecov.yml20
-rw-r--r--vendor/github.com/pion/srtp/v2/context.go196
-rw-r--r--vendor/github.com/pion/srtp/v2/errors.go40
-rw-r--r--vendor/github.com/pion/srtp/v2/go.mod11
-rw-r--r--vendor/github.com/pion/srtp/v2/go.sum34
-rw-r--r--vendor/github.com/pion/srtp/v2/key_derivation.go63
-rw-r--r--vendor/github.com/pion/srtp/v2/keying.go54
-rw-r--r--vendor/github.com/pion/srtp/v2/option.go54
-rw-r--r--vendor/github.com/pion/srtp/v2/protection_profile.go67
-rw-r--r--vendor/github.com/pion/srtp/v2/renovate.json15
-rw-r--r--vendor/github.com/pion/srtp/v2/session.go150
-rw-r--r--vendor/github.com/pion/srtp/v2/session_srtcp.go180
-rw-r--r--vendor/github.com/pion/srtp/v2/session_srtp.go171
-rw-r--r--vendor/github.com/pion/srtp/v2/srtcp.go77
-rw-r--r--vendor/github.com/pion/srtp/v2/srtp.go68
-rw-r--r--vendor/github.com/pion/srtp/v2/srtp_cipher.go46
-rw-r--r--vendor/github.com/pion/srtp/v2/srtp_cipher_aead_aes_gcm.go198
-rw-r--r--vendor/github.com/pion/srtp/v2/srtp_cipher_aes_cm_hmac_sha1.go228
-rw-r--r--vendor/github.com/pion/srtp/v2/stream.go8
-rw-r--r--vendor/github.com/pion/srtp/v2/stream_srtcp.go157
-rw-r--r--vendor/github.com/pion/srtp/v2/stream_srtp.go154
-rw-r--r--vendor/github.com/pion/srtp/v2/util.go33
27 files changed, 2232 insertions, 0 deletions
diff --git a/vendor/github.com/pion/srtp/v2/.gitignore b/vendor/github.com/pion/srtp/v2/.gitignore
new file mode 100644
index 0000000..83db74b
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/.gitignore
@@ -0,0 +1,24 @@
+### JetBrains IDE ###
+#####################
+.idea/
+
+### Emacs Temporary Files ###
+#############################
+*~
+
+### Folders ###
+###############
+bin/
+vendor/
+node_modules/
+
+### Files ###
+#############
+*.ivf
+*.ogg
+tags
+cover.out
+*.sw[poe]
+*.wasm
+examples/sfu-ws/cert.pem
+examples/sfu-ws/key.pem
diff --git a/vendor/github.com/pion/srtp/v2/.golangci.yml b/vendor/github.com/pion/srtp/v2/.golangci.yml
new file mode 100644
index 0000000..d6162c9
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/.golangci.yml
@@ -0,0 +1,89 @@
+linters-settings:
+ govet:
+ check-shadowing: true
+ misspell:
+ locale: US
+ exhaustive:
+ default-signifies-exhaustive: true
+ gomodguard:
+ blocked:
+ modules:
+ - github.com/pkg/errors:
+ recommendations:
+ - errors
+
+linters:
+ enable:
+ - asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers
+ - bodyclose # checks whether HTTP response body is closed successfully
+ - deadcode # Finds unused code
+ - depguard # Go linter that checks if package imports are in a list of acceptable packages
+ - dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())
+ - dupl # Tool for code clone detection
+ - errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases
+ - exhaustive # check exhaustiveness of enum switch statements
+ - exportloopref # checks for pointers to enclosing loop variables
+ - gci # Gci control golang package import order and make it always deterministic.
+ - gochecknoglobals # Checks that no globals are present in Go code
+ - gochecknoinits # Checks that no init functions are present in Go code
+ - gocognit # Computes and checks the cognitive complexity of functions
+ - goconst # Finds repeated strings that could be replaced by a constant
+ - gocritic # The most opinionated Go source code linter
+ - godox # Tool for detection of FIXME, TODO and other comment keywords
+ - goerr113 # Golang linter to check the errors handling expressions
+ - gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification
+ - gofumpt # Gofumpt checks whether code was gofumpt-ed.
+ - goheader # Checks is file header matches to pattern
+ - goimports # Goimports does everything that gofmt does. Additionally it checks unused imports
+ - golint # Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes
+ - gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations.
+ - goprintffuncname # Checks that printf-like functions are named with `f` at the end
+ - gosec # Inspects source code for security problems
+ - gosimple # Linter for Go source code that specializes in simplifying a code
+ - govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
+ - ineffassign # Detects when assignments to existing variables are not used
+ - misspell # Finds commonly misspelled English words in comments
+ - nakedret # Finds naked returns in functions greater than a specified function length
+ - noctx # noctx finds sending http request without context.Context
+ - scopelint # Scopelint checks for unpinned variables in go programs
+ - staticcheck # Staticcheck is a go vet on steroids, applying a ton of static analysis checks
+ - structcheck # Finds unused struct fields
+ - stylecheck # Stylecheck is a replacement for golint
+ - typecheck # Like the front-end of a Go compiler, parses and type-checks Go code
+ - unconvert # Remove unnecessary type conversions
+ - unparam # Reports unused function parameters
+ - unused # Checks Go code for unused constants, variables, functions and types
+ - varcheck # Finds unused global variables and constants
+ - whitespace # Tool for detection of leading and trailing whitespace
+ disable:
+ - funlen # Tool for detection of long functions
+ - gocyclo # Computes and checks the cyclomatic complexity of functions
+ - godot # Check if comments end in a period
+ - gomnd # An analyzer to detect magic numbers.
+ - lll # Reports long lines
+ - maligned # Tool to detect Go structs that would take less memory if their fields were sorted
+ - nestif # Reports deeply nested if statements
+ - nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity
+ - nolintlint # Reports ill-formed or insufficient nolint directives
+ - prealloc # Finds slice declarations that could potentially be preallocated
+ - rowserrcheck # checks whether Err of rows is checked successfully
+ - sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed.
+ - testpackage # linter that makes you use a separate _test package
+ - wsl # Whitespace Linter - Forces you to use empty lines!
+
+issues:
+ exclude-use-default: false
+ exclude-rules:
+ # Allow complex tests, better to be self contained
+ - path: _test\.go
+ linters:
+ - gocognit
+
+ # Allow complex main function in examples
+ - path: examples
+ text: "of func `main` is high"
+ linters:
+ - gocognit
+
+run:
+ skip-dirs-use-default: false
diff --git a/vendor/github.com/pion/srtp/v2/DESIGN.md b/vendor/github.com/pion/srtp/v2/DESIGN.md
new file mode 100644
index 0000000..8742540
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/DESIGN.md
@@ -0,0 +1,20 @@
+<h1 align="center">
+ Design
+</h1>
+
+### Portable
+Pion SRTP is written in Go and extremely portable. Anywhere Golang runs, Pion SRTP should work as well! Instead of dealing with complicated
+cross-compiling of multiple libraries, you now can run anywhere with one `go build`
+
+### Simple API
+The API is based on an io.ReadWriteCloser.
+
+### Readable
+If code comes from an RFC we try to make sure everything is commented with a link to the spec.
+This makes learning and debugging easier, this library was written to also serve as a guide for others.
+
+### Tested
+Every commit is tested via travis-ci Go provides fantastic facilities for testing, and more will be added as time goes on.
+
+### Shared libraries
+Every pion product is built using shared libraries, allowing others to review and reuse our libraries.
diff --git a/vendor/github.com/pion/srtp/v2/LICENSE b/vendor/github.com/pion/srtp/v2/LICENSE
new file mode 100644
index 0000000..ab60297
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/pion/srtp/v2/README.md b/vendor/github.com/pion/srtp/v2/README.md
new file mode 100644
index 0000000..19551e3
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/README.md
@@ -0,0 +1,54 @@
+<h1 align="center">
+ <br>
+ Pion SRTP
+ <br>
+</h1>
+<h4 align="center">A Go implementation of SRTP</h4>
+<p align="center">
+ <a href="https://pion.ly"><img src="https://img.shields.io/badge/pion-srtp-gray.svg?longCache=true&colorB=brightgreen" alt="Pion SRTP"></a>
+ <a href="https://sourcegraph.com/github.com/pion/srtp?badge"><img src="https://sourcegraph.com/github.com/pion/srtp/-/badge.svg" alt="Sourcegraph Widget"></a>
+ <a href="https://pion.ly/slack"><img src="https://img.shields.io/badge/join-us%20on%20slack-gray.svg?longCache=true&logo=slack&colorB=brightgreen" alt="Slack Widget"></a>
+ <br>
+ <a href="https://travis-ci.org/pion/srtp"><img src="https://travis-ci.org/pion/srtp.svg?branch=master" alt="Build Status"></a>
+ <a href="https://pkg.go.dev/github.com/pion/srtp"><img src="https://godoc.org/github.com/pion/srtp?status.svg" alt="GoDoc"></a>
+ <a href="https://codecov.io/gh/pion/srtp"><img src="https://codecov.io/gh/pion/srtp/branch/master/graph/badge.svg" alt="Coverage Status"></a>
+ <a href="https://goreportcard.com/report/github.com/pion/srtp"><img src="https://goreportcard.com/badge/github.com/pion/srtp" alt="Go Report Card"></a>
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
+</p>
+<br>
+
+See [DESIGN.md](DESIGN.md) for an overview of features and future goals.
+
+### Roadmap
+The library is used as a part of our WebRTC implementation. Please refer to that [roadmap](https://github.com/pion/webrtc/issues/9) to track our major milestones.
+
+### Community
+Pion has an active community on the [Golang Slack](https://invite.slack.golangbridge.org/). Sign up and join the **#pion** channel for discussions and support. You can also use [Pion mailing list](https://groups.google.com/forum/#!forum/pion).
+
+We are always looking to support **your projects**. Please reach out if you have something to build!
+
+If you need commercial support or don't want to use public methods you can contact us at [team@pion.ly](mailto:team@pion.ly)
+
+### Contributing
+Check out the **[contributing wiki](https://github.com/pion/webrtc/wiki/Contributing)** to join the group of amazing people making this project possible:
+
+* [Sean DuBois](https://github.com/Sean-Der) - *Original Author*
+* [Michiel De Backker](https://github.com/backkem) - *io.Writer interfaces*
+* [Tobias Fridén](https://github.com/tobiasfriden) *SRTP authentication verification*
+* [chenkaiC4](https://github.com/chenkaiC4) - *Fix GolangCI Linter*
+* [Luke Curley](https://github.com/kixelated) - *Performance*
+* [Chris Hiszpanski](https://github.com/thinkski) - *Fix out-of-bounds access*
+* [Yutaka Takeda](https://github.com/enobufs) - *Fix log messages*
+* [Max Hawkins](https://github.com/maxhawkins)
+* [Woodrow Douglass](https://github.com/wdouglass)
+* [Hugo Arregui](https://github.com/hugoArregui)
+* [Atsushi Watanabe](https://github.com/at-wat)
+* [Novel Corpse](https://github.com/NovelCorpse)
+* [Jerko Steiner](https://github.com/jeremija)
+* [Juliusz Chroboczek](https://github.com/jech)
+* [Mission Liao](https://github.com/mission-liao)
+* [Orlando](https://github.com/OrlandoCo)
+* [Tarrence van As](https://github.com/tarrencev)
+
+### License
+MIT License - see [LICENSE](LICENSE) for full text
diff --git a/vendor/github.com/pion/srtp/v2/codecov.yml b/vendor/github.com/pion/srtp/v2/codecov.yml
new file mode 100644
index 0000000..085200a
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/codecov.yml
@@ -0,0 +1,20 @@
+#
+# DO NOT EDIT THIS FILE
+#
+# It is automatically copied from https://github.com/pion/.goassets repository.
+#
+
+coverage:
+ status:
+ project:
+ default:
+ # Allow decreasing 2% of total coverage to avoid noise.
+ threshold: 2%
+ patch:
+ default:
+ target: 70%
+ only_pulls: true
+
+ignore:
+ - "examples/*"
+ - "examples/**/*"
diff --git a/vendor/github.com/pion/srtp/v2/context.go b/vendor/github.com/pion/srtp/v2/context.go
new file mode 100644
index 0000000..63566de
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/context.go
@@ -0,0 +1,196 @@
+package srtp
+
+import (
+ "fmt"
+
+ "github.com/pion/transport/replaydetector"
+)
+
+const (
+ labelSRTPEncryption = 0x00
+ labelSRTPAuthenticationTag = 0x01
+ labelSRTPSalt = 0x02
+
+ labelSRTCPEncryption = 0x03
+ labelSRTCPAuthenticationTag = 0x04
+ labelSRTCPSalt = 0x05
+
+ maxROCDisorder = 100
+ maxSequenceNumber = 65535
+
+ srtcpIndexSize = 4
+)
+
+// Encrypt/Decrypt state for a single SRTP SSRC
+type srtpSSRCState struct {
+ ssrc uint32
+ rolloverCounter uint32
+ rolloverHasProcessed bool
+ lastSequenceNumber uint16
+ replayDetector replaydetector.ReplayDetector
+}
+
+// Encrypt/Decrypt state for a single SRTCP SSRC
+type srtcpSSRCState struct {
+ srtcpIndex uint32
+ ssrc uint32
+ replayDetector replaydetector.ReplayDetector
+}
+
+// Context represents a SRTP cryptographic context.
+// Context can only be used for one-way operations.
+// it must either used ONLY for encryption or ONLY for decryption.
+type Context struct {
+ cipher srtpCipher
+
+ srtpSSRCStates map[uint32]*srtpSSRCState
+ srtcpSSRCStates map[uint32]*srtcpSSRCState
+
+ newSRTCPReplayDetector func() replaydetector.ReplayDetector
+ newSRTPReplayDetector func() replaydetector.ReplayDetector
+}
+
+// CreateContext creates a new SRTP Context.
+//
+// CreateContext receives variable number of ContextOption-s.
+// Passing multiple options which set the same parameter let the last one valid.
+// Following example create SRTP Context with replay protection with window size of 256.
+//
+// decCtx, err := srtp.CreateContext(key, salt, profile, srtp.SRTPReplayProtection(256))
+//
+func CreateContext(masterKey, masterSalt []byte, profile ProtectionProfile, opts ...ContextOption) (c *Context, err error) {
+ keyLen, err := profile.keyLen()
+ if err != nil {
+ return nil, err
+ }
+
+ saltLen, err := profile.saltLen()
+ if err != nil {
+ return nil, err
+ }
+
+ if masterKeyLen := len(masterKey); masterKeyLen != keyLen {
+ return c, fmt.Errorf("%w expected(%d) actual(%d)", errShortSrtpMasterKey, masterKey, keyLen)
+ } else if masterSaltLen := len(masterSalt); masterSaltLen != saltLen {
+ return c, fmt.Errorf("%w expected(%d) actual(%d)", errShortSrtpMasterSalt, saltLen, masterSaltLen)
+ }
+
+ c = &Context{
+ srtpSSRCStates: map[uint32]*srtpSSRCState{},
+ srtcpSSRCStates: map[uint32]*srtcpSSRCState{},
+ }
+
+ switch profile {
+ case ProtectionProfileAeadAes128Gcm:
+ c.cipher, err = newSrtpCipherAeadAesGcm(masterKey, masterSalt)
+ case ProtectionProfileAes128CmHmacSha1_80:
+ c.cipher, err = newSrtpCipherAesCmHmacSha1(masterKey, masterSalt)
+ default:
+ return nil, fmt.Errorf("%w: %#v", errNoSuchSRTPProfile, profile)
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ for _, o := range append(
+ []ContextOption{ // Default options
+ SRTPNoReplayProtection(),
+ SRTCPNoReplayProtection(),
+ },
+ opts..., // User specified options
+ ) {
+ if errOpt := o(c); errOpt != nil {
+ return nil, errOpt
+ }
+ }
+
+ return c, nil
+}
+
+// https://tools.ietf.org/html/rfc3550#appendix-A.1
+func (s *srtpSSRCState) nextRolloverCount(sequenceNumber uint16) (uint32, func()) {
+ roc := s.rolloverCounter
+
+ switch {
+ case !s.rolloverHasProcessed:
+ case sequenceNumber == 0: // We exactly hit the rollover count
+ // Only update rolloverCounter if lastSequenceNumber is greater then maxROCDisorder
+ // otherwise we already incremented for disorder
+ if s.lastSequenceNumber > maxROCDisorder {
+ roc++
+ }
+ case s.lastSequenceNumber < maxROCDisorder &&
+ sequenceNumber > (maxSequenceNumber-maxROCDisorder):
+ // Our last sequence number incremented because we crossed 0, but then our current number was within maxROCDisorder of the max
+ // So we fell behind, drop to account for jitter
+ roc--
+ case sequenceNumber < maxROCDisorder &&
+ s.lastSequenceNumber > (maxSequenceNumber-maxROCDisorder):
+ // our current is within a maxROCDisorder of 0
+ // and our last sequence number was a high sequence number, increment to account for jitter
+ roc++
+ }
+ return roc, func() {
+ s.rolloverHasProcessed = true
+ s.lastSequenceNumber = sequenceNumber
+ s.rolloverCounter = roc
+ }
+}
+
+func (c *Context) getSRTPSSRCState(ssrc uint32) *srtpSSRCState {
+ s, ok := c.srtpSSRCStates[ssrc]
+ if ok {
+ return s
+ }
+
+ s = &srtpSSRCState{
+ ssrc: ssrc,
+ replayDetector: c.newSRTPReplayDetector(),
+ }
+ c.srtpSSRCStates[ssrc] = s
+ return s
+}
+
+func (c *Context) getSRTCPSSRCState(ssrc uint32) *srtcpSSRCState {
+ s, ok := c.srtcpSSRCStates[ssrc]
+ if ok {
+ return s
+ }
+
+ s = &srtcpSSRCState{
+ ssrc: ssrc,
+ replayDetector: c.newSRTCPReplayDetector(),
+ }
+ c.srtcpSSRCStates[ssrc] = s
+ return s
+}
+
+// ROC returns SRTP rollover counter value of specified SSRC.
+func (c *Context) ROC(ssrc uint32) (uint32, bool) {
+ s, ok := c.srtpSSRCStates[ssrc]
+ if !ok {
+ return 0, false
+ }
+ return s.rolloverCounter, true
+}
+
+// SetROC sets SRTP rollover counter value of specified SSRC.
+func (c *Context) SetROC(ssrc uint32, roc uint32) {
+ s := c.getSRTPSSRCState(ssrc)
+ s.rolloverCounter = roc
+}
+
+// Index returns SRTCP index value of specified SSRC.
+func (c *Context) Index(ssrc uint32) (uint32, bool) {
+ s, ok := c.srtcpSSRCStates[ssrc]
+ if !ok {
+ return 0, false
+ }
+ return s.srtcpIndex, true
+}
+
+// SetIndex sets SRTCP index value of specified SSRC.
+func (c *Context) SetIndex(ssrc uint32, index uint32) {
+ s := c.getSRTCPSSRCState(ssrc)
+ s.srtcpIndex = index % (maxSRTCPIndex + 1)
+}
diff --git a/vendor/github.com/pion/srtp/v2/errors.go b/vendor/github.com/pion/srtp/v2/errors.go
new file mode 100644
index 0000000..a702621
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/errors.go
@@ -0,0 +1,40 @@
+package srtp
+
+import (
+ "errors"
+ "fmt"
+)
+
+var (
+ errDuplicated = errors.New("duplicated packet")
+ errShortSrtpMasterKey = errors.New("SRTP master key is not long enough")
+ errShortSrtpMasterSalt = errors.New("SRTP master salt is not long enough")
+ errNoSuchSRTPProfile = errors.New("no such SRTP Profile")
+ errNonZeroKDRNotSupported = errors.New("indexOverKdr > 0 is not supported yet")
+ errExporterWrongLabel = errors.New("exporter called with wrong label")
+ errNoConfig = errors.New("no config provided")
+ errNoConn = errors.New("no conn provided")
+ errFailedToVerifyAuthTag = errors.New("failed to verify auth tag")
+ errTooShortRTCP = errors.New("packet is too short to be rtcp packet")
+ errPayloadDiffers = errors.New("payload differs")
+ errStartedChannelUsedIncorrectly = errors.New("started channel used incorrectly, should only be closed")
+
+ errStreamNotInited = errors.New("stream has not been inited, unable to close")
+ errStreamAlreadyClosed = errors.New("stream is already closed")
+ errStreamAlreadyInited = errors.New("stream is already inited")
+ errFailedTypeAssertion = errors.New("failed to cast child")
+)
+
+type errorDuplicated struct {
+ Proto string // srtp or srtcp
+ SSRC uint32
+ Index uint32 // sequence number or index
+}
+
+func (e *errorDuplicated) Error() string {
+ return fmt.Sprintf("%s ssrc=%d index=%d: %v", e.Proto, e.SSRC, e.Index, errDuplicated)
+}
+
+func (e *errorDuplicated) Unwrap() error {
+ return errDuplicated
+}
diff --git a/vendor/github.com/pion/srtp/v2/go.mod b/vendor/github.com/pion/srtp/v2/go.mod
new file mode 100644
index 0000000..bc04f63
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/go.mod
@@ -0,0 +1,11 @@
+module github.com/pion/srtp/v2
+
+go 1.14
+
+require (
+ github.com/pion/logging v0.2.2
+ github.com/pion/rtcp v1.2.6
+ github.com/pion/rtp v1.6.2
+ github.com/pion/transport v0.12.2
+ github.com/stretchr/testify v1.7.0
+)
diff --git a/vendor/github.com/pion/srtp/v2/go.sum b/vendor/github.com/pion/srtp/v2/go.sum
new file mode 100644
index 0000000..6066df9
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/go.sum
@@ -0,0 +1,34 @@
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
+github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
+github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
+github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
+github.com/pion/rtcp v1.2.6 h1:1zvwBbyd0TeEuuWftrd/4d++m+/kZSeiguxU61LFWpo=
+github.com/pion/rtcp v1.2.6/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0=
+github.com/pion/rtp v1.6.2 h1:iGBerLX6JiDjB9NXuaPzHyxHFG9JsIEdgwTC0lp5n/U=
+github.com/pion/rtp v1.6.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
+github.com/pion/transport v0.12.2 h1:WYEjhloRHt1R86LhUKjC5y+P52Y11/QqEUalvtzVoys=
+github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7 h1:3uJsdck53FDIpWwLeAXlia9p4C8j0BO2xZrqzKpL0D8=
+golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/vendor/github.com/pion/srtp/v2/key_derivation.go b/vendor/github.com/pion/srtp/v2/key_derivation.go
new file mode 100644
index 0000000..5bbf3aa
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/key_derivation.go
@@ -0,0 +1,63 @@
+package srtp
+
+import (
+ "crypto/aes"
+ "encoding/binary"
+)
+
+func aesCmKeyDerivation(label byte, masterKey, masterSalt []byte, indexOverKdr int, outLen int) ([]byte, error) {
+ if indexOverKdr != 0 {
+ // 24-bit "index DIV kdr" must be xored to prf input.
+ return nil, errNonZeroKDRNotSupported
+ }
+
+ // https://tools.ietf.org/html/rfc3711#appendix-B.3
+ // The input block for AES-CM is generated by exclusive-oring the master salt with the
+ // concatenation of the encryption key label 0x00 with (index DIV kdr),
+ // - index is 'rollover count' and DIV is 'divided by'
+
+ nMasterKey := len(masterKey)
+ nMasterSalt := len(masterSalt)
+
+ prfIn := make([]byte, nMasterKey)
+ copy(prfIn[:nMasterSalt], masterSalt)
+
+ prfIn[7] ^= label
+
+ // The resulting value is then AES encrypted using the master key to get the cipher key.
+ block, err := aes.NewCipher(masterKey)
+ if err != nil {
+ return nil, err
+ }
+
+ out := make([]byte, ((outLen+nMasterKey)/nMasterKey)*nMasterKey)
+ var i uint16
+ for n := 0; n < outLen; n += nMasterKey {
+ binary.BigEndian.PutUint16(prfIn[nMasterKey-2:], i)
+ block.Encrypt(out[n:n+nMasterKey], prfIn)
+ i++
+ }
+ return out[:outLen], nil
+}
+
+// Generate IV https://tools.ietf.org/html/rfc3711#section-4.1.1
+// where the 128-bit integer value IV SHALL be defined by the SSRC, the
+// SRTP packet index i, and the SRTP session salting key k_s, as below.
+// - ROC = a 32-bit unsigned rollover counter (ROC), which records how many
+// - times the 16-bit RTP sequence number has been reset to zero after
+// - passing through 65,535
+// i = 2^16 * ROC + SEQ
+// IV = (salt*2 ^ 16) | (ssrc*2 ^ 64) | (i*2 ^ 16)
+func generateCounter(sequenceNumber uint16, rolloverCounter uint32, ssrc uint32, sessionSalt []byte) []byte {
+ counter := make([]byte, 16)
+
+ binary.BigEndian.PutUint32(counter[4:], ssrc)
+ binary.BigEndian.PutUint32(counter[8:], rolloverCounter)
+ binary.BigEndian.PutUint32(counter[12:], uint32(sequenceNumber)<<16)
+
+ for i := range sessionSalt {
+ counter[i] ^= sessionSalt[i]
+ }
+
+ return counter
+}
diff --git a/vendor/github.com/pion/srtp/v2/keying.go b/vendor/github.com/pion/srtp/v2/keying.go
new file mode 100644
index 0000000..82fd4d9
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/keying.go
@@ -0,0 +1,54 @@
+package srtp
+
+const labelExtractorDtlsSrtp = "EXTRACTOR-dtls_srtp"
+
+// KeyingMaterialExporter allows package SRTP to extract keying material
+type KeyingMaterialExporter interface {
+ ExportKeyingMaterial(label string, context []byte, length int) ([]byte, error)
+}
+
+// ExtractSessionKeysFromDTLS allows setting the Config SessionKeys by
+// extracting them from DTLS. This behavior is defined in RFC5764:
+// https://tools.ietf.org/html/rfc5764
+func (c *Config) ExtractSessionKeysFromDTLS(exporter KeyingMaterialExporter, isClient bool) error {
+ keyLen, err := c.Profile.keyLen()
+ if err != nil {
+ return err
+ }
+
+ saltLen, err := c.Profile.saltLen()
+ if err != nil {
+ return err
+ }
+
+ keyingMaterial, err := exporter.ExportKeyingMaterial(labelExtractorDtlsSrtp, nil, (keyLen*2)+(saltLen*2))
+ if err != nil {
+ return err
+ }
+
+ offset := 0
+ clientWriteKey := append([]byte{}, keyingMaterial[offset:offset+keyLen]...)
+ offset += keyLen
+
+ serverWriteKey := append([]byte{}, keyingMaterial[offset:offset+keyLen]...)
+ offset += keyLen
+
+ clientWriteKey = append(clientWriteKey, keyingMaterial[offset:offset+saltLen]...)
+ offset += saltLen
+
+ serverWriteKey = append(serverWriteKey, keyingMaterial[offset:offset+saltLen]...)
+
+ if isClient {
+ c.Keys.LocalMasterKey = clientWriteKey[0:keyLen]
+ c.Keys.LocalMasterSalt = clientWriteKey[keyLen:]
+ c.Keys.RemoteMasterKey = serverWriteKey[0:keyLen]
+ c.Keys.RemoteMasterSalt = serverWriteKey[keyLen:]
+ return nil
+ }
+
+ c.Keys.LocalMasterKey = serverWriteKey[0:keyLen]
+ c.Keys.LocalMasterSalt = serverWriteKey[keyLen:]
+ c.Keys.RemoteMasterKey = clientWriteKey[0:keyLen]
+ c.Keys.RemoteMasterSalt = clientWriteKey[keyLen:]
+ return nil
+}
diff --git a/vendor/github.com/pion/srtp/v2/option.go b/vendor/github.com/pion/srtp/v2/option.go
new file mode 100644
index 0000000..d6159f1
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/option.go
@@ -0,0 +1,54 @@
+package srtp
+
+import (
+ "github.com/pion/transport/replaydetector"
+)
+
+// ContextOption represents option of Context using the functional options pattern.
+type ContextOption func(*Context) error
+
+// SRTPReplayProtection sets SRTP replay protection window size.
+func SRTPReplayProtection(windowSize uint) ContextOption { // nolint:golint
+ return func(c *Context) error {
+ c.newSRTPReplayDetector = func() replaydetector.ReplayDetector {
+ return replaydetector.WithWrap(windowSize, maxSequenceNumber)
+ }
+ return nil
+ }
+}
+
+// SRTCPReplayProtection sets SRTCP replay protection window size.
+func SRTCPReplayProtection(windowSize uint) ContextOption {
+ return func(c *Context) error {
+ c.newSRTCPReplayDetector = func() replaydetector.ReplayDetector {
+ return replaydetector.WithWrap(windowSize, maxSRTCPIndex)
+ }
+ return nil
+ }
+}
+
+// SRTPNoReplayProtection disables SRTP replay protection.
+func SRTPNoReplayProtection() ContextOption { // nolint:golint
+ return func(c *Context) error {
+ c.newSRTPReplayDetector = func() replaydetector.ReplayDetector {
+ return &nopReplayDetector{}
+ }
+ return nil
+ }
+}
+
+// SRTCPNoReplayProtection disables SRTCP replay protection.
+func SRTCPNoReplayProtection() ContextOption {
+ return func(c *Context) error {
+ c.newSRTCPReplayDetector = func() replaydetector.ReplayDetector {
+ return &nopReplayDetector{}
+ }
+ return nil
+ }
+}
+
+type nopReplayDetector struct{}
+
+func (s *nopReplayDetector) Check(uint64) (func(), bool) {
+ return func() {}, true
+}
diff --git a/vendor/github.com/pion/srtp/v2/protection_profile.go b/vendor/github.com/pion/srtp/v2/protection_profile.go
new file mode 100644
index 0000000..94476ad
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/protection_profile.go
@@ -0,0 +1,67 @@
+package srtp
+
+import "fmt"
+
+// ProtectionProfile specifies Cipher and AuthTag details, similar to TLS cipher suite
+type ProtectionProfile uint16
+
+// Supported protection profiles
+const (
+ ProtectionProfileAes128CmHmacSha1_80 ProtectionProfile = 0x0001
+ ProtectionProfileAeadAes128Gcm ProtectionProfile = 0x0007
+)
+
+func (p ProtectionProfile) keyLen() (int, error) {
+ switch p {
+ case ProtectionProfileAes128CmHmacSha1_80:
+ fallthrough
+ case ProtectionProfileAeadAes128Gcm:
+ return 16, nil
+ default:
+ return 0, fmt.Errorf("%w: %#v", errNoSuchSRTPProfile, p)
+ }
+}
+
+func (p ProtectionProfile) saltLen() (int, error) {
+ switch p {
+ case ProtectionProfileAes128CmHmacSha1_80:
+ return 14, nil
+ case ProtectionProfileAeadAes128Gcm:
+ return 12, nil
+ default:
+ return 0, fmt.Errorf("%w: %#v", errNoSuchSRTPProfile, p)
+ }
+}
+
+func (p ProtectionProfile) authTagLen() (int, error) {
+ switch p {
+ case ProtectionProfileAes128CmHmacSha1_80:
+ return (&srtpCipherAesCmHmacSha1{}).authTagLen(), nil
+ case ProtectionProfileAeadAes128Gcm:
+ return (&srtpCipherAeadAesGcm{}).authTagLen(), nil
+ default:
+ return 0, fmt.Errorf("%w: %#v", errNoSuchSRTPProfile, p)
+ }
+}
+
+func (p ProtectionProfile) aeadAuthTagLen() (int, error) {
+ switch p {
+ case ProtectionProfileAes128CmHmacSha1_80:
+ return (&srtpCipherAesCmHmacSha1{}).aeadAuthTagLen(), nil
+ case ProtectionProfileAeadAes128Gcm:
+ return (&srtpCipherAeadAesGcm{}).aeadAuthTagLen(), nil
+ default:
+ return 0, fmt.Errorf("%w: %#v", errNoSuchSRTPProfile, p)
+ }
+}
+
+func (p ProtectionProfile) authKeyLen() (int, error) {
+ switch p {
+ case ProtectionProfileAes128CmHmacSha1_80:
+ return 20, nil
+ case ProtectionProfileAeadAes128Gcm:
+ return 0, nil
+ default:
+ return 0, fmt.Errorf("%w: %#v", errNoSuchSRTPProfile, p)
+ }
+}
diff --git a/vendor/github.com/pion/srtp/v2/renovate.json b/vendor/github.com/pion/srtp/v2/renovate.json
new file mode 100644
index 0000000..4400fd9
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/renovate.json
@@ -0,0 +1,15 @@
+{
+ "extends": [
+ "config:base"
+ ],
+ "postUpdateOptions": [
+ "gomodTidy"
+ ],
+ "commitBody": "Generated by renovateBot",
+ "packageRules": [
+ {
+ "packagePatterns": ["^golang.org/x/"],
+ "schedule": ["on the first day of the month"]
+ }
+ ]
+}
diff --git a/vendor/github.com/pion/srtp/v2/session.go b/vendor/github.com/pion/srtp/v2/session.go
new file mode 100644
index 0000000..95520f7
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/session.go
@@ -0,0 +1,150 @@
+package srtp
+
+import (
+ "io"
+ "net"
+ "sync"
+
+ "github.com/pion/logging"
+ "github.com/pion/transport/packetio"
+)
+
+type streamSession interface {
+ Close() error
+ write([]byte) (int, error)
+ decrypt([]byte) error
+}
+
+type session struct {
+ localContextMutex sync.Mutex
+ localContext, remoteContext *Context
+ localOptions, remoteOptions []ContextOption
+
+ newStream chan readStream
+
+ started chan interface{}
+ closed chan interface{}
+
+ readStreamsClosed bool
+ readStreams map[uint32]readStream
+ readStreamsLock sync.Mutex
+
+ log logging.LeveledLogger
+ bufferFactory func(packetType packetio.BufferPacketType, ssrc uint32) io.ReadWriteCloser
+
+ nextConn net.Conn
+}
+
+// Config is used to configure a session.
+// You can provide either a KeyingMaterialExporter to export keys
+// or directly pass the keys themselves.
+// After a Config is passed to a session it must not be modified.
+type Config struct {
+ Keys SessionKeys
+ Profile ProtectionProfile
+ BufferFactory func(packetType packetio.BufferPacketType, ssrc uint32) io.ReadWriteCloser
+ LoggerFactory logging.LoggerFactory
+
+ // List of local/remote context options.
+ // ReplayProtection is enabled on remote context by default.
+ // Default replay protection window size is 64.
+ LocalOptions, RemoteOptions []ContextOption
+}
+
+// SessionKeys bundles the keys required to setup an SRTP session
+type SessionKeys struct {
+ LocalMasterKey []byte
+ LocalMasterSalt []byte
+ RemoteMasterKey []byte
+ RemoteMasterSalt []byte
+}
+
+func (s *session) getOrCreateReadStream(ssrc uint32, child streamSession, proto func() readStream) (readStream, bool) {
+ s.readStreamsLock.Lock()
+ defer s.readStreamsLock.Unlock()
+
+ if s.readStreamsClosed {
+ return nil, false
+ }
+
+ r, ok := s.readStreams[ssrc]
+ if ok {
+ return r, false
+ }
+
+ // Create the readStream.
+ r = proto()
+
+ if err := r.init(child, ssrc); err != nil {
+ return nil, false
+ }
+
+ s.readStreams[ssrc] = r
+ return r, true
+}
+
+func (s *session) removeReadStream(ssrc uint32) {
+ s.readStreamsLock.Lock()
+ defer s.readStreamsLock.Unlock()
+
+ if s.readStreamsClosed {
+ return
+ }
+
+ delete(s.readStreams, ssrc)
+}
+
+func (s *session) close() error {
+ if s.nextConn == nil {
+ return nil
+ } else if err := s.nextConn.Close(); err != nil {
+ return err
+ }
+
+ <-s.closed
+ return nil
+}
+
+func (s *session) start(localMasterKey, localMasterSalt, remoteMasterKey, remoteMasterSalt []byte, profile ProtectionProfile, child streamSession) error {
+ var err error
+ s.localContext, err = CreateContext(localMasterKey, localMasterSalt, profile, s.localOptions...)
+ if err != nil {
+ return err
+ }
+
+ s.remoteContext, err = CreateContext(remoteMasterKey, remoteMasterSalt, profile, s.remoteOptions...)
+ if err != nil {
+ return err
+ }
+
+ go func() {
+ defer func() {
+ close(s.newStream)
+
+ s.readStreamsLock.Lock()
+ s.readStreamsClosed = true
+ s.readStreamsLock.Unlock()
+ close(s.closed)
+ }()
+
+ b := make([]byte, 8192)
+ for {
+ var i int
+ i, err = s.nextConn.Read(b)
+ if err != nil {
+ if err != io.EOF {
+ s.log.Error(err.Error())
+ }
+ return
+ }
+
+ if err = child.decrypt(b[:i]); err != nil {
+ s.log.Info(err.Error())
+ }
+ }
+ }()
+
+ close(s.started)
+
+ return nil
+}
diff --git a/vendor/github.com/pion/srtp/v2/session_srtcp.go b/vendor/github.com/pion/srtp/v2/session_srtcp.go
new file mode 100644
index 0000000..a5fb656
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/session_srtcp.go
@@ -0,0 +1,180 @@
+package srtp
+
+import (
+ "net"
+ "time"
+
+ "github.com/pion/logging"
+ "github.com/pion/rtcp"
+)
+
+const defaultSessionSRTCPReplayProtectionWindow = 64
+
+// SessionSRTCP implements io.ReadWriteCloser and provides a bi-directional SRTCP session
+// SRTCP itself does not have a design like this, but it is common in most applications
+// for local/remote to each have their own keying material. This provides those patterns
+// instead of making everyone re-implement
+type SessionSRTCP struct {
+ session
+ writeStream *WriteStreamSRTCP
+}
+
+// NewSessionSRTCP creates a SRTCP session using conn as the underlying transport.
+func NewSessionSRTCP(conn net.Conn, config *Config) (*SessionSRTCP, error) { //nolint:dupl
+ if config == nil {
+ return nil, errNoConfig
+ } else if conn == nil {
+ return nil, errNoConn
+ }
+
+ loggerFactory := config.LoggerFactory
+ if loggerFactory == nil {
+ loggerFactory = logging.NewDefaultLoggerFactory()
+ }
+
+ localOpts := append(
+ []ContextOption{},
+ config.LocalOptions...,
+ )
+ remoteOpts := append(
+ []ContextOption{
+ // Default options
+ SRTCPReplayProtection(defaultSessionSRTCPReplayProtectionWindow),
+ },
+ config.RemoteOptions...,
+ )
+
+ s := &SessionSRTCP{
+ session: session{
+ nextConn: conn,
+ localOptions: localOpts,
+ remoteOptions: remoteOpts,
+ readStreams: map[uint32]readStream{},
+ newStream: make(chan readStream),
+ started: make(chan interface{}),
+ closed: make(chan interface{}),
+ bufferFactory: config.BufferFactory,
+ log: loggerFactory.NewLogger("srtp"),
+ },
+ }
+ s.writeStream = &WriteStreamSRTCP{s}
+
+ err := s.session.start(
+ config.Keys.LocalMasterKey, config.Keys.LocalMasterSalt,
+ config.Keys.RemoteMasterKey, config.Keys.RemoteMasterSalt,
+ config.Profile,
+ s,
+ )
+ if err != nil {
+ return nil, err
+ }
+ return s, nil
+}
+
+// OpenWriteStream returns the global write stream for the Session
+func (s *SessionSRTCP) OpenWriteStream() (*WriteStreamSRTCP, error) {
+ return s.writeStream, nil
+}
+
+// OpenReadStream opens a read stream for the given SSRC, it can be used
+// if you want a certain SSRC, but don't want to wait for AcceptStream
+func (s *SessionSRTCP) OpenReadStream(ssrc uint32) (*ReadStreamSRTCP, error) {
+ r, _ := s.session.getOrCreateReadStream(ssrc, s, newReadStreamSRTCP)
+
+ if readStream, ok := r.(*ReadStreamSRTCP); ok {
+ return readStream, nil
+ }
+ return nil, errFailedTypeAssertion
+}
+
+// AcceptStream returns a stream to handle RTCP for a single SSRC
+func (s *SessionSRTCP) AcceptStream() (*ReadStreamSRTCP, uint32, error) {
+ stream, ok := <-s.newStream
+ if !ok {
+ return nil, 0, errStreamAlreadyClosed
+ }
+
+ readStream, ok := stream.(*ReadStreamSRTCP)
+ if !ok {
+ return nil, 0, errFailedTypeAssertion
+ }
+
+ return readStream, stream.GetSSRC(), nil
+}
+
+// Close ends the session
+func (s *SessionSRTCP) Close() error {
+ return s.session.close()
+}
+
+// Private
+
+func (s *SessionSRTCP) write(buf []byte) (int, error) {
+ if _, ok := <-s.session.started; ok {
+ return 0, errStartedChannelUsedIncorrectly
+ }
+
+ s.session.localContextMutex.Lock()
+ encrypted, err := s.localContext.EncryptRTCP(nil, buf, nil)
+ s.session.localContextMutex.Unlock()
+
+ if err != nil {
+ return 0, err
+ }
+ return s.session.nextConn.Write(encrypted)
+}
+
+func (s *SessionSRTCP) setWriteDeadline(t time.Time) error {
+ return s.session.nextConn.SetWriteDeadline(t)
+}
+
+// create a list of Destination SSRCs
+// that's a superset of all Destinations in the slice.
+func destinationSSRC(pkts []rtcp.Packet) []uint32 {
+ ssrcSet := make(map[uint32]struct{})
+ for _, p := range pkts {
+ for _, ssrc := range p.DestinationSSRC() {
+ ssrcSet[ssrc] = struct{}{}
+ }
+ }
+
+ out := make([]uint32, 0, len(ssrcSet))
+ for ssrc := range ssrcSet {
+ out = append(out, ssrc)
+ }
+
+ return out
+}
+
+func (s *SessionSRTCP) decrypt(buf []byte) error {
+ decrypted, err := s.remoteContext.DecryptRTCP(buf, buf, nil)
+ if err != nil {
+ return err
+ }
+
+ pkt, err := rtcp.Unmarshal(decrypted)
+ if err != nil {
+ return err
+ }
+
+ for _, ssrc := range destinationSSRC(pkt) {
+ r, isNew := s.session.getOrCreateReadStream(ssrc, s, newReadStreamSRTCP)
+ if r == nil {
+ return nil // Session has been closed
+ } else if isNew {
+ s.session.newStream <- r // Notify AcceptStream
+ }
+
+ readStream, ok := r.(*ReadStreamSRTCP)
+ if !ok {
+ return errFailedTypeAssertion
+ }
+
+ _, err = readStream.write(decrypted)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/pion/srtp/v2/session_srtp.go b/vendor/github.com/pion/srtp/v2/session_srtp.go
new file mode 100644
index 0000000..dc815af
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/session_srtp.go
@@ -0,0 +1,171 @@
+package srtp
+
+import (
+ "net"
+ "time"
+
+ "github.com/pion/logging"
+ "github.com/pion/rtp"
+)
+
+const defaultSessionSRTPReplayProtectionWindow = 64
+
+// SessionSRTP implements io.ReadWriteCloser and provides a bi-directional SRTP session
+// SRTP itself does not have a design like this, but it is common in most applications
+// for local/remote to each have their own keying material. This provides those patterns
+// instead of making everyone re-implement
+type SessionSRTP struct {
+ session
+ writeStream *WriteStreamSRTP
+}
+
+// NewSessionSRTP creates a SRTP session using conn as the underlying transport.
+func NewSessionSRTP(conn net.Conn, config *Config) (*SessionSRTP, error) { //nolint:dupl
+ if config == nil {
+ return nil, errNoConfig
+ } else if conn == nil {
+ return nil, errNoConn
+ }
+
+ loggerFactory := config.LoggerFactory
+ if loggerFactory == nil {
+ loggerFactory = logging.NewDefaultLoggerFactory()
+ }
+
+ localOpts := append(
+ []ContextOption{},
+ config.LocalOptions...,
+ )
+ remoteOpts := append(
+ []ContextOption{
+ // Default options
+ SRTPReplayProtection(defaultSessionSRTPReplayProtectionWindow),
+ },
+ config.RemoteOptions...,
+ )
+
+ s := &SessionSRTP{
+ session: session{
+ nextConn: conn,
+ localOptions: localOpts,
+ remoteOptions: remoteOpts,
+ readStreams: map[uint32]readStream{},
+ newStream: make(chan readStream),
+ started: make(chan interface{}),
+ closed: make(chan interface{}),
+ bufferFactory: config.BufferFactory,
+ log: loggerFactory.NewLogger("srtp"),
+ },
+ }
+ s.writeStream = &WriteStreamSRTP{s}
+
+ err := s.session.start(
+ config.Keys.LocalMasterKey, config.Keys.LocalMasterSalt,
+ config.Keys.RemoteMasterKey, config.Keys.RemoteMasterSalt,
+ config.Profile,
+ s,
+ )
+ if err != nil {
+ return nil, err
+ }
+ return s, nil
+}
+
+// OpenWriteStream returns the global write stream for the Session
+func (s *SessionSRTP) OpenWriteStream() (*WriteStreamSRTP, error) {
+ return s.writeStream, nil
+}
+
+// OpenReadStream opens a read stream for the given SSRC, it can be used
+// if you want a certain SSRC, but don't want to wait for AcceptStream
+func (s *SessionSRTP) OpenReadStream(ssrc uint32) (*ReadStreamSRTP, error) {
+ r, _ := s.session.getOrCreateReadStream(ssrc, s, newReadStreamSRTP)
+
+ if readStream, ok := r.(*ReadStreamSRTP); ok {
+ return readStream, nil
+ }
+
+ return nil, errFailedTypeAssertion
+}
+
+// AcceptStream returns a stream to handle RTCP for a single SSRC
+func (s *SessionSRTP) AcceptStream() (*ReadStreamSRTP, uint32, error) {
+ stream, ok := <-s.newStream
+ if !ok {
+ return nil, 0, errStreamAlreadyClosed
+ }
+
+ readStream, ok := stream.(*ReadStreamSRTP)
+ if !ok {
+ return nil, 0, errFailedTypeAssertion
+ }
+
+ return readStream, stream.GetSSRC(), nil
+}
+
+// Close ends the session
+func (s *SessionSRTP) Close() error {
+ return s.session.close()
+}
+
+func (s *SessionSRTP) write(b []byte) (int, error) {
+ packet := &rtp.Packet{}
+
+ err := packet.Unmarshal(b)
+ if err != nil {
+ return 0, nil
+ }
+
+ return s.writeRTP(&packet.Header, packet.Payload)
+}
+
+func (s *SessionSRTP) writeRTP(header *rtp.Header, payload []byte) (int, error) {
+ if _, ok := <-s.session.started; ok {
+ return 0, errStartedChannelUsedIncorrectly
+ }
+
+ s.session.localContextMutex.Lock()
+ encrypted, err := s.localContext.encryptRTP(nil, header, payload)
+ s.session.localContextMutex.Unlock()
+
+ if err != nil {
+ return 0, err
+ }
+
+ return s.session.nextConn.Write(encrypted)
+}
+
+func (s *SessionSRTP) setWriteDeadline(t time.Time) error {
+ return s.session.nextConn.SetWriteDeadline(t)
+}
+
+func (s *SessionSRTP) decrypt(buf []byte) error {
+ h := &rtp.Header{}
+ if err := h.Unmarshal(buf); err != nil {
+ return err
+ }
+
+ r, isNew := s.session.getOrCreateReadStream(h.SSRC, s, newReadStreamSRTP)
+ if r == nil {
+ return nil // Session has been closed
+ } else if isNew {
+ s.session.newStream <- r // Notify AcceptStream
+ }
+
+ readStream, ok := r.(*ReadStreamSRTP)
+ if !ok {
+ return errFailedTypeAssertion
+ }
+
+ decrypted, err := s.remoteContext.decryptRTP(buf, buf, h)
+ if err != nil {
+ return err
+ }
+
+ _, err = readStream.write(decrypted)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/pion/srtp/v2/srtcp.go b/vendor/github.com/pion/srtp/v2/srtcp.go
new file mode 100644
index 0000000..dbf5125
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/srtcp.go
@@ -0,0 +1,77 @@
+package srtp
+
+import (
+ "encoding/binary"
+ "fmt"
+
+ "github.com/pion/rtcp"
+)
+
+const maxSRTCPIndex = 0x7FFFFFFF
+
+func (c *Context) decryptRTCP(dst, encrypted []byte) ([]byte, error) {
+ out := allocateIfMismatch(dst, encrypted)
+ tailOffset := len(encrypted) - (c.cipher.authTagLen() + srtcpIndexSize)
+
+ if tailOffset < 0 {
+ return nil, fmt.Errorf("%w: %d", errTooShortRTCP, len(encrypted))
+ } else if isEncrypted := encrypted[tailOffset] >> 7; isEncrypted == 0 {
+ return out, nil
+ }
+
+ index := c.cipher.getRTCPIndex(encrypted)
+ ssrc := binary.BigEndian.Uint32(encrypted[4:])
+
+ s := c.getSRTCPSSRCState(ssrc)
+ markAsValid, ok := s.replayDetector.Check(uint64(index))
+ if !ok {
+ return nil, &errorDuplicated{Proto: "srtcp", SSRC: ssrc, Index: index}
+ }
+
+ out, err := c.cipher.decryptRTCP(out, encrypted, index, ssrc)
+ if err != nil {
+ return nil, err
+ }
+
+ markAsValid()
+ return out, nil
+}
+
+// DecryptRTCP decrypts a buffer that contains a RTCP packet
+func (c *Context) DecryptRTCP(dst, encrypted []byte, header *rtcp.Header) ([]byte, error) {
+ if header == nil {
+ header = &rtcp.Header{}
+ }
+
+ if err := header.Unmarshal(encrypted); err != nil {
+ return nil, err
+ }
+
+ return c.decryptRTCP(dst, encrypted)
+}
+
+func (c *Context) encryptRTCP(dst, decrypted []byte) ([]byte, error) {
+ ssrc := binary.BigEndian.Uint32(decrypted[4:])
+ s := c.getSRTCPSSRCState(ssrc)
+
+ // We roll over early because MSB is used for marking as encrypted
+ s.srtcpIndex++
+ if s.srtcpIndex > maxSRTCPIndex {
+ s.srtcpIndex = 0
+ }
+
+ return c.cipher.encryptRTCP(dst, decrypted, s.srtcpIndex, ssrc)
+}
+
+// EncryptRTCP Encrypts a RTCP packet
+func (c *Context) EncryptRTCP(dst, decrypted []byte, header *rtcp.Header) ([]byte, error) {
+ if header == nil {
+ header = &rtcp.Header{}
+ }
+
+ if err := header.Unmarshal(decrypted); err != nil {
+ return nil, err
+ }
+
+ return c.encryptRTCP(dst, decrypted)
+}
diff --git a/vendor/github.com/pion/srtp/v2/srtp.go b/vendor/github.com/pion/srtp/v2/srtp.go
new file mode 100644
index 0000000..c4ed3ac
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/srtp.go
@@ -0,0 +1,68 @@
+// Package srtp implements Secure Real-time Transport Protocol
+package srtp
+
+import (
+ "github.com/pion/rtp"
+)
+
+func (c *Context) decryptRTP(dst, ciphertext []byte, header *rtp.Header) ([]byte, error) {
+ s := c.getSRTPSSRCState(header.SSRC)
+
+ markAsValid, ok := s.replayDetector.Check(uint64(header.SequenceNumber))
+ if !ok {
+ return nil, &errorDuplicated{
+ Proto: "srtp", SSRC: header.SSRC, Index: uint32(header.SequenceNumber),
+ }
+ }
+
+ dst = growBufferSize(dst, len(ciphertext)-c.cipher.authTagLen())
+ roc, updateROC := s.nextRolloverCount(header.SequenceNumber)
+
+ dst, err := c.cipher.decryptRTP(dst, ciphertext, header, roc)
+ if err != nil {
+ return nil, err
+ }
+
+ markAsValid()
+ updateROC()
+ return dst, nil
+}
+
+// DecryptRTP decrypts a RTP packet with an encrypted payload
+func (c *Context) DecryptRTP(dst, encrypted []byte, header *rtp.Header) ([]byte, error) {
+ if header == nil {
+ header = &rtp.Header{}
+ }
+
+ if err := header.Unmarshal(encrypted); err != nil {
+ return nil, err
+ }
+
+ return c.decryptRTP(dst, encrypted, header)
+}
+
+// EncryptRTP marshals and encrypts an RTP packet, writing to the dst buffer provided.
+// If the dst buffer does not have the capacity to hold `len(plaintext) + 10` bytes, a new one will be allocated and returned.
+// If a rtp.Header is provided, it will be Unmarshaled using the plaintext.
+func (c *Context) EncryptRTP(dst []byte, plaintext []byte, header *rtp.Header) ([]byte, error) {
+ if header == nil {
+ header = &rtp.Header{}
+ }
+
+ if err := header.Unmarshal(plaintext); err != nil {
+ return nil, err
+ }
+
+ return c.encryptRTP(dst, header, plaintext[header.PayloadOffset:])
+}
+
+// encryptRTP marshals and encrypts an RTP packet, writing to the dst buffer provided.
+// If the dst buffer does not have the capacity, a new one will be allocated and returned.
+// Similar to above but faster because it can avoid unmarshaling the header and marshaling the payload.
+func (c *Context) encryptRTP(dst []byte, header *rtp.Header, payload []byte) (ciphertext []byte, err error) {
+ s := c.getSRTPSSRCState(header.SSRC)
+ roc, updateROC := s.nextRolloverCount(header.SequenceNumber)
+ updateROC()
+
+ return c.cipher.encryptRTP(dst, header, payload, roc)
+}
diff --git a/vendor/github.com/pion/srtp/v2/srtp_cipher.go b/vendor/github.com/pion/srtp/v2/srtp_cipher.go
new file mode 100644
index 0000000..4c5cd88
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/srtp_cipher.go
@@ -0,0 +1,46 @@
+package srtp
+
+import "github.com/pion/rtp"
+
+// cipher represents a implementation of one
+// of the SRTP Specific ciphers
+type srtpCipher interface {
+ // authTagLen returns auth key length of the cipher.
+ // See the note below.
+ authTagLen() int
+ // aeadAuthTagLen returns AEAD auth key length of the cipher.
+ // See the note below.
+ aeadAuthTagLen() int
+ getRTCPIndex([]byte) uint32
+
+ encryptRTP([]byte, *rtp.Header, []byte, uint32) ([]byte, error)
+ encryptRTCP([]byte, []byte, uint32, uint32) ([]byte, error)
+
+ decryptRTP([]byte, []byte, *rtp.Header, uint32) ([]byte, error)
+ decryptRTCP([]byte, []byte, uint32, uint32) ([]byte, error)
+}
+
+/*
+NOTE: Auth tag and AEAD auth tag are placed at the different position in SRTCP
+
+In non-AEAD cipher, the authentication tag is placed *after* the ESRTCP word
+(Encrypted-flag and SRTCP index).
+
+> AES_128_CM_HMAC_SHA1_80
+> | RTCP Header | Encrypted payload |E| SRTCP Index | Auth tag |
+> ^ |----------|
+> | ^
+> | authTagLen=10
+> aeadAuthTagLen=0
+
+In AEAD cipher, the AEAD authentication tag is embedded in the ciphertext.
+It is *before* the ESRTCP word (Encrypted-flag and SRTCP index).
+
+> AEAD_AES_128_GCM
+> | RTCP Header | Encrypted payload | AEAD auth tag |E| SRTCP Index |
+> |---------------| ^
+> ^ authTagLen=0
+> aeadAuthTagLen=16
+
+See https://tools.ietf.org/html/rfc7714 for the full specifications.
+*/
diff --git a/vendor/github.com/pion/srtp/v2/srtp_cipher_aead_aes_gcm.go b/vendor/github.com/pion/srtp/v2/srtp_cipher_aead_aes_gcm.go
new file mode 100644
index 0000000..2720679
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/srtp_cipher_aead_aes_gcm.go
@@ -0,0 +1,198 @@
+package srtp
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "encoding/binary"
+
+ "github.com/pion/rtp"
+)
+
+const (
+ rtcpEncryptionFlag = 0x80
+)
+
+type srtpCipherAeadAesGcm struct {
+ srtpCipher, srtcpCipher cipher.AEAD
+
+ srtpSessionSalt, srtcpSessionSalt []byte
+}
+
+func newSrtpCipherAeadAesGcm(masterKey, masterSalt []byte) (*srtpCipherAeadAesGcm, error) {
+ s := &srtpCipherAeadAesGcm{}
+
+ srtpSessionKey, err := aesCmKeyDerivation(labelSRTPEncryption, masterKey, masterSalt, 0, len(masterKey))
+ if err != nil {
+ return nil, err
+ }
+
+ srtpBlock, err := aes.NewCipher(srtpSessionKey)
+ if err != nil {
+ return nil, err
+ }
+
+ s.srtpCipher, err = cipher.NewGCM(srtpBlock)
+ if err != nil {
+ return nil, err
+ }
+
+ srtcpSessionKey, err := aesCmKeyDerivation(labelSRTCPEncryption, masterKey, masterSalt, 0, len(masterKey))
+ if err != nil {
+ return nil, err
+ }
+
+ srtcpBlock, err := aes.NewCipher(srtcpSessionKey)
+ if err != nil {
+ return nil, err
+ }
+
+ s.srtcpCipher, err = cipher.NewGCM(srtcpBlock)
+ if err != nil {
+ return nil, err
+ }
+
+ if s.srtpSessionSalt, err = aesCmKeyDerivation(labelSRTPSalt, masterKey, masterSalt, 0, len(masterSalt)); err != nil {
+ return nil, err
+ } else if s.srtcpSessionSalt, err = aesCmKeyDerivation(labelSRTCPSalt, masterKey, masterSalt, 0, len(masterSalt)); err != nil {
+ return nil, err
+ }
+
+ return s, nil
+}
+
+func (s *srtpCipherAeadAesGcm) authTagLen() int {
+ return 0
+}
+
+func (s *srtpCipherAeadAesGcm) aeadAuthTagLen() int {
+ return 16
+}
+
+func (s *srtpCipherAeadAesGcm) encryptRTP(dst []byte, header *rtp.Header, payload []byte, roc uint32) (ciphertext []byte, err error) {
+ // Grow the given buffer to fit the output.
+ dst = growBufferSize(dst, header.MarshalSize()+len(payload)+s.aeadAuthTagLen())
+
+ hdr, err := header.Marshal()
+ if err != nil {
+ return nil, err
+ }
+
+ iv := s.rtpInitializationVector(header, roc)
+ nHdr := len(hdr)
+ s.srtpCipher.Seal(dst[nHdr:nHdr], iv, payload, hdr)
+ copy(dst[:nHdr], hdr)
+ return dst, nil
+}
+
+func (s *srtpCipherAeadAesGcm) decryptRTP(dst, ciphertext []byte, header *rtp.Header, roc uint32) ([]byte, error) {
+ // Grow the given buffer to fit the output.
+ nDst := len(ciphertext) - s.aeadAuthTagLen()
+ if nDst < 0 {
+ // Size of ciphertext is shorter than AEAD auth tag len.
+ return nil, errFailedToVerifyAuthTag
+ }
+ dst = growBufferSize(dst, nDst)
+
+ iv := s.rtpInitializationVector(header, roc)
+
+ if _, err := s.srtpCipher.Open(
+ dst[header.PayloadOffset:header.PayloadOffset], iv, ciphertext[header.PayloadOffset:], ciphertext[:header.PayloadOffset],
+ ); err != nil {
+ return nil, err
+ }
+
+ copy(dst[:header.PayloadOffset], ciphertext[:header.PayloadOffset])
+ return dst, nil
+}
+
+func (s *srtpCipherAeadAesGcm) encryptRTCP(dst, decrypted []byte, srtcpIndex uint32, ssrc uint32) ([]byte, error) {
+ aadPos := len(decrypted) + s.aeadAuthTagLen()
+ // Grow the given buffer to fit the output.
+ dst = growBufferSize(dst, aadPos+srtcpIndexSize)
+
+ iv := s.rtcpInitializationVector(srtcpIndex, ssrc)
+ aad := s.rtcpAdditionalAuthenticatedData(decrypted, srtcpIndex)
+
+ s.srtcpCipher.Seal(dst[8:8], iv, decrypted[8:], aad)
+
+ copy(dst[:8], decrypted[:8])
+ copy(dst[aadPos:aadPos+4], aad[8:12])
+ return dst, nil
+}
+
+func (s *srtpCipherAeadAesGcm) decryptRTCP(dst, encrypted []byte, srtcpIndex, ssrc uint32) ([]byte, error) {
+ aadPos := len(encrypted) - srtcpIndexSize
+ // Grow the given buffer to fit the output.
+ nDst := aadPos - s.aeadAuthTagLen()
+ if nDst < 0 {
+ // Size of ciphertext is shorter than AEAD auth tag len.
+ return nil, errFailedToVerifyAuthTag
+ }
+ dst = growBufferSize(dst, nDst)
+
+ iv := s.rtcpInitializationVector(srtcpIndex, ssrc)
+ aad := s.rtcpAdditionalAuthenticatedData(encrypted, srtcpIndex)
+
+ if _, err := s.srtcpCipher.Open(dst[8:8], iv, encrypted[8:aadPos], aad); err != nil {
+ return nil, err
+ }
+
+ copy(dst[:8], encrypted[:8])
+ return dst, nil
+}
+
+// The 12-octet IV used by AES-GCM SRTP is formed by first concatenating
+// 2 octets of zeroes, the 4-octet SSRC, the 4-octet rollover counter
+// (ROC), and the 2-octet sequence number (SEQ). The resulting 12-octet
+// value is then XORed to the 12-octet salt to form the 12-octet IV.
+//
+// https://tools.ietf.org/html/rfc7714#section-8.1
+func (s *srtpCipherAeadAesGcm) rtpInitializationVector(header *rtp.Header, roc uint32) []byte {
+ iv := make([]byte, 12)
+ binary.BigEndian.PutUint32(iv[2:], header.SSRC)
+ binary.BigEndian.PutUint32(iv[6:], roc)
+ binary.BigEndian.PutUint16(iv[10:], header.SequenceNumber)
+
+ for i := range iv {
+ iv[i] ^= s.srtpSessionSalt[i]
+ }
+ return iv
+}
+
+// The 12-octet IV used by AES-GCM SRTCP is formed by first
+// concatenating 2 octets of zeroes, the 4-octet SSRC identifier,
+// 2 octets of zeroes, a single "0" bit, and the 31-bit SRTCP index.
+// The resulting 12-octet value is then XORed to the 12-octet salt to
+// form the 12-octet IV.
+//
+// https://tools.ietf.org/html/rfc7714#section-9.1
+func (s *srtpCipherAeadAesGcm) rtcpInitializationVector(srtcpIndex uint32, ssrc uint32) []byte {
+ iv := make([]byte, 12)
+
+ binary.BigEndian.PutUint32(iv[2:], ssrc)
+ binary.BigEndian.PutUint32(iv[8:], srtcpIndex)
+
+ for i := range iv {
+ iv[i] ^= s.srtcpSessionSalt[i]
+ }
+ return iv
+}
+
+// In an SRTCP packet, a 1-bit Encryption flag is prepended to the
+// 31-bit SRTCP index to form a 32-bit value we shall call the
+// "ESRTCP word"
+//
+// https://tools.ietf.org/html/rfc7714#section-17
+func (s *srtpCipherAeadAesGcm) rtcpAdditionalAuthenticatedData(rtcpPacket []byte, srtcpIndex uint32) []byte {
+ aad := make([]byte, 12)
+
+ copy(aad, rtcpPacket[:8])
+ binary.BigEndian.PutUint32(aad[8:], srtcpIndex)
+ aad[8] |= rtcpEncryptionFlag
+
+ return aad
+}
+
+func (s *srtpCipherAeadAesGcm) getRTCPIndex(in []byte) uint32 {
+ return binary.BigEndian.Uint32(in[len(in)-4:]) &^ (rtcpEncryptionFlag << 24)
+}
diff --git a/vendor/github.com/pion/srtp/v2/srtp_cipher_aes_cm_hmac_sha1.go b/vendor/github.com/pion/srtp/v2/srtp_cipher_aes_cm_hmac_sha1.go
new file mode 100644
index 0000000..9d783d1
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/srtp_cipher_aes_cm_hmac_sha1.go
@@ -0,0 +1,228 @@
+package srtp
+
+import ( //nolint:gci
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/hmac"
+ "crypto/sha1" //nolint:gosec
+ "crypto/subtle"
+ "encoding/binary"
+ "hash"
+
+ "github.com/pion/rtp"
+)
+
+type srtpCipherAesCmHmacSha1 struct {
+ srtpSessionSalt []byte
+ srtpSessionAuth hash.Hash
+ srtpBlock cipher.Block
+
+ srtcpSessionSalt []byte
+ srtcpSessionAuth hash.Hash
+ srtcpBlock cipher.Block
+}
+
+func newSrtpCipherAesCmHmacSha1(masterKey, masterSalt []byte) (*srtpCipherAesCmHmacSha1, error) {
+ s := &srtpCipherAesCmHmacSha1{}
+ srtpSessionKey, err := aesCmKeyDerivation(labelSRTPEncryption, masterKey, masterSalt, 0, len(masterKey))
+ if err != nil {
+ return nil, err
+ } else if s.srtpBlock, err = aes.NewCipher(srtpSessionKey); err != nil {
+ return nil, err
+ }
+
+ srtcpSessionKey, err := aesCmKeyDerivation(labelSRTCPEncryption, masterKey, masterSalt, 0, len(masterKey))
+ if err != nil {
+ return nil, err
+ } else if s.srtcpBlock, err = aes.NewCipher(srtcpSessionKey); err != nil {
+ return nil, err
+ }
+
+ if s.srtpSessionSalt, err = aesCmKeyDerivation(labelSRTPSalt, masterKey, masterSalt, 0, len(masterSalt)); err != nil {
+ return nil, err
+ } else if s.srtcpSessionSalt, err = aesCmKeyDerivation(labelSRTCPSalt, masterKey, masterSalt, 0, len(masterSalt)); err != nil {
+ return nil, err
+ }
+
+ authKeyLen, err := ProtectionProfileAes128CmHmacSha1_80.authKeyLen()
+ if err != nil {
+ return nil, err
+ }
+
+ srtpSessionAuthTag, err := aesCmKeyDerivation(labelSRTPAuthenticationTag, masterKey, masterSalt, 0, authKeyLen)
+ if err != nil {
+ return nil, err
+ }
+
+ srtcpSessionAuthTag, err := aesCmKeyDerivation(labelSRTCPAuthenticationTag, masterKey, masterSalt, 0, authKeyLen)
+ if err != nil {
+ return nil, err
+ }
+
+ s.srtcpSessionAuth = hmac.New(sha1.New, srtcpSessionAuthTag)
+ s.srtpSessionAuth = hmac.New(sha1.New, srtpSessionAuthTag)
+ return s, nil
+}
+
+func (s *srtpCipherAesCmHmacSha1) authTagLen() int {
+ return 10
+}
+
+func (s *srtpCipherAesCmHmacSha1) aeadAuthTagLen() int {
+ return 0
+}
+
+func (s *srtpCipherAesCmHmacSha1) encryptRTP(dst []byte, header *rtp.Header, payload []byte, roc uint32) (ciphertext []byte, err error) {
+ // Grow the given buffer to fit the output.
+ dst = growBufferSize(dst, header.MarshalSize()+len(payload)+s.authTagLen())
+
+ // Copy the header unencrypted.
+ n, err := header.MarshalTo(dst)
+ if err != nil {
+ return nil, err
+ }
+
+ // Encrypt the payload
+ counter := generateCounter(header.SequenceNumber, roc, header.SSRC, s.srtpSessionSalt)
+ stream := cipher.NewCTR(s.srtpBlock, counter)
+ stream.XORKeyStream(dst[n:], payload)
+ n += len(payload)
+
+ // Generate the auth tag.
+ authTag, err := s.generateSrtpAuthTag(dst[:n], roc)
+ if err != nil {
+ return nil, err
+ }
+
+ // Write the auth tag to the dest.
+ copy(dst[n:], authTag)
+
+ return dst, nil
+}
+
+func (s *srtpCipherAesCmHmacSha1) decryptRTP(dst, ciphertext []byte, header *rtp.Header, roc uint32) ([]byte, error) {
+ // Split the auth tag and the cipher text into two parts.
+ actualTag := ciphertext[len(ciphertext)-s.authTagLen():]
+ ciphertext = ciphertext[:len(ciphertext)-s.authTagLen()]
+
+ // Generate the auth tag we expect to see from the ciphertext.
+ expectedTag, err := s.generateSrtpAuthTag(ciphertext, roc)
+ if err != nil {
+ return nil, err
+ }
+
+ // See if the auth tag actually matches.
+ // We use a constant time comparison to prevent timing attacks.
+ if subtle.ConstantTimeCompare(actualTag, expectedTag) != 1 {
+ return nil, errFailedToVerifyAuthTag
+ }
+
+ // Write the plaintext header to the destination buffer.
+ copy(dst, ciphertext[:header.PayloadOffset])
+
+ // Decrypt the ciphertext for the payload.
+ counter := generateCounter(header.SequenceNumber, roc, header.SSRC, s.srtpSessionSalt)
+ stream := cipher.NewCTR(s.srtpBlock, counter)
+ stream.XORKeyStream(dst[header.PayloadOffset:], ciphertext[header.PayloadOffset:])
+ return dst, nil
+}
+
+func (s *srtpCipherAesCmHmacSha1) encryptRTCP(dst, decrypted []byte, srtcpIndex uint32, ssrc uint32) ([]byte, error) {
+ dst = allocateIfMismatch(dst, decrypted)
+
+ // Encrypt everything after header
+ stream := cipher.NewCTR(s.srtcpBlock, generateCounter(uint16(srtcpIndex&0xffff), srtcpIndex>>16, ssrc, s.srtcpSessionSalt))
+ stream.XORKeyStream(dst[8:], dst[8:])
+
+ // Add SRTCP Index and set Encryption bit
+ dst = append(dst, make([]byte, 4)...)
+ binary.BigEndian.PutUint32(dst[len(dst)-4:], srtcpIndex)
+ dst[len(dst)-4] |= 0x80
+
+ authTag, err := s.generateSrtcpAuthTag(dst)
+ if err != nil {
+ return nil, err
+ }
+ return append(dst, authTag...), nil
+}
+
+func (s *srtpCipherAesCmHmacSha1) decryptRTCP(out, encrypted []byte, index, ssrc uint32) ([]byte, error) {
+ tailOffset := len(encrypted) - (s.authTagLen() + srtcpIndexSize)
+ out = out[0:tailOffset]
+
+ expectedTag, err := s.generateSrtcpAuthTag(encrypted[:len(encrypted)-s.authTagLen()])
+ if err != nil {
+ return nil, err
+ }
+
+ actualTag := encrypted[len(encrypted)-s.authTagLen():]
+ if subtle.ConstantTimeCompare(actualTag, expectedTag) != 1 {
+ return nil, errFailedToVerifyAuthTag
+ }
+
+ stream := cipher.NewCTR(s.srtcpBlock, generateCounter(uint16(index&0xffff), index>>16, ssrc, s.srtcpSessionSalt))
+ stream.XORKeyStream(out[8:], out[8:])
+
+ return out, nil
+}
+
+func (s *srtpCipherAesCmHmacSha1) generateSrtpAuthTag(buf []byte, roc uint32) ([]byte, error) {
+ // https://tools.ietf.org/html/rfc3711#section-4.2
+ // In the case of SRTP, M SHALL consist of the Authenticated
+ // Portion of the packet (as specified in Figure 1) concatenated with
+ // the ROC, M = Authenticated Portion || ROC;
+ //
+ // The pre-defined authentication transform for SRTP is HMAC-SHA1
+ // [RFC2104]. With HMAC-SHA1, the SRTP_PREFIX_LENGTH (Figure 3) SHALL
+ // be 0. For SRTP (respectively SRTCP), the HMAC SHALL be applied to
+ // the session authentication key and M as specified above, i.e.,
+ // HMAC(k_a, M). The HMAC output SHALL then be truncated to the n_tag
+ // left-most bits.
+ // - Authenticated portion of the packet is everything BEFORE MKI
+ // - k_a is the session message authentication key
+ // - n_tag is the bit-length of the output authentication tag
+ s.srtpSessionAuth.Reset()
+
+ if _, err := s.srtpSessionAuth.Write(buf); err != nil {
+ return nil, err
+ }
+
+ // For SRTP only, we need to hash the rollover counter as well.
+ rocRaw := [4]byte{}
+ binary.BigEndian.PutUint32(rocRaw[:], roc)
+
+ _, err := s.srtpSessionAuth.Write(rocRaw[:])
+ if err != nil {
+ return nil, err
+ }
+
+ // Truncate the hash to the first 10 bytes.
+ return s.srtpSessionAuth.Sum(nil)[0:s.authTagLen()], nil
+}
+
+func (s *srtpCipherAesCmHmacSha1) generateSrtcpAuthTag(buf []byte) ([]byte, error) {
+ // https://tools.ietf.org/html/rfc3711#section-4.2
+ //
+ // The pre-defined authentication transform for SRTP is HMAC-SHA1
+ // [RFC2104]. With HMAC-SHA1, the SRTP_PREFIX_LENGTH (Figure 3) SHALL
+ // be 0. For SRTP (respectively SRTCP), the HMAC SHALL be applied to
+ // the session authentication key and M as specified above, i.e.,
+ // HMAC(k_a, M). The HMAC output SHALL then be truncated to the n_tag
+ // left-most bits.
+ // - Authenticated portion of the packet is everything BEFORE MKI
+ // - k_a is the session message authentication key
+ // - n_tag is the bit-length of the output authentication tag
+ s.srtcpSessionAuth.Reset()
+
+ if _, err := s.srtcpSessionAuth.Write(buf); err != nil {
+ return nil, err
+ }
+
+ return s.srtcpSessionAuth.Sum(nil)[0:s.authTagLen()], nil
+}
+
+func (s *srtpCipherAesCmHmacSha1) getRTCPIndex(in []byte) uint32 {
+ tailOffset := len(in) - (s.authTagLen() + srtcpIndexSize)
+ srtcpIndexBuffer := in[tailOffset : tailOffset+srtcpIndexSize]
+ return binary.BigEndian.Uint32(srtcpIndexBuffer) &^ (1 << 31)
+}
diff --git a/vendor/github.com/pion/srtp/v2/stream.go b/vendor/github.com/pion/srtp/v2/stream.go
new file mode 100644
index 0000000..7b7a0cf
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/stream.go
@@ -0,0 +1,8 @@
+package srtp
+
+type readStream interface {
+ init(child streamSession, ssrc uint32) error
+
+ Read(buf []byte) (int, error)
+ GetSSRC() uint32
+}
diff --git a/vendor/github.com/pion/srtp/v2/stream_srtcp.go b/vendor/github.com/pion/srtp/v2/stream_srtcp.go
new file mode 100644
index 0000000..e335937
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/stream_srtcp.go
@@ -0,0 +1,157 @@
+package srtp
+
+import (
+ "errors"
+ "io"
+ "sync"
+ "time"
+
+ "github.com/pion/rtcp"
+ "github.com/pion/transport/packetio"
+)
+
+// Limit the buffer size to 100KB
+const srtcpBufferSize = 100 * 1000
+
+// ReadStreamSRTCP handles decryption for a single RTCP SSRC
+type ReadStreamSRTCP struct {
+ mu sync.Mutex
+
+ isInited bool
+ isClosed chan bool
+
+ session *SessionSRTCP
+ ssrc uint32
+
+ buffer io.ReadWriteCloser
+}
+
+func (r *ReadStreamSRTCP) write(buf []byte) (n int, err error) {
+ n, err = r.buffer.Write(buf)
+
+ if errors.Is(err, packetio.ErrFull) {
+ // Silently drop data when the buffer is full.
+ return len(buf), nil
+ }
+
+ return n, err
+}
+
+// Used by getOrCreateReadStream
+func newReadStreamSRTCP() readStream {
+ return &ReadStreamSRTCP{}
+}
+
+// ReadRTCP reads and decrypts full RTCP packet and its header from the nextConn
+func (r *ReadStreamSRTCP) ReadRTCP(buf []byte) (int, *rtcp.Header, error) {
+ n, err := r.Read(buf)
+ if err != nil {
+ return 0, nil, err
+ }
+
+ header := &rtcp.Header{}
+ err = header.Unmarshal(buf[:n])
+ if err != nil {
+ return 0, nil, err
+ }
+
+ return n, header, nil
+}
+
+// Read reads and decrypts full RTCP packet from the nextConn
+func (r *ReadStreamSRTCP) Read(buf []byte) (int, error) {
+ return r.buffer.Read(buf)
+}
+
+// SetReadDeadline sets the deadline for the Read operation.
+// Setting to zero means no deadline.
+func (r *ReadStreamSRTCP) SetReadDeadline(t time.Time) error {
+ if b, ok := r.buffer.(interface {
+ SetReadDeadline(time.Time) error
+ }); ok {
+ return b.SetReadDeadline(t)
+ }
+ return nil
+}
+
+// Close removes the ReadStream from the session and cleans up any associated state
+func (r *ReadStreamSRTCP) Close() error {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+
+ if !r.isInited {
+ return errStreamNotInited
+ }
+
+ select {
+ case <-r.isClosed:
+ return errStreamAlreadyClosed
+ default:
+ err := r.buffer.Close()
+ if err != nil {
+ return err
+ }
+
+ r.session.removeReadStream(r.ssrc)
+ return nil
+ }
+}
+
+func (r *ReadStreamSRTCP) init(child streamSession, ssrc uint32) error {
+ sessionSRTCP, ok := child.(*SessionSRTCP)
+
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if !ok {
+ return errFailedTypeAssertion
+ } else if r.isInited {
+ return errStreamAlreadyInited
+ }
+
+ r.session = sessionSRTCP
+ r.ssrc = ssrc
+ r.isInited = true
+ r.isClosed = make(chan bool)
+
+ if r.session.bufferFactory != nil {
+ r.buffer = r.session.bufferFactory(packetio.RTCPBufferPacket, ssrc)
+ } else {
+ // Create a buffer and limit it to 100KB
+ buff := packetio.NewBuffer()
+ buff.SetLimitSize(srtcpBufferSize)
+ r.buffer = buff
+ }
+
+ return nil
+}
+
+// GetSSRC returns the SSRC we are demuxing for
+func (r *ReadStreamSRTCP) GetSSRC() uint32 {
+ return r.ssrc
+}
+
+// WriteStreamSRTCP is stream for a single Session that is used to encrypt RTCP
+type WriteStreamSRTCP struct {
+ session *SessionSRTCP
+}
+
+// WriteRTCP encrypts a RTCP header and its payload to the nextConn
+func (w *WriteStreamSRTCP) WriteRTCP(header *rtcp.Header, payload []byte) (int, error) {
+ headerRaw, err := header.Marshal()
+ if err != nil {
+ return 0, err
+ }
+
+ return w.session.write(append(headerRaw, payload...))
+}
+
+// Write encrypts and writes a full RTCP packets to the nextConn
+func (w *WriteStreamSRTCP) Write(b []byte) (int, error) {
+ return w.session.write(b)
+}
+
+// SetWriteDeadline sets the deadline for the Write operation.
+// Setting to zero means no deadline.
+func (w *WriteStreamSRTCP) SetWriteDeadline(t time.Time) error {
+ return w.session.setWriteDeadline(t)
+}
diff --git a/vendor/github.com/pion/srtp/v2/stream_srtp.go b/vendor/github.com/pion/srtp/v2/stream_srtp.go
new file mode 100644
index 0000000..c391adb
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/stream_srtp.go
@@ -0,0 +1,154 @@
+package srtp
+
+import (
+ "errors"
+ "io"
+ "sync"
+ "time"
+
+ "github.com/pion/rtp"
+ "github.com/pion/transport/packetio"
+)
+
+// Limit the buffer size to 1MB
+const srtpBufferSize = 1000 * 1000
+
+// ReadStreamSRTP handles decryption for a single RTP SSRC
+type ReadStreamSRTP struct {
+ mu sync.Mutex
+
+ isInited bool
+ isClosed chan bool
+
+ session *SessionSRTP
+ ssrc uint32
+
+ buffer io.ReadWriteCloser
+}
+
+// Used by getOrCreateReadStream
+func newReadStreamSRTP() readStream {
+ return &ReadStreamSRTP{}
+}
+
+func (r *ReadStreamSRTP) init(child streamSession, ssrc uint32) error {
+ sessionSRTP, ok := child.(*SessionSRTP)
+
+ r.mu.Lock()
+ defer r.mu.Unlock()
+
+ if !ok {
+ return errFailedTypeAssertion
+ } else if r.isInited {
+ return errStreamAlreadyInited
+ }
+
+ r.session = sessionSRTP
+ r.ssrc = ssrc
+ r.isInited = true
+ r.isClosed = make(chan bool)
+
+ // Create a buffer with a 1MB limit
+ if r.session.bufferFactory != nil {
+ r.buffer = r.session.bufferFactory(packetio.RTPBufferPacket, ssrc)
+ } else {
+ buff := packetio.NewBuffer()
+ buff.SetLimitSize(srtpBufferSize)
+ r.buffer = buff
+ }
+
+ return nil
+}
+
+func (r *ReadStreamSRTP) write(buf []byte) (n int, err error) {
+ n, err = r.buffer.Write(buf)
+
+ if errors.Is(err, packetio.ErrFull) {
+ // Silently drop data when the buffer is full.
+ return len(buf), nil
+ }
+
+ return n, err
+}
+
+// Read reads and decrypts full RTP packet from the nextConn
+func (r *ReadStreamSRTP) Read(buf []byte) (int, error) {
+ return r.buffer.Read(buf)
+}
+
+// ReadRTP reads and decrypts full RTP packet and its header from the nextConn
+func (r *ReadStreamSRTP) ReadRTP(buf []byte) (int, *rtp.Header, error) {
+ n, err := r.Read(buf)
+ if err != nil {
+ return 0, nil, err
+ }
+
+ header := &rtp.Header{}
+
+ err = header.Unmarshal(buf[:n])
+ if err != nil {
+ return 0, nil, err
+ }
+
+ return n, header, nil
+}
+
+// SetReadDeadline sets the deadline for the Read operation.
+// Setting to zero means no deadline.
+func (r *ReadStreamSRTP) SetReadDeadline(t time.Time) error {
+ if b, ok := r.buffer.(interface {
+ SetReadDeadline(time.Time) error
+ }); ok {
+ return b.SetReadDeadline(t)
+ }
+ return nil
+}
+
+// Close removes the ReadStream from the session and cleans up any associated state
+func (r *ReadStreamSRTP) Close() error {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+
+ if !r.isInited {
+ return errStreamNotInited
+ }
+
+ select {
+ case <-r.isClosed:
+ return errStreamAlreadyClosed
+ default:
+ err := r.buffer.Close()
+ if err != nil {
+ return err
+ }
+
+ r.session.removeReadStream(r.ssrc)
+ return nil
+ }
+}
+
+// GetSSRC returns the SSRC we are demuxing for
+func (r *ReadStreamSRTP) GetSSRC() uint32 {
+ return r.ssrc
+}
+
+// WriteStreamSRTP is stream for a single Session that is used to encrypt RTP
+type WriteStreamSRTP struct {
+ session *SessionSRTP
+}
+
+// WriteRTP encrypts a RTP packet and writes to the connection
+func (w *WriteStreamSRTP) WriteRTP(header *rtp.Header, payload []byte) (int, error) {
+ return w.session.writeRTP(header, payload)
+}
+
+// Write encrypts and writes a full RTP packets to the nextConn
+func (w *WriteStreamSRTP) Write(b []byte) (int, error) {
+ return w.session.write(b)
+}
+
+// SetWriteDeadline sets the deadline for the Write operation.
+// Setting to zero means no deadline.
+func (w *WriteStreamSRTP) SetWriteDeadline(t time.Time) error {
+ return w.session.setWriteDeadline(t)
+}
diff --git a/vendor/github.com/pion/srtp/v2/util.go b/vendor/github.com/pion/srtp/v2/util.go
new file mode 100644
index 0000000..1ae34a6
--- /dev/null
+++ b/vendor/github.com/pion/srtp/v2/util.go
@@ -0,0 +1,33 @@
+package srtp
+
+import "bytes"
+
+// Grow the buffer size to the given number of bytes.
+func growBufferSize(buf []byte, size int) []byte {
+ if size <= cap(buf) {
+ return buf[:size]
+ }
+
+ buf2 := make([]byte, size)
+ copy(buf2, buf)
+ return buf2
+}
+
+// Check if buffers match, if not allocate a new buffer and return it
+func allocateIfMismatch(dst, src []byte) []byte {
+ if dst == nil {
+ dst = make([]byte, len(src))
+ copy(dst, src)
+ } else if !bytes.Equal(dst, src) { // bytes.Equal returns on ref equality, no optimization needed
+ extraNeeded := len(src) - len(dst)
+ if extraNeeded > 0 {
+ dst = append(dst, make([]byte, extraNeeded)...)
+ } else if extraNeeded < 0 {
+ dst = dst[:len(dst)+extraNeeded]
+ }
+
+ copy(dst, src)
+ }
+
+ return dst
+}