// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

package srtp

import ( //nolint:gci
	
	
	
	 //nolint:gosec
	
	
	

	
)

type srtpCipherAesCmHmacSha1 struct {
	protectionProfileWithArgs

	srtpSessionSalt []byte
	srtpSessionAuth hash.Hash
	srtpBlock       cipher.Block
	srtpEncrypted   bool

	srtcpSessionSalt []byte
	srtcpSessionAuth hash.Hash
	srtcpBlock       cipher.Block
	srtcpEncrypted   bool

	mki []byte
}

//nolint:cyclop
func newSrtpCipherAesCmHmacSha1(
	 protectionProfileWithArgs,
	, ,  []byte,
	,  bool,
) (*srtpCipherAesCmHmacSha1, error) {
	switch .ProtectionProfile {
	case ProtectionProfileNullHmacSha1_80, ProtectionProfileNullHmacSha1_32:
		 = false
		 = false
	default:
	}

	 := &srtpCipherAesCmHmacSha1{
		protectionProfileWithArgs: ,
		srtpEncrypted:             ,
		srtcpEncrypted:            ,
	}

	,  := aesCmKeyDerivation(labelSRTPEncryption, , , 0, len())
	if  != nil {
		return nil, 
	} else if .srtpBlock,  = aes.NewCipher();  != nil {
		return nil, 
	}

	,  := aesCmKeyDerivation(labelSRTCPEncryption, , , 0, len())
	if  != nil {
		return nil, 
	} else if .srtcpBlock,  = aes.NewCipher();  != nil {
		return nil, 
	}

	if .srtpSessionSalt,  = aesCmKeyDerivation(
		labelSRTPSalt, , , 0, len(),
	);  != nil {
		return nil, 
	} else if .srtcpSessionSalt,  = aesCmKeyDerivation(
		labelSRTCPSalt, , , 0, len(),
	);  != nil {
		return nil, 
	}

	,  := .AuthKeyLen()
	if  != nil {
		return nil, 
	}

	,  := aesCmKeyDerivation(labelSRTPAuthenticationTag, , , 0, )
	if  != nil {
		return nil, 
	}

	,  := aesCmKeyDerivation(labelSRTCPAuthenticationTag, , , 0, )
	if  != nil {
		return nil, 
	}

	.srtcpSessionAuth = hmac.New(sha1.New, )
	.srtpSessionAuth = hmac.New(sha1.New, )

	 := len()
	if  > 0 {
		.mki = make([]byte, )
		copy(.mki, )
	}

	return , nil
}

func ( *srtpCipherAesCmHmacSha1) (
	 []byte,
	 *rtp.Header,
	 int,
	 []byte,
	 uint32,
	 bool,
) ( []byte,  error) {
	 := [:]
	 := len()

	// Grow the given buffer to fit the output.
	,  := .AuthTagRTPLen()
	if  != nil {
		return nil, 
	}
	 = growBufferSize(, ++len(.mki)+)
	 := isSameBuffer(, )

	// Copy the header unencrypted.
	if ! {
		copy(, [:])
	}

	// Encrypt the payload
	if .srtpEncrypted {
		 := generateCounter(.SequenceNumber, , .SSRC, .srtpSessionSalt)
		if  = xorBytesCTR(.srtpBlock, [:], [:], );  != nil {
			return nil, 
		}
	} else if ! {
		copy([:], )
	}
	 :=  + 

	// Generate the auth tag.
	,  := .generateSrtpAuthTag([:], , )
	if  != nil {
		return nil, 
	}

	// Append the MKI (if used)
	if len(.mki) > 0 {
		copy([:], .mki)
		 += len(.mki)
	}

	// Write the auth tag to the dest.
	copy([:], )

	return , nil
}

func ( *srtpCipherAesCmHmacSha1) (
	,  []byte,
	 *rtp.Header,
	 int,
	 uint32,
	 bool,
) ([]byte, error) {
	// Split the auth tag and the cipher text into two parts.
	,  := .AuthTagRTPLen()
	if  != nil {
		return nil, 
	}

	// Split the auth tag and the cipher text into two parts.
	 := [len()-:]
	 = [:len()-len(.mki)-]

	// Generate the auth tag we expect to see from the ciphertext.
	,  := .generateSrtpAuthTag(, , )
	if  != nil {
		return nil, 
	}

	// See if the auth tag actually matches.
	// We use a constant time comparison to prevent timing attacks.
	if subtle.ConstantTimeCompare(, ) != 1 {
		return nil, ErrFailedToVerifyAuthTag
	}

	 := isSameBuffer(, )

	// Write the plaintext header to the destination buffer.
	if ! {
		copy(, [:])
	}

	// Decrypt the ciphertext for the payload.
	if .srtpEncrypted {
		 := generateCounter(.SequenceNumber, , .SSRC, .srtpSessionSalt)
		 = xorBytesCTR(
			.srtpBlock, [:], [:], [:],
		)
		if  != nil {
			return nil, 
		}
	} else if ! {
		copy([:], [:])
	}

	return , nil
}

