aes_ccm.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. package ciphersuite
  4. import (
  5. "crypto/sha256"
  6. "fmt"
  7. "hash"
  8. "sync/atomic"
  9. "github.com/pion/dtls/v2/pkg/crypto/ciphersuite"
  10. "github.com/pion/dtls/v2/pkg/crypto/clientcertificate"
  11. "github.com/pion/dtls/v2/pkg/crypto/prf"
  12. "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
  13. )
  14. // AesCcm is a base class used by multiple AES-CCM Ciphers
  15. type AesCcm struct {
  16. ccm atomic.Value // *cryptoCCM
  17. clientCertificateType clientcertificate.Type
  18. id ID
  19. psk bool
  20. keyExchangeAlgorithm KeyExchangeAlgorithm
  21. cryptoCCMTagLen ciphersuite.CCMTagLen
  22. ecc bool
  23. }
  24. // CertificateType returns what type of certificate this CipherSuite exchanges
  25. func (c *AesCcm) CertificateType() clientcertificate.Type {
  26. return c.clientCertificateType
  27. }
  28. // ID returns the ID of the CipherSuite
  29. func (c *AesCcm) ID() ID {
  30. return c.id
  31. }
  32. func (c *AesCcm) String() string {
  33. return c.id.String()
  34. }
  35. // ECC uses Elliptic Curve Cryptography
  36. func (c *AesCcm) ECC() bool {
  37. return c.ecc
  38. }
  39. // KeyExchangeAlgorithm controls what key exchange algorithm is using during the handshake
  40. func (c *AesCcm) KeyExchangeAlgorithm() KeyExchangeAlgorithm {
  41. return c.keyExchangeAlgorithm
  42. }
  43. // HashFunc returns the hashing func for this CipherSuite
  44. func (c *AesCcm) HashFunc() func() hash.Hash {
  45. return sha256.New
  46. }
  47. // AuthenticationType controls what authentication method is using during the handshake
  48. func (c *AesCcm) AuthenticationType() AuthenticationType {
  49. if c.psk {
  50. return AuthenticationTypePreSharedKey
  51. }
  52. return AuthenticationTypeCertificate
  53. }
  54. // IsInitialized returns if the CipherSuite has keying material and can
  55. // encrypt/decrypt packets
  56. func (c *AesCcm) IsInitialized() bool {
  57. return c.ccm.Load() != nil
  58. }
  59. // Init initializes the internal Cipher with keying material
  60. func (c *AesCcm) Init(masterSecret, clientRandom, serverRandom []byte, isClient bool, prfKeyLen int) error {
  61. const (
  62. prfMacLen = 0
  63. prfIvLen = 4
  64. )
  65. keys, err := prf.GenerateEncryptionKeys(masterSecret, clientRandom, serverRandom, prfMacLen, prfKeyLen, prfIvLen, c.HashFunc())
  66. if err != nil {
  67. return err
  68. }
  69. var ccm *ciphersuite.CCM
  70. if isClient {
  71. ccm, err = ciphersuite.NewCCM(c.cryptoCCMTagLen, keys.ClientWriteKey, keys.ClientWriteIV, keys.ServerWriteKey, keys.ServerWriteIV)
  72. } else {
  73. ccm, err = ciphersuite.NewCCM(c.cryptoCCMTagLen, keys.ServerWriteKey, keys.ServerWriteIV, keys.ClientWriteKey, keys.ClientWriteIV)
  74. }
  75. c.ccm.Store(ccm)
  76. return err
  77. }
  78. // Encrypt encrypts a single TLS RecordLayer
  79. func (c *AesCcm) Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error) {
  80. cipherSuite, ok := c.ccm.Load().(*ciphersuite.CCM)
  81. if !ok {
  82. return nil, fmt.Errorf("%w, unable to encrypt", errCipherSuiteNotInit)
  83. }
  84. return cipherSuite.Encrypt(pkt, raw)
  85. }
  86. // Decrypt decrypts a single TLS RecordLayer
  87. func (c *AesCcm) Decrypt(raw []byte) ([]byte, error) {
  88. cipherSuite, ok := c.ccm.Load().(*ciphersuite.CCM)
  89. if !ok {
  90. return nil, fmt.Errorf("%w, unable to decrypt", errCipherSuiteNotInit)
  91. }
  92. return cipherSuite.Decrypt(raw)
  93. }