ciphersuite.go 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. // Package ciphersuite provides the crypto operations needed for a DTLS CipherSuite
  4. package ciphersuite
  5. import (
  6. "encoding/binary"
  7. "errors"
  8. "github.com/pion/dtls/v2/pkg/protocol"
  9. "github.com/pion/dtls/v2/pkg/protocol/recordlayer"
  10. )
  11. var (
  12. errNotEnoughRoomForNonce = &protocol.InternalError{Err: errors.New("buffer not long enough to contain nonce")} //nolint:goerr113
  13. errDecryptPacket = &protocol.TemporaryError{Err: errors.New("failed to decrypt packet")} //nolint:goerr113
  14. errInvalidMAC = &protocol.TemporaryError{Err: errors.New("invalid mac")} //nolint:goerr113
  15. errFailedToCast = &protocol.FatalError{Err: errors.New("failed to cast")} //nolint:goerr113
  16. )
  17. func generateAEADAdditionalData(h *recordlayer.Header, payloadLen int) []byte {
  18. var additionalData [13]byte
  19. // SequenceNumber MUST be set first
  20. // we only want uint48, clobbering an extra 2 (using uint64, Golang doesn't have uint48)
  21. binary.BigEndian.PutUint64(additionalData[:], h.SequenceNumber)
  22. binary.BigEndian.PutUint16(additionalData[:], h.Epoch)
  23. additionalData[8] = byte(h.ContentType)
  24. additionalData[9] = h.Version.Major
  25. additionalData[10] = h.Version.Minor
  26. binary.BigEndian.PutUint16(additionalData[len(additionalData)-2:], uint16(payloadLen))
  27. return additionalData[:]
  28. }
  29. // examinePadding returns, in constant time, the length of the padding to remove
  30. // from the end of payload. It also returns a byte which is equal to 255 if the
  31. // padding was valid and 0 otherwise. See RFC 2246, Section 6.2.3.2.
  32. //
  33. // https://github.com/golang/go/blob/039c2081d1178f90a8fa2f4e6958693129f8de33/src/crypto/tls/conn.go#L245
  34. func examinePadding(payload []byte) (toRemove int, good byte) {
  35. if len(payload) < 1 {
  36. return 0, 0
  37. }
  38. paddingLen := payload[len(payload)-1]
  39. t := uint(len(payload)-1) - uint(paddingLen)
  40. // if len(payload) >= (paddingLen - 1) then the MSB of t is zero
  41. good = byte(int32(^t) >> 31)
  42. // The maximum possible padding length plus the actual length field
  43. toCheck := 256
  44. // The length of the padded data is public, so we can use an if here
  45. if toCheck > len(payload) {
  46. toCheck = len(payload)
  47. }
  48. for i := 0; i < toCheck; i++ {
  49. t := uint(paddingLen) - uint(i)
  50. // if i <= paddingLen then the MSB of t is zero
  51. mask := byte(int32(^t) >> 31)
  52. b := payload[len(payload)-1-i]
  53. good &^= mask&paddingLen ^ mask&b
  54. }
  55. // We AND together the bits of good and replicate the result across
  56. // all the bits.
  57. good &= good << 4
  58. good &= good << 2
  59. good &= good << 1
  60. good = uint8(int8(good) >> 7)
  61. toRemove = int(paddingLen) + 1
  62. return toRemove, good
  63. }