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

package ciphersuite

import (
	
	
	
	

	
	
	
	
)

// AesCcm is a base class used by multiple AES-CCM Ciphers.
type AesCcm struct {
	ccm                   atomic.Value // *cryptoCCM
	clientCertificateType clientcertificate.Type
	id                    ID
	psk                   bool
	keyExchangeAlgorithm  KeyExchangeAlgorithm
	cryptoCCMTagLen       ciphersuite.CCMTagLen
	ecc                   bool
}

// CertificateType returns what type of certificate this CipherSuite exchanges.
func ( *AesCcm) () clientcertificate.Type {
	return .clientCertificateType
}

// ID returns the ID of the CipherSuite.
func ( *AesCcm) () ID {
	return .id
}

func ( *AesCcm) () string {
	return .id.String()
}

// ECC uses Elliptic Curve Cryptography.
func ( *AesCcm) () bool {
	return .ecc
}

// KeyExchangeAlgorithm controls what key exchange algorithm is using during the handshake.
func ( *AesCcm) () KeyExchangeAlgorithm {
	return .keyExchangeAlgorithm
}

// HashFunc returns the hashing func for this CipherSuite.
func ( *AesCcm) () func() hash.Hash {
	return sha256.New
}

// AuthenticationType controls what authentication method is using during the handshake.
func ( *AesCcm) () AuthenticationType {
	if .psk {
		return AuthenticationTypePreSharedKey
	}

	return AuthenticationTypeCertificate
}

// IsInitialized returns if the CipherSuite has keying material and can
// encrypt/decrypt packets.
func ( *AesCcm) () bool {
	return .ccm.Load() != nil
}

// Init initializes the internal Cipher with keying material.
func ( *AesCcm) (, ,  []byte,  bool,  int) error {
	const (
		 = 0
		  = 4
	)

	,  := prf.GenerateEncryptionKeys(
		, , , , , , .HashFunc(),
	)
	if  != nil {
		return 
	}

	var  *ciphersuite.CCM
	if  {
		,  = ciphersuite.NewCCM(
			.cryptoCCMTagLen, .ClientWriteKey, .ClientWriteIV, .ServerWriteKey, .ServerWriteIV,
		)
	} else {
		,  = ciphersuite.NewCCM(
			.cryptoCCMTagLen, .ServerWriteKey, .ServerWriteIV, .ClientWriteKey, .ClientWriteIV,
		)
	}
	.ccm.Store()

	return 
}

// Encrypt encrypts a single TLS RecordLayer.
func ( *AesCcm) ( *recordlayer.RecordLayer,  []byte) ([]byte, error) {
	,  := .ccm.Load().(*ciphersuite.CCM)
	if ! {
		return nil, fmt.Errorf("%w, unable to encrypt", errCipherSuiteNotInit)
	}

	return .Encrypt(, )
}

// Decrypt decrypts a single TLS RecordLayer.
func ( *AesCcm) ( recordlayer.Header,  []byte) ([]byte, error) {
	,  := .ccm.Load().(*ciphersuite.CCM)
	if ! {
		return nil, fmt.Errorf("%w, unable to decrypt", errCipherSuiteNotInit)
	}

	return .Decrypt(, )
}