encryption.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. // Package rfc8009 provides encryption and checksum methods as specified in RFC 8009
  2. package rfc8009
  3. import (
  4. "crypto/aes"
  5. "crypto/hmac"
  6. "crypto/rand"
  7. "errors"
  8. "fmt"
  9. "github.com/jcmturner/aescts/v2"
  10. "github.com/jcmturner/gokrb5/v8/crypto/common"
  11. "github.com/jcmturner/gokrb5/v8/crypto/etype"
  12. "github.com/jcmturner/gokrb5/v8/iana/etypeID"
  13. )
  14. // EncryptData encrypts the data provided using methods specific to the etype provided as defined in RFC 8009.
  15. func EncryptData(key, data []byte, e etype.EType) ([]byte, []byte, error) {
  16. kl := e.GetKeyByteSize()
  17. if e.GetETypeID() == etypeID.AES256_CTS_HMAC_SHA384_192 {
  18. kl = 32
  19. }
  20. if len(key) != kl {
  21. return []byte{}, []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
  22. }
  23. ivz := make([]byte, aes.BlockSize)
  24. return aescts.Encrypt(key, ivz, data)
  25. }
  26. // EncryptMessage encrypts the message provided using the methods specific to the etype provided as defined in RFC 8009.
  27. // The encrypted data is concatenated with its integrity hash to create an encrypted message.
  28. func EncryptMessage(key, message []byte, usage uint32, e etype.EType) ([]byte, []byte, error) {
  29. kl := e.GetKeyByteSize()
  30. if e.GetETypeID() == etypeID.AES256_CTS_HMAC_SHA384_192 {
  31. kl = 32
  32. }
  33. if len(key) != kl {
  34. return []byte{}, []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", kl, len(key))
  35. }
  36. if len(key) != e.GetKeyByteSize() {
  37. }
  38. //confounder
  39. c := make([]byte, e.GetConfounderByteSize())
  40. _, err := rand.Read(c)
  41. if err != nil {
  42. return []byte{}, []byte{}, fmt.Errorf("could not generate random confounder: %v", err)
  43. }
  44. plainBytes := append(c, message...)
  45. // Derive key for encryption from usage
  46. var k []byte
  47. if usage != 0 {
  48. k, err = e.DeriveKey(key, common.GetUsageKe(usage))
  49. if err != nil {
  50. return []byte{}, []byte{}, fmt.Errorf("error deriving key for encryption: %v", err)
  51. }
  52. }
  53. // Encrypt the data
  54. iv, b, err := e.EncryptData(k, plainBytes)
  55. if err != nil {
  56. return iv, b, fmt.Errorf("error encrypting data: %v", err)
  57. }
  58. ivz := make([]byte, e.GetConfounderByteSize())
  59. ih, err := GetIntegityHash(ivz, b, key, usage, e)
  60. if err != nil {
  61. return iv, b, fmt.Errorf("error encrypting data: %v", err)
  62. }
  63. b = append(b, ih...)
  64. return iv, b, nil
  65. }
  66. // DecryptData decrypts the data provided using the methods specific to the etype provided as defined in RFC 8009.
  67. func DecryptData(key, data []byte, e etype.EType) ([]byte, error) {
  68. kl := e.GetKeyByteSize()
  69. if e.GetETypeID() == etypeID.AES256_CTS_HMAC_SHA384_192 {
  70. kl = 32
  71. }
  72. if len(key) != kl {
  73. return []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", kl, len(key))
  74. }
  75. ivz := make([]byte, aes.BlockSize)
  76. return aescts.Decrypt(key, ivz, data)
  77. }
  78. // DecryptMessage decrypts the message provided using the methods specific to the etype provided as defined in RFC 8009.
  79. // The integrity of the message is also verified.
  80. func DecryptMessage(key, ciphertext []byte, usage uint32, e etype.EType) ([]byte, error) {
  81. //Derive the key
  82. k, err := e.DeriveKey(key, common.GetUsageKe(usage))
  83. if err != nil {
  84. return nil, fmt.Errorf("error deriving key: %v", err)
  85. }
  86. // Strip off the checksum from the end
  87. b, err := e.DecryptData(k, ciphertext[:len(ciphertext)-e.GetHMACBitLength()/8])
  88. if err != nil {
  89. return nil, err
  90. }
  91. //Verify checksum
  92. if !e.VerifyIntegrity(key, ciphertext, b, usage) {
  93. return nil, errors.New("integrity verification failed")
  94. }
  95. //Remove the confounder bytes
  96. return b[e.GetConfounderByteSize():], nil
  97. }
  98. // GetIntegityHash returns a keyed integrity hash of the bytes provided as defined in RFC 8009
  99. func GetIntegityHash(iv, c, key []byte, usage uint32, e etype.EType) ([]byte, error) {
  100. // Generate and append integrity hash
  101. // Rather than calculating the hash over the confounder and plaintext
  102. // it is calculated over the iv concatenated with the AES cipher output.
  103. ib := append(iv, c...)
  104. return common.GetIntegrityHash(ib, key, usage, e)
  105. }
  106. // VerifyIntegrity verifies the integrity of cipertext bytes ct.
  107. func VerifyIntegrity(key, ct []byte, usage uint32, etype etype.EType) bool {
  108. h := make([]byte, etype.GetHMACBitLength()/8)
  109. copy(h, ct[len(ct)-etype.GetHMACBitLength()/8:])
  110. ivz := make([]byte, etype.GetConfounderByteSize())
  111. ib := append(ivz, ct[:len(ct)-(etype.GetHMACBitLength()/8)]...)
  112. expectedMAC, _ := common.GetIntegrityHash(ib, key, usage, etype)
  113. return hmac.Equal(h, expectedMAC)
  114. }