func ( *srtpCipherAesCmHmacSha1) (,  []byte,  uint32,  uint32) ([]byte, error) {
	,  := .AuthTagRTCPLen()
	if  != nil {
		return nil, 
	}
	 := len(.mki)
	 := len()
	 :=  +  +  + srtcpIndexSize

	 = growBufferSize(, )
	 := isSameBuffer(, )

	if ! {
		copy(, [:srtcpHeaderSize]) // Copy the first 8 bytes (RTCP header)
	}

	// Encrypt everything after header
	if .srtcpEncrypted {
		 := generateCounter(uint16(&0xffff), >>16, , .srtcpSessionSalt) //nolint:gosec // G115
		if  = xorBytesCTR(.srtcpBlock, [:], [srtcpHeaderSize:], [srtcpHeaderSize:]);  != nil {
			return nil, 
		}

		// Add SRTCP Index and set Encryption bit
		binary.BigEndian.PutUint32([:], )
		[] |= srtcpEncryptionFlag
	} else {
		// Copy the decrypted payload as is
		if ! {
			copy([srtcpHeaderSize:], [srtcpHeaderSize:])
		}

		// Add SRTCP Index with Encryption bit cleared
		binary.BigEndian.PutUint32([:], )
	}

	 :=  + srtcpIndexSize

	// Generate the authentication tag
	,  := .generateSrtcpAuthTag([:])
	if  != nil {
		return nil, 
	}

	// Include the MKI if provided
	if len(.mki) > 0 {
		copy([:], .mki)
		 += 
	}

	// Append the auth tag at the end of the buffer
	copy([:], )

	return , nil
}

func ( *srtpCipherAesCmHmacSha1) (,  []byte, ,  uint32) ([]byte, error) {
	,  := .AuthTagRTCPLen()
	if  != nil {
		return nil, 
	}
	 := len(.mki)
	 := len()
	 :=  - ( +  + srtcpIndexSize)
	if  < 8 {
		return nil, errTooShortRTCP
	}

	,  := .generateSrtcpAuthTag([:--])
	if  != nil {
		return nil, 
	}

	 := [-:]
	if subtle.ConstantTimeCompare(, ) != 1 {
		return nil, ErrFailedToVerifyAuthTag
	}

	 = growBufferSize(, )
	 := isSameBuffer(, )

	if ! {
		copy(, [:srtcpHeaderSize]) // Copy the first 8 bytes (RTCP header)
	}

	 := []&srtcpEncryptionFlag != 0
	if  {
		 := generateCounter(uint16(&0xffff), >>16, , .srtcpSessionSalt) //nolint:gosec // G115
		 = xorBytesCTR(.srtcpBlock, [:], [srtcpHeaderSize:], [srtcpHeaderSize:])
	} else if ! {
		copy([srtcpHeaderSize:], [srtcpHeaderSize:])
	}

	return , 
}

func ( *srtpCipherAesCmHmacSha1) ( []byte,  uint32,  bool) ([]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
	.srtpSessionAuth.Reset()

	if ,  := .srtpSessionAuth.Write();  != nil {
		return nil, 
	}

	// For SRTP only, we need to hash the rollover counter as well.
	 := [4]byte{}
	binary.BigEndian.PutUint32([:], )

	,  := .srtpSessionAuth.Write([:])
	if  != nil {
		return nil, 
	}

	// Truncate the hash to the size indicated by the profile
	,  := .AuthTagRTPLen()
	if  != nil {
		return nil, 
	}

	var  []byte
	if  {
		 = append(, [:]...)
	}

	return .srtpSessionAuth.Sum()[0:], nil
}

func ( *srtpCipherAesCmHmacSha1) ( []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
	.srtcpSessionAuth.Reset()

	if ,  := .srtcpSessionAuth.Write();  != nil {
		return nil, 
	}
	,  := .AuthTagRTCPLen()
	if  != nil {
		return nil, 
	}

	return .srtcpSessionAuth.Sum(nil)[0:], nil
}

func ( *srtpCipherAesCmHmacSha1) ( []byte) uint32 {
	,  := .AuthTagRTCPLen()
	 := len() - ( + srtcpIndexSize + len(.mki))
	 := [ : +srtcpIndexSize]

	return binary.BigEndian.Uint32() &^ (1 << 31)
}