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