ciphersuite.go 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  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. // [Psiphon]
  30. // Backport of https://github.com/pion/dtls/commit/61762dee8217991882c5eb79856b9e7a73ee349f. In
  31. // newer pion/dtls, AEAD nonce generation has moved to common code in aead.encrypt. In this older
  32. // fork, apply the fix to both CCM.Encrypt and GCM.Encrypt via this helper function.
  33. //
  34. // As in the upstream fix, nonce generation is changed from random bytes, which is more vulnerable
  35. // to reuse, to instead follow the scheme recommended in
  36. // https://www.rfc-editor.org/rfc/rfc9325#name-nonce-reuse-in-tls-12.
  37. func generateAEADNonce(writeIV []byte, h *recordlayer.Header) []byte {
  38. if gcmNonceLength != 12 || ccmNonceLength != 12 {
  39. panic("unexpected nonce length")
  40. }
  41. nonce := make([]byte, 12)
  42. copy(nonce, writeIV[:4])
  43. seq64 := (uint64(h.Epoch) << 48) | (h.SequenceNumber & 0x0000ffffffffffff)
  44. binary.BigEndian.PutUint64(nonce[4:], seq64)
  45. return nonce
  46. }
  47. // examinePadding returns, in constant time, the length of the padding to remove
  48. // from the end of payload. It also returns a byte which is equal to 255 if the
  49. // padding was valid and 0 otherwise. See RFC 2246, Section 6.2.3.2.
  50. //
  51. // https://github.com/golang/go/blob/039c2081d1178f90a8fa2f4e6958693129f8de33/src/crypto/tls/conn.go#L245
  52. func examinePadding(payload []byte) (toRemove int, good byte) {
  53. if len(payload) < 1 {
  54. return 0, 0
  55. }
  56. paddingLen := payload[len(payload)-1]
  57. t := uint(len(payload)-1) - uint(paddingLen)
  58. // if len(payload) >= (paddingLen - 1) then the MSB of t is zero
  59. good = byte(int32(^t) >> 31)
  60. // The maximum possible padding length plus the actual length field
  61. toCheck := 256
  62. // The length of the padded data is public, so we can use an if here
  63. if toCheck > len(payload) {
  64. toCheck = len(payload)
  65. }
  66. for i := 0; i < toCheck; i++ {
  67. t := uint(paddingLen) - uint(i)
  68. // if i <= paddingLen then the MSB of t is zero
  69. mask := byte(int32(^t) >> 31)
  70. b := payload[len(payload)-1-i]
  71. good &^= mask&paddingLen ^ mask&b
  72. }
  73. // We AND together the bits of good and replicate the result across
  74. // all the bits.
  75. good &= good << 4
  76. good &= good << 2
  77. good &= good << 1
  78. good = uint8(int8(good) >> 7)
  79. toRemove = int(paddingLen) + 1
  80. return toRemove, good
  81. }