package srtp
import (
"encoding/binary"
"fmt"
"github.com/pion/rtp"
)
func (c *Context ) decryptRTP (dst , ciphertext []byte , header *rtp .Header , headerLen int ) ([]byte , error ) {
authTagLen , err := c .cipher .AuthTagRTPLen ()
if err != nil {
return nil , err
}
aeadAuthTagLen , err := c .cipher .AEADAuthTagLen ()
if err != nil {
return nil , err
}
mkiLen := len (c .sendMKI )
var hasRocInPacket bool
hasRocInPacket , authTagLen = c .hasROCInPacket (header , authTagLen )
if len (ciphertext ) < (headerLen + aeadAuthTagLen + mkiLen + authTagLen ) {
return nil , fmt .Errorf ("%w: %d" , errTooShortRTP , len (ciphertext ))
}
ssrcState := c .getSRTPSSRCState (header .SSRC )
var roc uint32
var diff int64
var index uint64
if !hasRocInPacket {
roc , diff , _ = ssrcState .nextRolloverCount (header .SequenceNumber )
index = (uint64 (roc ) << 16 ) | uint64 (header .SequenceNumber )
} else {
roc = binary .BigEndian .Uint32 (ciphertext [len (ciphertext )-authTagLen :])
index = (uint64 (roc ) << 16 ) | uint64 (header .SequenceNumber )
diff = int64 (ssrcState .index ) - int64 (index )
}
markAsValid , ok := ssrcState .replayDetector .Check (index )
if !ok {
return nil , &duplicatedError {
Proto : "srtp" , SSRC : header .SSRC , Index : uint32 (header .SequenceNumber ),
}
}
cipher := c .cipher
if len (c .mkis ) > 0 {
actualMKI := ciphertext [len (ciphertext )-mkiLen -authTagLen : len (ciphertext )-authTagLen ]
cipher , ok = c .mkis [string (actualMKI )]
if !ok {
return nil , ErrMKINotFound
}
}
dst = growBufferSize (dst , len (ciphertext )-authTagLen -len (c .sendMKI ))
dst , err = cipher .decryptRTP (dst , ciphertext , header , headerLen , roc , hasRocInPacket )
if err != nil {
return nil , err
}
markAsValid ()
ssrcState .updateRolloverCount (header .SequenceNumber , diff , hasRocInPacket , roc )
return dst , nil
}
func (c *Context ) DecryptRTP (dst , encrypted []byte , header *rtp .Header ) ([]byte , error ) {
if header == nil {
header = &rtp .Header {}
}
headerLen , err := header .Unmarshal (encrypted )
if err != nil {
return nil , err
}
return c .decryptRTP (dst , encrypted , header , headerLen )
}
func (c *Context ) EncryptRTP (dst []byte , plaintext []byte , header *rtp .Header ) ([]byte , error ) {
if header == nil {
header = &rtp .Header {}
}
headerLen , err := header .Unmarshal (plaintext )
if err != nil {
return nil , err
}
return c .encryptRTP (dst , header , headerLen , plaintext )
}
func (c *Context ) encryptRTP (dst []byte , header *rtp .Header , headerLen int , plaintext []byte ,
) (ciphertext []byte , err error ) {
s := c .getSRTPSSRCState (header .SSRC )
roc , diff , ovf := s .nextRolloverCount (header .SequenceNumber )
if ovf {
return nil , errExceededMaxPackets
}
s .updateRolloverCount (header .SequenceNumber , diff , false , 0 )
rocInPacket := false
if c .rccMode != RCCModeNone && header .SequenceNumber %c .rocTransmitRate == 0 {
rocInPacket = true
}
return c .cipher .encryptRTP (dst , header , headerLen , plaintext , roc , rocInPacket )
}
func (c *Context ) hasROCInPacket (header *rtp .Header , authTagLen int ) (bool , int ) {
hasRocInPacket := false
switch c .rccMode {
case RCCMode2 :
hasRocInPacket = header .SequenceNumber %c .rocTransmitRate == 0
case RCCMode3 :
hasRocInPacket = header .SequenceNumber %c .rocTransmitRate == 0
if hasRocInPacket {
authTagLen = 4
}
default :
}
return hasRocInPacket , authTagLen
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .