encryption.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // Package rfc3961 provides encryption and checksum methods as specified in RFC 3961
  2. package rfc3961
  3. import (
  4. "crypto/cipher"
  5. "crypto/des"
  6. "crypto/hmac"
  7. "crypto/rand"
  8. "errors"
  9. "fmt"
  10. "github.com/jcmturner/gokrb5/v8/crypto/common"
  11. "github.com/jcmturner/gokrb5/v8/crypto/etype"
  12. )
  13. // DES3EncryptData encrypts the data provided using DES3 and methods specific to the etype provided.
  14. func DES3EncryptData(key, data []byte, e etype.EType) ([]byte, []byte, error) {
  15. if len(key) != e.GetKeyByteSize() {
  16. return nil, nil, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
  17. }
  18. data, _ = common.ZeroPad(data, e.GetMessageBlockByteSize())
  19. block, err := des.NewTripleDESCipher(key)
  20. if err != nil {
  21. return nil, nil, fmt.Errorf("error creating cipher: %v", err)
  22. }
  23. //RFC 3961: initial cipher state All bits zero
  24. ivz := make([]byte, des.BlockSize)
  25. ct := make([]byte, len(data))
  26. mode := cipher.NewCBCEncrypter(block, ivz)
  27. mode.CryptBlocks(ct, data)
  28. return ct[len(ct)-e.GetMessageBlockByteSize():], ct, nil
  29. }
  30. // DES3EncryptMessage encrypts the message provided using DES3 and methods specific to the etype provided.
  31. // The encrypted data is concatenated with its integrity hash to create an encrypted message.
  32. func DES3EncryptMessage(key, message []byte, usage uint32, e etype.EType) ([]byte, []byte, error) {
  33. //confounder
  34. c := make([]byte, e.GetConfounderByteSize())
  35. _, err := rand.Read(c)
  36. if err != nil {
  37. return []byte{}, []byte{}, fmt.Errorf("could not generate random confounder: %v", err)
  38. }
  39. plainBytes := append(c, message...)
  40. plainBytes, _ = common.ZeroPad(plainBytes, e.GetMessageBlockByteSize())
  41. // Derive key for encryption from usage
  42. var k []byte
  43. if usage != 0 {
  44. k, err = e.DeriveKey(key, common.GetUsageKe(usage))
  45. if err != nil {
  46. return []byte{}, []byte{}, fmt.Errorf("error deriving key for encryption: %v", err)
  47. }
  48. }
  49. iv, b, err := e.EncryptData(k, plainBytes)
  50. if err != nil {
  51. return iv, b, fmt.Errorf("error encrypting data: %v", err)
  52. }
  53. // Generate and append integrity hash
  54. ih, err := common.GetIntegrityHash(plainBytes, key, usage, e)
  55. if err != nil {
  56. return iv, b, fmt.Errorf("error encrypting data: %v", err)
  57. }
  58. b = append(b, ih...)
  59. return iv, b, nil
  60. }
  61. // DES3DecryptData decrypts the data provided using DES3 and methods specific to the etype provided.
  62. func DES3DecryptData(key, data []byte, e etype.EType) ([]byte, error) {
  63. if len(key) != e.GetKeyByteSize() {
  64. return []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
  65. }
  66. if len(data) < des.BlockSize || len(data)%des.BlockSize != 0 {
  67. return []byte{}, errors.New("ciphertext is not a multiple of the block size")
  68. }
  69. block, err := des.NewTripleDESCipher(key)
  70. if err != nil {
  71. return []byte{}, fmt.Errorf("error creating cipher: %v", err)
  72. }
  73. pt := make([]byte, len(data))
  74. ivz := make([]byte, des.BlockSize)
  75. mode := cipher.NewCBCDecrypter(block, ivz)
  76. mode.CryptBlocks(pt, data)
  77. return pt, nil
  78. }
  79. // DES3DecryptMessage decrypts the message provided using DES3 and methods specific to the etype provided.
  80. // The integrity of the message is also verified.
  81. func DES3DecryptMessage(key, ciphertext []byte, usage uint32, e etype.EType) ([]byte, error) {
  82. //Derive the key
  83. k, err := e.DeriveKey(key, common.GetUsageKe(usage))
  84. if err != nil {
  85. return nil, fmt.Errorf("error deriving key: %v", err)
  86. }
  87. // Strip off the checksum from the end
  88. b, err := e.DecryptData(k, ciphertext[:len(ciphertext)-e.GetHMACBitLength()/8])
  89. if err != nil {
  90. return nil, fmt.Errorf("error decrypting: %v", err)
  91. }
  92. //Verify checksum
  93. if !e.VerifyIntegrity(key, ciphertext, b, usage) {
  94. return nil, errors.New("error decrypting: integrity verification failed")
  95. }
  96. //Remove the confounder bytes
  97. return b[e.GetConfounderByteSize():], nil
  98. }
  99. // VerifyIntegrity verifies the integrity of cipertext bytes ct.
  100. func VerifyIntegrity(key, ct, pt []byte, usage uint32, etype etype.EType) bool {
  101. h := make([]byte, etype.GetHMACBitLength()/8)
  102. copy(h, ct[len(ct)-etype.GetHMACBitLength()/8:])
  103. expectedMAC, _ := common.GetIntegrityHash(pt, key, usage, etype)
  104. return hmac.Equal(h, expectedMAC)
  105. }