encryption.go 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. // Package rfc4757 provides encryption and checksum methods as specified in RFC 4757
  2. package rfc4757
  3. import (
  4. "crypto/hmac"
  5. "crypto/rand"
  6. "crypto/rc4"
  7. "errors"
  8. "fmt"
  9. "github.com/jcmturner/gokrb5/v8/crypto/etype"
  10. )
  11. // EncryptData encrypts the data provided using methods specific to the etype provided as defined in RFC 4757.
  12. func EncryptData(key, data []byte, e etype.EType) ([]byte, error) {
  13. if len(key) != e.GetKeyByteSize() {
  14. return []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
  15. }
  16. rc4Cipher, err := rc4.NewCipher(key)
  17. if err != nil {
  18. return []byte{}, fmt.Errorf("error creating RC4 cipher: %v", err)
  19. }
  20. ed := make([]byte, len(data))
  21. copy(ed, data)
  22. rc4Cipher.XORKeyStream(ed, ed)
  23. rc4Cipher.Reset()
  24. return ed, nil
  25. }
  26. // DecryptData decrypts the data provided using the methods specific to the etype provided as defined in RFC 4757.
  27. func DecryptData(key, data []byte, e etype.EType) ([]byte, error) {
  28. return EncryptData(key, data, e)
  29. }
  30. // EncryptMessage encrypts the message provided using the methods specific to the etype provided as defined in RFC 4757.
  31. // The encrypted data is concatenated with its RC4 header containing integrity checksum and confounder to create an encrypted message.
  32. func EncryptMessage(key, data []byte, usage uint32, export bool, e etype.EType) ([]byte, error) {
  33. confounder := make([]byte, e.GetConfounderByteSize()) // size = 8
  34. _, err := rand.Read(confounder)
  35. if err != nil {
  36. return []byte{}, fmt.Errorf("error generating confounder: %v", err)
  37. }
  38. k1 := key
  39. k2 := HMAC(k1, UsageToMSMsgType(usage))
  40. toenc := append(confounder, data...)
  41. chksum := HMAC(k2, toenc)
  42. k3 := HMAC(k2, chksum)
  43. ed, err := EncryptData(k3, toenc, e)
  44. if err != nil {
  45. return []byte{}, fmt.Errorf("error encrypting data: %v", err)
  46. }
  47. msg := append(chksum, ed...)
  48. return msg, nil
  49. }
  50. // DecryptMessage decrypts the message provided using the methods specific to the etype provided as defined in RFC 4757.
  51. // The integrity of the message is also verified.
  52. func DecryptMessage(key, data []byte, usage uint32, export bool, e etype.EType) ([]byte, error) {
  53. checksum := data[:e.GetHMACBitLength()/8]
  54. ct := data[e.GetHMACBitLength()/8:]
  55. _, k2, k3 := deriveKeys(key, checksum, usage, export)
  56. pt, err := DecryptData(k3, ct, e)
  57. if err != nil {
  58. return []byte{}, fmt.Errorf("error decrypting data: %v", err)
  59. }
  60. if !VerifyIntegrity(k2, pt, data, e) {
  61. return []byte{}, errors.New("integrity checksum incorrect")
  62. }
  63. return pt[e.GetConfounderByteSize():], nil
  64. }
  65. // VerifyIntegrity checks the integrity checksum of the data matches that calculated from the decrypted data.
  66. func VerifyIntegrity(key, pt, data []byte, e etype.EType) bool {
  67. chksum := HMAC(key, pt)
  68. return hmac.Equal(chksum, data[:e.GetHMACBitLength()/8])
  69. }